Friday 17 April 2015

D3 Tooltips for a line chart

I wrote a blog entry on my attempts to write a line chart for D3 here. One thing it didn't have was tooltips when you hovered over the chart to tell you what the data was at that point.

I've added these for an article I recently wrote for my website. Their behaviour is limited but it's a start.

Composition

The tips themselves are constructed of one SVG 'rect' element and two SVG 'text' elements. They are positioned via the mouseover event.

Code

The first thing to do is to create the SVG element to hang all the child elements off:
    var chk = d3.select("#cht1")
.append("svg")
.attr("class", "chk")
.attr("width", 960)
.attr("height", 600);

Then we need to create the tooltip elements:
     chk.append("rect")
.attr("width", 70)
.attr("height", 50)
.attr("x","-2000")
.attr("y","-2000")
.attr("rx","2")
.attr("ry","2")
.attr("class", "tooltip_box")
.attr("id", "tooltip1")
.attr("opacity", "0.0");
    chk.append("text")
.attr("class","bbd_tooltip_text")
.attr("id","bbd_tt_txt1")
.attr("x", "-2000")
        .attr("y", "-2000")
        .attr("dy", ".35em")
        .attr("dx", ".35em")
        .text(" ");
    chk.append("text")
.attr("class","bbd_tooltip_text")
.attr("id","bbd_tt_txt2")
.attr("x", "-2000")
        .attr("y", "-2000")
        .attr("dy", ".35em")
        .attr("dx", ".35em")
        .text(" ");

I've given the elements a starting position of (-2000,-2000). It's not strictly necessary as I could have just made their opacity attribute equal to zero. I've also given the elements ids and classes.

Now we need to make them move with the mouse. I've added <rect> elements over the data points and it is to these that we add the event function:
    .on("mouseover", function(d, i) {
//Select mouse position
var ym = d3.mouse(this)[1];
d3.select("#tooltip1")
.attr("x", x_scale(resp_data[i].x)+10)
.attr("y", ym)
.attr("opacity", "0.5");
d3.select("#bbd_tt_txt1")
.attr("x", x_scale(resp_data[i].x)+10)
.attr("y", ym+12)
.text("x="+resp_data[i].x);
d3.select("#bbd_tt_txt2")
.attr("x", x_scale(resp_data[i].x)+10)
.attr("y", ym+32)
.text("y="+resp_data[i].y);
   })

In the code above resp_data is an array holding all the data, x_scale is a D3 scale object and ym holds the y position of the mouse.

For the three elements of the tooltip I've changed the opacity, the position and the text.

We also need to clear up the tooltip when we exit the <rect> element:
    .on("mouseout", function() {
d3.select("#tooltip1")
.attr("x", "-2000")
.attr("y", "-2000")
.attr("opacity", "0.0");
d3.select("#bbd_tt_txt1")
.attr("x", "100")
.attr("y", "100")
.text(" ");
d3.select("#bbd_tt_txt2")
.attr("x", "-2000")
.attr("y", "-2000")
.text(" ");
    })

and finally we need to change the tooltip when the mouse moves:
    .on("mousemove", function(d, i) {
var ym = d3.mouse(this)[1];
d3.select("#tooltip1")
.attr("x", x_scale(resp_data[i].x)+10)
.attr("y", ym)
.attr("opacity", "0.5");
d3.select("#bbd_tt_txt1")
.attr("x", x_scale(resp_data[i].x)+10)
.attr("y", ym+12)
.text("x="+resp_data[i].x);
d3.select("#bbd_tt_txt2")
.attr("x", x_scale(resp_data[i].x)+10)
.attr("y", ym+32)
.text("y="+resp_data[i].y);
    })

And that's it, apart from CSS to style the elements. I'll leave that up to you though.

No comments:

Post a Comment