A scruffy graph in response to the question “When will your book pass Backbone Tutorials for the #1 overall spot?“ on googlegroups.
The answer? [Spolier Alert]
Never.
It might pass it on or about the 3rd of August 2017, but by that stage The ABC of PDF with iText would have already shot passed both and will be number one in around 14 may 2016.
<!DOCTYPE html>
<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("books.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 + 7) + "," + (y0) + ")")
.text(formatDate(x0));
focus.select("text.y2")
.attr("transform",
"translate(" + (date1 + 7) + "," + (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>