Friday, 2 May 2014

Including an HTML link in a d3.js tool tip

The following post is a portion of the D3 Tips and Tricks book which is free to download. To use this post in context, consider it with the others in the blog or just download the the book as a pdf / epub or mobi .
----------------------------------------------------------

Including an HTML link in a d3.js tool tip

There was an interesting question on d3noob.org about adding an HTML link to a tooltip. While the person asking the question had the problem pretty much solved already, I thought it might be useful for others (bear in mind that this post follows on from the original on adding tooltips in d3.js).
The premise is that you want to add a tool tip to your visualization using the method described here, but you also want to include an HTML link in the tooltip that will link somewhere else. This might look a little like the following;
Tool tip with an HTML Link
In the image above the date has been turned into a link. In this case the link goes to google.com, but that can obviously be configurable.
The full code for this example can be found on github or in the code samples bundled with D3 Tips and Tricks (tooltips-link.html and data.csv). A working example can be found on bl.ocks.org.
There are a few changes that we would want to make to our original tooltip code to implement this feature.
First of all, we’ll add the link to the date element. Adding an HTML link can be as simple as wrapping the ‘thing’ to be used as a link in <a> tags with an appropriate URL to go to.
The following adaptation of the code that prints the information into our tooltip code does just that;
    div .html(
        '<a href= "http://google.com">' + // The first <a> tag
        formatTime(d.date) +
        "</a>" +                          // closing </a> tag
        "<br/>"  + d.close)     
        .style("left", (d3.event.pageX) + "px")             
        .style("top", (d3.event.pageY - 28) + "px");
<a href= "http://google.com"> places our first <a> tag and declares the URL and the second tag follows after the date.
The second change we will want to make is to ensure that the tooltip stays in place long enough for us to actually click on the link. The problem being solved here is that our original code relies on the mouse being over the dot on the graph to display the tooltip. if the tooltip is displayed and the cursor moves to press the link, it will move off the dot on the graph and the tooltip vanishes (Nice!).
To solve the problem we can leave the tooltip in place adjacent to a dot while the mouse roams freely over the graph until the next time it reaches a dot and then the previous tooltip vanishes and a new one appears. The best way to appreciate this difference is to check out the live example on bl.ocks.org.
The code is as follows (you may notice that this also includes the link as described above);
    .on("mouseover", function(d) {        
        div.transition()
            .duration(500)    
            .style("opacity", 0);
        div.transition()
            .duration(200)    
            .style("opacity", .9);    
        div .html(
            '<a href= "http://google.com">' + // The first <a> tag
            formatTime(d.date) +
            "</a>" +                          // closing </a> tag
            "<br/>"  + d.close)     
            .style("left", (d3.event.pageX) + "px")             
            .style("top", (d3.event.pageY - 28) + "px");
        });
We have removed the .on("mouseout" portion and moved the function that it used to carry out to the start of the.on("mouseover" portion. That way the first thing that occurs when the mouse cursor moves over a dot is that it removes the previous tooltip and then it places the new one.
The last change we need to make is to remove from the <style> section the line that told the mouse to ignore the tooltip;
  /*  pointer-events: none;    This line needs to be removed */
In this case I have just commented it out so that it’s a bit more obvious that it gets removed.
One link is interesting, but let’s face it, we didn’t go to all the trouble of putting a link into a tool tip to just go to one location. Now we shift it up a gear and start linking to different places depending on our data. At the same time (and because someone asked) we will make the link open in a new tab!
The changes to the script are fairly minor, but one fairly large change is the need to have links to go to. For this example I have added a range of links to visit to our csv file so it now looks like this;
date,close,link
1-May-12,58.13,http://bl.ocks.org/d3noob/c37cb8e630aaef7df30d
30-Apr-12,53.98,http://bl.ocks.org/d3noob/11313583
27-Apr-12,67.00,http://bl.ocks.org/d3noob/11306153
26-Apr-12,89.70,http://bl.ocks.org/d3noob/11137963
25-Apr-12,99.00,http://bl.ocks.org/d3noob/10633856
24-Apr-12,130.28,http://bl.ocks.org/d3noob/10633704
23-Apr-12,166.70,http://bl.ocks.org/d3noob/10633421
20-Apr-12,234.98,http://bl.ocks.org/d3noob/10633192
19-Apr-12,345.44,http://bl.ocks.org/d3noob/10632804
18-Apr-12,443.34,http://bl.ocks.org/d3noob/9692795
17-Apr-12,543.70,http://bl.ocks.org/d3noob/9267535
16-Apr-12,580.13,http://bl.ocks.org/d3noob/9211665
13-Apr-12,605.23,http://bl.ocks.org/d3noob/9167301
12-Apr-12,622.77,http://bl.ocks.org/d3noob/8603837
11-Apr-12,626.20,http://bl.ocks.org/d3noob/8375092
10-Apr-12,628.44,http://bl.ocks.org/d3noob/8329447
9-Apr-12,636.23,http://bl.ocks.org/d3noob/8329404
5-Apr-12,633.68,http://bl.ocks.org/d3noob/8150631
4-Apr-12,624.31,http://bl.ocks.org/d3noob/8273682
3-Apr-12,629.32,http://bl.ocks.org/d3noob/7845954
2-Apr-12,618.63,http://bl.ocks.org/d3noob/6584483
30-Mar-12,599.55,http://bl.ocks.org/d3noob/5893649
29-Mar-12,609.86,http://bl.ocks.org/d3noob/6077996
28-Mar-12,617.62,http://bl.ocks.org/d3noob/5193723
27-Mar-12,614.48,http://bl.ocks.org/d3noob/5141528
26-Mar-12,606.98,http://bl.ocks.org/d3noob/5028304
The code change is to the piece of JavaScript where we add the html. This is what we end up with;
    div .html(
        '<a href= "'+d.link+'" target="_blank">' + //with a link
        formatTime(d.date) +
        "</a>" +
        "<br/>"  + d.close)     
        .style("left", (d3.event.pageX) + "px")             
        .style("top", (d3.event.pageY - 28) + "px");
We’ve replaced the URL http://google.com with the variable for our link column d.link and we’ve also added in the target="_blank" statement so that our link opens in a new tab.
A quick word of warning on this piece of code. it can look a little messy because it includes nested speech-marks and quotation marks. This makes it a bit confusing if you’re unused to the idea of nesting this type of information. If things aren’t working in this part of your code, I recommend going back to basics and adding one piece at a time, getting it right and then add the next piece. Take it slow :-).
The full code for this multi link example can be found on github or in the code samples bundled with D3 Tips and Tricks (tooltips-link-multi.html and datatips.csv). A working example can be found on bl.ocks.org.
Hopefully that helps people with a similar desire to include links in their tooltips. Many thanks to the reader who suggested it :-).

The description above (and heaps of other stuff) is in the D3 Tips and Tricks book that can be downloaded for free (or donate if you really want to :-)).

3 comments:

  1. Thanks for this tips, it's usefull

    ReplyDelete
  2. Hi, is this possible for 3d surface plot graphs? =)

    ReplyDelete
    Replies
    1. I seem to recall seeing something like a 3d surface plot, but I couldn't discover it again. Bearing in mind that it will be the users browser doing the processing, I presume that each individuals experience would vary markedly.

      Delete