D3 Tips and Tricks v4

Friday, 9 May 2014

Show / hide a d3.js element by clicking on another element

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 .
----------------------------------------------------------
Show / hide an element by clicking on another element
This is a trick that I found I wanted to implement in order to present a graph with a range of lines and to then provide the reader with the facility to click on the associated legend to toggle the visibility of the lines off and on as required.
The example we’ll follow is our friend from earlier, a slightly modified example of the graph with two lines.
Show / hide lines on a graph
In this example we will be able to click on either of the two titles at the bottom of the graph (‘Blue Line’ or ‘Red Line’) and have it toggle the respective line and Y axis.
THE CODE
The code for the example is available online at bl.ocks.org or GitHub. It is also available as the file ‘show-hide.html’ as a separate download with D3 Tips and Tricks. A copy of most the files that appear in the book can be downloaded (in a zip file) when you download the book from Leanpub.
There are two main parts to implementing this technique. Firstly we have to label the element (or elements) that we wish to show / hide and then we have to give the object that will get clicked on the attribute that allows it to recognize a mouse click and the code that it subsequently uses to show / hide our labelled element.
Labeling the element that is to be switched on and off is dreadfully easy. It simply involves including an idattribute to an element that identifies it uniquely.
svg.append("path")
    .attr("class", "line")
    .attr("id", "blueLine")
    .attr("d", valueline(data));
In the example above we have applied the id blueLine to the path that draws the blue line on our graph.
The second part is a little trickier. The following is the portion of JavaScript that places our text label under the graph. The only part of it that is unusual is the .on("click", function() section of the code.
svg.append("text")
    .attr("x", 0)             
    .attr("y", height + margin.top + 10)    
    .attr("class", "legend")
    .style("fill", "steelblue")         
    .on("click", function(){
        // Determine if current line is visible
        var active   = blueLine.active ? false : true,
          newOpacity = active ? 0 : 1;
        // Hide or show the elements
        d3.select("#blueLine").style("opacity", newOpacity);
        d3.select("#blueAxis").style("opacity", newOpacity);
        // Update whether or not the elements are active
        blueLine.active = active;
When we click on our ‘Blue Line’ text element the .on("click", function() section executes.
We’re using a short-hand version of the if statement a couple of times here. Firstly we check to see if the variable blueLine.active is true or false and if it’s true it gets set to false and if it’s false it gets set to true (not at all confusing).
        var active   = blueLine.active ? false : true,
          newOpacity = active ? 0 : 1;
Then after toggling this variable we set the value of newOpacity to either 0 or 1 depending on whether active isfalse or true (the second short-hand JavaScript if statement).
We can then select our identifiers that we have declared using the id attributes in the earlier pieces of code and modify their opacity to either 0 (off) or 1 (on)
        d3.select("#blueLine").style("opacity", newOpacity);
        d3.select("#blueAxis").style("opacity", newOpacity);
Lastly we update our blueLine.active variable to whatever the active state is so that it can toggle correctly the next time it is clicked on.
        blueLine.active = active;
Quite a neat piece of code. Kudos to Max Leiserson for providing the example on which it is largely based in an answer to a question on Stack Overflow.

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 :-)).

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 :-)).