|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<body> |
|
<style> |
|
.axis path, |
|
.axis line { |
|
fill: none; |
|
stroke: #ccc; |
|
shape-rendering: crispEdges; |
|
} |
|
path.domain { |
|
stroke: none; |
|
} |
|
.axis text { |
|
font-family: "Monaco", monospace; |
|
font-size: 12px; |
|
} |
|
.line { |
|
stroke-width: 5px; |
|
} |
|
.min, |
|
.max { |
|
font-size: 9px; |
|
font-family: "Monaco", monospace; |
|
text-shadow: 1px 1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, -1px -1px 0 #fff; |
|
} |
|
.tooltip, |
|
.annotation { |
|
position: absolute; |
|
font-size: 11px; |
|
font-family: "Monaco", monospace; |
|
pointer-events: none; |
|
text-shadow: 1px 1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, -1px -1px 0 #fff; |
|
} |
|
</style> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
|
|
<script> |
|
var margin = { top: 10, right: 70, bottom: 10, left: 30 }, |
|
width = 960 - margin.left - margin.right, |
|
height = 500 - margin.top - margin.bottom; |
|
|
|
var format = d3.format(".2"); |
|
|
|
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 y = d3.scaleLinear().range([height, 0]); |
|
|
|
var x = d3.scaleLinear().range([0, width]); |
|
|
|
var xAxis = d3.axisBottom(x); |
|
|
|
var yAxis = d3 |
|
.axisLeft(y) |
|
.tickValues([5, 15, 25, 35]) |
|
.tickSize(-width) |
|
.tickFormat(function(d) { |
|
return d + "%"; |
|
}); |
|
|
|
var color = d3 |
|
.scaleLinear() |
|
.range(["blue", "red"]) |
|
.domain([0, 36]); |
|
|
|
var div = d3 |
|
.select("body") |
|
.append("div") |
|
.attr("class", "tooltip"); |
|
|
|
var annotation = d3 |
|
.select("body") |
|
.append("div") |
|
.attr("class", "annotation"); |
|
|
|
var firstYear = d3 |
|
.select("body") |
|
.append("div") |
|
.attr("class", "annotation"); |
|
|
|
var lastYear = d3 |
|
.select("body") |
|
.append("div") |
|
.attr("class", "annotation"); |
|
|
|
d3.csv("data.csv", type, function(error, data) { |
|
// sort the data from min to max |
|
data.sort(function(a, b) { |
|
return a.rate_2015 - b.rate_2015; |
|
}); |
|
|
|
y.domain([0, 40]); |
|
x.domain([ |
|
0, |
|
d3.max(data, function(d, i) { |
|
return i; |
|
}) |
|
]); |
|
|
|
// call the axis |
|
var axis = svg |
|
.append("g") |
|
.attr("class", "axis") |
|
.call(yAxis); |
|
|
|
// paint the lines |
|
var lines = svg.append("g").attr("class", "lines"); |
|
|
|
var lineGroup = lines |
|
.selectAll("line") |
|
.data(data) |
|
.enter() |
|
.append("g") |
|
.attr("class", "line-g") |
|
.on("mousemove", function(d, i) { |
|
div |
|
.html(d.province) |
|
.style("left", x(i) + 35 + "px") |
|
.style("top", y(d.rate_2015) - 20 + "px"); |
|
}) |
|
.on("mouseleave", function() { |
|
d3 |
|
.select(this) |
|
.selectAll("text") |
|
.style("font-weight", "400"); |
|
}); |
|
|
|
lineGroup |
|
.append("line") |
|
.attr("class", "line") |
|
.attr("x1", function(d, i) { |
|
return x(i) + 15; |
|
}) |
|
.attr("y1", function(d) { |
|
return y(d.rate_2015); |
|
}) |
|
.attr("x2", function(d, i) { |
|
return x(i) + 15; |
|
}) |
|
.attr("y2", function(d, i) { |
|
return y(d.rate_2005); |
|
}) |
|
.style("stroke", function(d, i) { |
|
return color(d.rate_2015); |
|
}); |
|
|
|
// annotate the last item in the array |
|
var last = data[data.length - 1]; |
|
annotation |
|
.html(last.province) |
|
.style("left", function(d, i) { |
|
return x(data.length + 1.1) + "px"; |
|
}) |
|
.style("top", y(last.rate_2015) - 20 + "px"); |
|
|
|
firstYear |
|
.html("— 2005") |
|
.style("left", function(d, i) { |
|
return x(data.length + 2) + "px"; |
|
}) |
|
.style("top", y(last.rate_2005) + 10 + "px"); |
|
|
|
lastYear |
|
.html("— 2015") |
|
.style("left", function(d, i) { |
|
return x(data.length + 2) + "px"; |
|
}) |
|
.style("top", y(last.rate_2015) + 10 + "px"); |
|
|
|
// 2005 unemployment |
|
lineGroup |
|
.append("text") |
|
.attr("class", "min") |
|
.attr("x", function(d, i) { |
|
return x(i) + 12; |
|
}) |
|
.attr("y", function(d, i) { |
|
return y(d.rate_2005) + 10; |
|
}) |
|
.text(function(d) { |
|
return round(d.rate_2005, 0); |
|
}); |
|
|
|
// 2015 unemployment |
|
lineGroup |
|
.append("text") |
|
.attr("class", "max") |
|
.attr("x", function(d, i) { |
|
return x(i) + 9; |
|
}) |
|
.attr("y", function(d, i) { |
|
return y(d.rate_2015) - 5; |
|
}) |
|
.text(function(d) { |
|
return round(d.rate_2015, 0); |
|
}); |
|
}); |
|
|
|
function type(d) { |
|
d.id = +d.id; |
|
d.rate_2015 = +d.rate_2015; |
|
d.rate_2005 = +d.rate_2005; |
|
return d; |
|
} |
|
|
|
// From https://github.com/d3/d3-format/issues/32 |
|
function round(x, n) { |
|
return n == null ? Math.round(x) : Math.round(x * (n = Math.pow(10, n))) / n; |
|
} |
|
</script> |