Question

I'm new to D3 JS. I spent some time to learn D3 js and build a sort of time table (I'm not sure this is the term) and to animate it.

Now I found a strange behavior on exit transition, when I try to remove the last element in a row the animation goes perfectly but when the element is not the last one, D3 removes it without animation.

It's hard to understand my problem, it's really easier to watch it! :)

I created a working fiddle here: http://jsfiddle.net/fLBq4/5/

  • Click 'Draw' to build the graph (data are loaded from an external js that create the var demodata)
  • Then click the second button and watch the last element of Sunday. The transition works correctly.
  • Then click the last button. You'll see that the first element of Friday is removed without the transition!

Now... I'm really surprised because the code for removing elements it's the same for both executions:

frames.exit()
.transition()
.duration(500)
.attr('width',0)
.remove();

Moreover, I implemented the listeners for 'start' and 'end' transition events (you will not find them in the fiddle). These events are fired correctly, i.e. the 'end' event is timed correctly 500 msec after start.

Why won't D3 animate all the elements in the same way, in my case?

Was it helpful?

Solution

What's happening is that you're getting caught out by D3's data matching. The bar that disappears suddenly isn't in the exit selection, it's in the update selection. The second bar is in the exit selection and disappears gradually, but the first bar is moved to its position instantaneously, so you can't actually see that. I've added a transition to the update selection so you can see what's happening here.

The reason that this is happening is that D3 matches data and DOM elements by index by default. That is, the first data element corresponds to the first DOM element in the selection and so on. In your particular case, you're removing an element from the array, so the last DOM element ends up being not matched and becomes part of the exit selection. The other elements however change their position (as new data is matched to them).

To fix, simply provide a function that tells D3 how to match data and DOM elements, e.g.

var frames = groups.selectAll('.frame')
  .data(function(d){return d;}, function(d) { return d.start; });

Complete demo here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top