A graph of the rate of download of some of the books in the top downloads category of Leanpub.
The data is extrapolated to allow the mouse move tooltip to determine when certain events (like one book overhauling another) will occur.
You will probably want to open it in full screen :-).
xxxxxxxxxx
<meta charset="utf-8">
<style>
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script>
var margin = {top: 30, right: 50, bottom: 30, left: 60},
width = 1900 - margin.left - margin.right,
height = 870 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse,
formatDate = d3.time.format("%d-%b"),
bisectDate = d3.bisector(function(d) { return d.date; }).left;
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(8);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
var valueline = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.bt); });
var valueline2 = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.tnbb); });
var valueline3 = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.hon); });
var valueline4 = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.d3tat); });
var valueline5 = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.htdwyl); });
var valueline6 = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.watir); });
var valueline7 = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.lh); });
var valueline8 = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.taopwi); });
var valueline9 = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.qgffoad); });
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + ","
+ margin.top + ")");
var focus = svg.append("g")
.style("display", "none");
// Get the data
d3.csv("books2dayEX.csv", function(error, data){
data.forEach(function(d) {
d.date = parseDate(d.date);
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
// console.log(data);
y.domain([
d3.min(data, function(d) { return Math.min(d.bt,d.tnbb,d.hon,d.d3tat,d.htdwyl,d.watir,d.lh,d.taopwi,d.qgffoad); }),
d3.max(data, function(d) { return Math.max(d.bt,d.tnbb,d.hon,d.d3tat,d.htdwyl,d.watir,d.lh,d.taopwi,d.qgffoad); })
]);
svg.append("path") // Add the valueline path.
.attr("class", "line")
.style("stroke", "red")
.attr("d", valueline(data));
svg.append("path") // Add the valueline2 path.
.attr("class", "line")
.style("stroke", "steelblue")
.attr("d", valueline2(data));
svg.append("path") // Add the valueline3 path.
.attr("class", "line")
.style("stroke", "green")
.attr("d", valueline3(data));
// D3 Tips and tricks line
svg.append("path") // Add the valueline4 path.
.attr("class", "line")
.style("stroke", "black")
.attr("d", valueline4(data));
svg.append("path") // Add the valueline5 path.
.attr("class", "line")
.style("stroke", "purple")
.attr("d", valueline5(data));
svg.append("path") // Add the valueline6 path.
.attr("class", "line")
.style("stroke", "orange")
.attr("d", valueline6(data));
svg.append("path") // Add the valueline7 path.
.attr("class", "line")
.style("stroke", "grey")
.attr("d", valueline7(data));
svg.append("path") // Add the valueline8 path.
.attr("class", "line")
.style("stroke", "blue")
.attr("d", valueline8(data));
svg.append("path") // Add the valueline9 path.
.attr("class", "line")
.style("stroke", "red")
.attr("d", valueline9(data));
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
// append the x line
focus.append("line")
.attr("class", "x")
.style("stroke", "blue")
.style("stroke-dasharray", "3,3")
.style("opacity", 0.5)
.attr("y1", 0)
.attr("y2", height);
// append the y line
focus.append("line")
.attr("class", "y")
.style("stroke", "blue")
.style("stroke-dasharray", "3,3")
.style("opacity", 0.5)
.attr("x1", width)
.attr("x2", width);
// place the value at the intersection
focus.append("text")
.attr("class", "y1")
.style("stroke", "white")
.style("stroke-width", "3.5px")
.style("opacity", 0.8)
.attr("dx", 8)
.attr("dy", "-.3em");
focus.append("text")
.attr("class", "y2")
.attr("dx", 8)
.attr("dy", "-.3em");
// place the date at the intersection
focus.append("text")
.attr("class", "y3")
.style("stroke", "white")
.style("stroke-width", "3.5px")
.style("opacity", 0.8)
.attr("dx", 8)
.attr("dy", "1em");
focus.append("text")
.attr("class", "y4")
.attr("dx", 8)
.attr("dy", "1em");
// append the rectangle to capture mouse
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
y0 = d3.mouse(this)[1]
y1 = parseInt(y.invert(y0)),
date1 = d3.mouse(this)[0];
// console.log(x0);
focus.select(".x")
.attr("transform",
"translate(" + date1 + "," + (0) + ")")
.attr("y2", height );
focus.select(".y")
.attr("transform",
"translate(" + width * -1 + "," +
y0 + ")")
.attr("x2", width + width);
focus.select("text.y1")
.attr("transform",
"translate(" + (date1 + 5) + "," + (y0) + ")")
.text(formatDate(x0));
focus.select("text.y2")
.attr("transform",
"translate(" + (date1 + 5) + "," + (y0) + ")")
.text(formatDate(x0));
focus.select("text.y3")
.attr("transform",
"translate(" + (date1 + 7) + "," + (y0 + 4) + ")")
.text(y1);
focus.select("text.y4")
.attr("transform",
"translate(" + (date1 + 7) + "," + (y0 + 4) + ")")
.text(y1);
}
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[data.length-1].bt) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "red")
.text("bt");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[data.length-1].tnbb) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "steelblue")
.text("tnbb");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[data.length-1].hon) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "green")
.text("hon");
// D3 Tips and tricks line
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[data.length-1].d3tat) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "black")
.text("d3tat");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[data.length-1].htdwyl) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "purple")
.text("htdwyl");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[data.length-1].watir) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "orange")
.text("watir");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[data.length-1].lh) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "grey")
.text("lh");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[data.length-1].taopwi) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "blue")
.text("taopwi");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[data.length-1].qgffoad) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "red")
.text("qgffoad");
});
</script>
</body>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js