Synthesis : Scott Becker

Learning D3 Part 3: Animation & Interaction

Update: I’m releasing a series of screencast tutorials on D3 at deveo.tv. Check it out and let me know what you think!

In Learning D3 Part 2, I went over how to bind datasets to the DOM, and get elements on and off the page with enter and exit sub-selections. This time I’ll go over how to add some basic animation and interaction.

Transitions

You specify animations (or other transitions) with the .transition() method, followed by a chain describing the end result. This can include any DOM transformation, such as updates to the width or background color. D3 conveniently calculates the “tween” values for distances and colors, which saves a huge amount of time. You just worry about the values to transition from and to, the duration of the animation, and any delay that should happen before the animation starts.

If you’re drawing a horizontal bar chart of running distances, it might help to convey distance a bit more by animating the growth of each bar horizontally.

var distances = [2.23, 2.39, 2.59, 2.77, 3.05];
 
d3.select('body').selectAll('div')
  .data(distances)
  .enter()
  .append('div')
  .html('.')
  .style('width', '10px')
  .style('opacity', 0)
  .transition()
    .delay(function(d, i) { return i * 1000 })
    .duration(1000)
    .style('width', function(d) { return (d * 150) + 'px'; })
    .style('opacity', 1)
    .text(function(d) { return d + ' miles'; });

I’m throwing in a few things at once. See it run here. What’s happening? A div is appended for each distance, and initially set to a small width of 10px, the text of “.” and an opacity of 0. It’s invisible! But only for a moment. Then we set up the transition. Each item is delayed 1 second later than the previous using a function returning a multiple of the item index. The duration is set to 1 second with .duration(1000). With this combo, each bar appears in succession. The rest is familiar, setting the full width, label text, and full opacity.

Interaction

Now let’s add some basic user interaction to it, by highlighting the current run when you mouse over it.

var distances = [2.23, 2.39, 2.59, 2.77, 3.05];
 
d3.select('body').selectAll('div')
  .data(distances)
  .enter()
    .append('div')
    .html('...')
    .style('width', '10px')
    .style('opacity', 0)
    .on("mouseover", function(){
      d3.select(this).transition().duration(300)
        .style("background-color", "#FFD700");
    })
    .on("mouseout", function(){
      d3.select(this).transition().duration(300)
        .style("background-color", "#333");
    })
    .transition()
      .delay(function(d, i) { return i * 300 })
      .duration(300)    
      .style('width', function(d) { return (d * 150) + 'px'; })
      .style('opacity', 1)
      .text(function(d) { return d + ' miles'; });

Here’s the running example. Notice the .on(“mouseover”) and .on(“mouseout”) events, describing another transition/animation to fade the background color to yellow and back. The events pass the current context as “this”, which you can again select with d3.select() and apply transitions to.

That’s the basic idea. These basic building blocks are all you really need to build up complex visualizations. I haven’t touched on SVG yet, so that’ll be up next.

Continue with the D3 Series:

 

3 responses to “Learning D3 Part 3: Animation & Interaction”

  1. Kent says:

    Really enjoying your examples, so thanks so much for documenting your exploration. I hope to incorporate some of this in some blog posts soon. For now, I have a super simple silly example at http://axysreporting.com/fred-example.html. With the help of your examples, I hope to make it much more attractive and robust d3.js visualization.

  2. Robin says:

    If you check the Fiddle and keep the mouse over the locations of one of the bars before it arrives the expansion transition will be replaced by the mouseover transition. Is there a good way to prevent this from happening?