I have been working on an interactive line chart built using D3.js. One hover I would like a tool tip to be displayed with a vertical line. The vertical line comes out fine, however, I have problems related to the tool tip. The tool tip position is not on the graph and I am only getting the first data element.
Here is my code:
margin = {
top: 20,
right: 20,
bottom: 20,
left: 50
};
var width = Math.max(250, Math.min(700, d3.select("#content").width- margin.left - margin.right)),
height = 500;
var vis = d3.select("#line_chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
max_x = 0, max_y = 0, min = 100;
d3.csv("line.csv", function(error, data) {
for(i=0; i < data.length; i++){
max_y = Math.max(max_y, data[i].number);
max_x = Math.max(max_x, data[i].class);
min = Math.min(min, data[i].class);
}
xScale = d3.scale.linear().range([margin.left, width - margin.right]).domain([min, max_x]),
yScale = d3.scale.linear().range([height - margin.top, margin.bottom]).domain([0, max_y]),
xAxis = d3.svg.axis()
.scale(xScale),
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
vis.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(xAxis);
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (margin.left) + ",0)")
.call(yAxis);
var lineGen = d3.svg.line()
.x(function(d) {
return xScale(d.class);
})
.y(function(d) {
return yScale(d.number);
})
.interpolate("basis");
var pth = vis.append('svg:path')
.attr('d', lineGen(data))
.attr('stroke', '#000')
.attr('stroke-width', 3.5)
.attr('fill', 'none');
var totalLength = pth.node().getTotalLength();
pth
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2400)
.ease("linear")
.attr("stroke-dashoffset", 0);
//Line chart mouse over
var hoverLineGroup = vis.append("g")
.attr("class", "hover-line");
var hoverLine = hoverLineGroup
.append("line")
.attr("stroke", "#000")
.attr("x1", 10).attr("x2", 10)
.attr("y1", 0).attr("y2", height);
var hoverTT = hoverLineGroup.append('text')
.attr("class", "hover-tex capo")
.attr('dy', "0.35em");
var cle = hoverLineGroup.append("circle")
.attr("r", 4.5);
var hoverTT2 = hoverLineGroup.append('text')
.attr("class", "hover-text capo")
.attr('dy', "0.35em");
hoverLineGroup.style("opacity", 1e-6);
var rectHover = vis.append("rect")
.data(data)
.attr("class", "overlay")
.attr("width", width)
.attr("height", height);
rectHover
.on("mouseout", hoverMouseOff)
.on("mousemove", hoverMouseOn);
function hoverMouseOn(d) {
var mouse_x = d3.mouse(this)[0];
var mouse_y = d3.mouse(this)[1];
var graph_y = yScale.invert(mouse_y);
var graph_x = xScale.invert(mouse_x);
hoverTT.text("Marks: " + Math.round(graph_x * 100)/100);
hoverTT.attr('x', mouse_x + 10);
hoverTT.attr('y', yScale(d.class));
hoverTT2.text("Frequency: " + Math.round(d.number * 100)/100)
.attr('x', mouse_x + 10)
.attr('y', yScale(d.class) +15);
cle
.attr('x', mouse_x)
.attr('y', mouse_y);
hoverLine.attr("x1", mouse_x).attr("x2", mouse_x)
hoverLineGroup.style("opacity", 1);
}
function hoverMouseOff() {
hoverLineGroup.style("opacity", 1e-6);
};
});
}
The data:
class,number
25,1
30,7
35,11
45,13
50,21
55,23
60,30
65,41
75,39
80,24
85,14
90,4
95,8
100,2
I am not able to figure out what the issue is.
How can I solve this?
Thanks in advance.
EDIT: Here is the working code: https://jsfiddle.net/kan83q0m/1/
In your hoverMouseOn method, the variable d is undefined. You'll need to use d3.bisector to find the closest data point, like this:
var bisectDate = d3.bisector(function(d) { return d.class; }).left;
var mouseDate = xScale.invert(mouse_x);
var i = bisectDate(data, mouseDate);
var d0 = data[i - 1]
var d1 = data[i];
var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0;
Also, I put the mousemove listener on 'vis' instead of 'rectHover':
vis
.on("mouseout", hoverMouseOff)
.on("mousemove", hoverMouseOn);
and used d.number instead of d.class for the y values. If you want the tooltip to always be on the line it gets a bit more complicated. Here's a working fiddle.
Might be easier to just put the tooltip at your mouse coordinates like in this fiddle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With