making the tooltip always visible. Evolution of the Spanish population. Data from wikipedia
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<title>Line Chart</title>
<style>
.axis--x .tick text,
.axis--y .tick text {
font-size: 1em;
fill: rgb(128,128,128);
text-shadow: 0px 0px 5px rgb(255,255,255), 0px 0px 5px rgb(255,255,255), 0px 0px 10px rgb(255,255,255);
}
.axis path,
.axis line {
fill: none;
stroke: rgb(128,128,128);
shape-rendering: crispEdges;
}
g.axis:nth-child(2) > g:nth-child(1) > line:nth-child(1) {
stroke: none;
}
.axis--y path, .axis--x path {
display: none;
}
.axis--y line {
stroke: rgba(128, 128, 128,0.3);
stroke-dasharray: 2, 2;
}
.lines {
fill: none;
stroke-linejoin: round;
stroke-linecap: round;
}
svg > g > g.focus > text {
font-size: 1em;
text-anchor: middle;
text-shadow: 1px 2px 3px rgb(255,255,255), 1px 2px 3px rgb(255,255,255), 1px -2px 3px rgb(255,255,255), -1px 2px 3px rgb(255,255,255);
}
.voronoi path {
fill: none;
pointer-events: all;
}
.focus text {
font-size: 1.4em;
fill: rgb(128, 128, 128);
text-shadow: 0px 0px 5px rgb(255,255,255), 0px 0px 5px rgb(255,255,255), 0px 0px 10px rgb(255,255,255);
}
.focus .userData {
font-size: 1.2em;
fill: rgb(70,70,70);
}
</style>
</head>
<body>
<script src="d3.js"></script>
<script type="text/javascript">
var yearFormat = d3.time.format("%Y");
format = function(d){return d.toPrecision(3);},
margin = {top: 20, right: 30, bottom: 40, left: 50},
width = 900 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var xAxis, yAxis, svg, x, y,
translate = width/3.3,
lineWidth = 2;
x = d3.time.scale()
.range([0, width]);
y = d3.scale.linear()
.range([height, 0]);
var voronoi = d3.geom.voronoi()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.value); })
.clipExtent([[-margin.left, -margin.top], [width + margin.right, height + margin.bottom]]);
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return x(d.date);})
.y(function(d) { return y(d.value);});
svg = d3.select("body").append("svg")
.attr("preserveAspectRatio", "xMidYMid")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("class", "line-chart-group")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var colors = [
"#009AA6",
"rgb(197,197,197)"
];
d3.csv("data.csv", type, function(error, data) {
x.domain(d3.extent(years));
y.domain([0, d3.max(data, function(c) {
return d3.max(c.values, function(d) {
return d.value;
});
})+3])
.nice();
xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickPadding(10)
.innerTickSize(8)
.ticks(8);
yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
.tickSize(-width-margin.right+margin.left)
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
svg.append("g").attr("class", "lines")
.selectAll("path")
.data(data)
.enter().append("path")
.attr("d", function(d) { d.line = this; return line(d.values); })
.attr("stroke", function(d, i) {
return colors[i%colors.length];
})
.attr("class", function(d){return "user "+d.name;})
.attr("id", function(d,i){return "stroke_"+i;})
.style("opacity", "0.8")
.attr("stroke-width", lineWidth);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(-100,-100)");
focus.append("circle")
.attr("fill", "white")
.attr("class", "notation")
.attr("stroke-width", "1.5")
.attr("r", 5);
focus.append("text")
.attr("y", -40)
.attr("class", "userData");
focus.append("text")
.attr("y", -20)
.attr("class", "userValue");
var voronoiGroup = svg.append("g")
.attr("class", "voronoi");
voronoiGroup.selectAll("path")
.data(voronoi(d3.nest()
.key(function(d) { return x(d.date) + "," + y(d.value); })
.rollup(function(v) { return v[0];})
.entries(d3.merge(data.map(function(d) { return d.values; })))
.map(function(d) { return d.values; })))
.enter().append("path")
.attr("d", function(d) {return "M" + d.join("L") + "Z"; })
.datum(function(d) { return d.point; })
.on({
"mouseover": mouseover,
"mouseout": mouseout
});
function mouseover(d) {
focus.selectAll(".userData, .userValue")
.text("");
var userData = yearFormat(d.date);
var userValue = d.user.name + ": "+format(d.value);
d3.select(d.user.line).classed("user--hover", true);
d.user.line.parentNode.appendChild(d.user.line);
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")");
d3.select(".focus circle").attr("stroke", d3.select(d.user.line).attr("stroke"));
focus.selectAll("text")
.attr("x", function() {
// Right side
if (x(d.date) > (width - 80)) {
return - (d3.mean([50, (x(d.date)-width)]));
}
// Left side
else if (x(d.date) < 10) {
return - (d3.mean([x(d.date),(userValue.length - 50)])*2);
}
// Center
else {
return 0;
}
});
focus.selectAll(".userData")
.text(userData);
focus.selectAll(".userValue")
.text(userValue);
d3.select(d.user.line).style({
"opacity": "1",
"stroke-width": (lineWidth * 1.2)
});
}
function mouseout(d) {
d3.select(d.user.line).classed("user--hover", false);
focus.attr("transform", "translate(-100,-100)");
d3.select(d.user.line).style({
"opacity": "0.8",
"stroke-width": lineWidth
});
}
});
function type(d, i) {
if (!i) years = Object.keys(d).map(yearFormat.parse).filter(Number);
var user = {
name: d.name,
values: null
};
user.values = years.map(function(m) {
return {
user: user,
date: m,
value: d[yearFormat(m)]/1000,
values:d[yearFormat(m)]
};
});
return user;
}
</script>
</body>
</html>