block by d3noob acfbbc5a9e0e9eb643fb

Super Leanpub Extrapolation

Full Screen

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.

index.html

<!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>

books.csv