|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
text { |
|
font: 10px sans-serif; |
|
} |
|
|
|
.axis path, |
|
.axis line { |
|
fill: none; |
|
stroke: #000; |
|
shape-rendering: crispEdges; |
|
} |
|
|
|
.line { |
|
fill: none; |
|
stroke-width: 1.5px; |
|
} |
|
|
|
.label { |
|
text-anchor: middle; |
|
} |
|
|
|
.label rect { |
|
fill: white; |
|
} |
|
|
|
.label-key { |
|
font-weight: bold; |
|
} |
|
|
|
</style> |
|
<svg width="960" height="500"></svg> |
|
<script src="//d3js.org/d3.v4.0.0-alpha.9.min.js"></script> |
|
<script> |
|
|
|
var parseTime = d3.timeParse("%Y"); |
|
|
|
var svg = d3.select("svg"); |
|
|
|
var margin = {top: 30, right: 50, bottom: 30, left: 30}, |
|
width = +svg.attr("width") - margin.left - margin.right, |
|
height = +svg.attr("height") - margin.top - margin.bottom, |
|
labelPadding = 3; |
|
|
|
var g = svg.append("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
d3.requestTsv("data.tsv", function(d) { |
|
d.date = parseTime(d.date); |
|
for (var k in d) if (k !== "date") d[k] = +d[k]; |
|
return d; |
|
}, function(error, data) { |
|
if (error) throw error; |
|
|
|
var series = data.columns.slice(1).map(function(key) { |
|
return data.map(function(d) { |
|
return { |
|
key: key, |
|
date: d.date, |
|
value: d[key] |
|
}; |
|
}); |
|
}); |
|
|
|
var x = d3.scaleTime() |
|
.domain([data[0].date, data[data.length - 1].date]) |
|
.range([0, width]); |
|
|
|
var y = d3.scaleLinear() |
|
.domain([0, d3.max(series, function(s) { return d3.max(s, function(d) { return d.value; }); })]) |
|
.range([height, 0]); |
|
|
|
var z = d3.scaleCategory10(); |
|
|
|
g.append("g") |
|
.attr("class", "axis axis--x") |
|
.attr("transform", "translate(0," + height + ")") |
|
.call(d3.axisBottom(x)); |
|
|
|
var serie = g.selectAll(".serie") |
|
.data(series) |
|
.enter().append("g") |
|
.attr("class", "serie"); |
|
|
|
serie.append("path") |
|
.attr("class", "line") |
|
.style("stroke", function(d) { return z(d[0].key); }) |
|
.attr("d", d3.line() |
|
.x(function(d) { return x(d.date); }) |
|
.y(function(d) { return y(d.value); })); |
|
|
|
var label = serie.selectAll(".label") |
|
.data(function(d) { return d; }) |
|
.enter().append("g") |
|
.attr("class", "label") |
|
.attr("transform", function(d, i) { return "translate(" + x(d.date) + "," + y(d.value) + ")"; }); |
|
|
|
label.append("text") |
|
.attr("dy", ".35em") |
|
.text(function(d) { return d.value; }) |
|
.filter(function(d, i) { return i === data.length - 1; }) |
|
.append("tspan") |
|
.attr("class", "label-key") |
|
.text(function(d) { return " " + d.key; }); |
|
|
|
label.append("rect", "text") |
|
.datum(function() { return this.nextSibling.getBBox(); }) |
|
.attr("x", function(d) { return d.x - labelPadding; }) |
|
.attr("y", function(d) { return d.y - labelPadding; }) |
|
.attr("width", function(d) { return d.width + 2 * labelPadding; }) |
|
.attr("height", function(d) { return d.height + 2 * labelPadding; }); |
|
}); |
|
|
|
</script> |
It seems there is a change between the 4.0-alpha and 4.2 that prevents this from working?
Cloning the gist and updating the reference to
<script src="http://d3js.org/d3.v4.min.js"></script>
results in empty white boxes (no labels).This, I'm figuring, has to do with:
And the fact that in the 4.0-alpha version it results in:
And in 4.2 it results in:
I also had to change
this.previousSibling
tothis.nextSibling
.For some reason in 4.2, the order of elements is reversed, and the text is hidden under the rectangle.
It seems like an easy fix, but I don't have a clue.
Ideas?