2

As explained here, you can schedule successive transition-driven attribute value changes on a single element [..] "using transition.transition, which creates a new transition whose delay immediately follows the existing transition" (a statement which seems to imply that staggered transitions don't work on single elements).

As explained in this post, however, "chained transitions (transition.transition) are implemented by inheriting the delay based on the previous transition‘s delay + duration, so, if you subsequently override the delay by setting it yourself, you’re still setting the delay relative to the current time, not the end of the previous transition".

As usual, I seem to have a special case: a single element (for argument's sake a circle whose colour is to be changed) addressed by a series of transitions of varying delay and duration. This means I have no choice but to set the delay and duration myself.

In sum, as far as I see, I can neither stagger nor chain the transitions: in both cases, each transition's delays and durations will be overridden by those of the successor..

As to examples, the closest I've found is this, which, though in itself useful, doesn't go so far as to cover my particular case. I'm at a loss how to proceed. Any suggestions?

Community
  • 1
  • 1
user1019696
  • 453
  • 1
  • 5
  • 15

1 Answers1

3

You have basically two options here. First, you can use the normal chained transition pattern, computing the delays of subsequent transitions based on the duration of the previous transitions:

 d3.select("svg").append("circle")
   .attr("transform", "translate(20,20)")
   .attr("r", 20)
   .attr("fill", "black")
   .transition().duration(1000)
   .attr("fill", "orange")
   .transition().delay(1500).duration(500)
   .attr("fill", "blue");

The delay of the second transition, 1500, is the duration of the first transition, 1000, plus the delay before the second transition starts, 500. If you have access to those numbers (e.g. from the data bound to your elements), you should be able to compute the delays for subsequent transitions quite easily.

The alternative is to use transition.each() to attach a handler for the "end" event and use that to set up the second transition:

d3.select("svg").append("circle")
  .attr("transform", "translate(100,20)")
  .attr("r", 20)
  .attr("fill", "black")
  .transition().duration(1000)
  .attr("fill", "orange")
  .each("end", function() {
    d3.select(this)
    .transition().delay(500).duration(500)
    .attr("fill", "blue");
  });

Here the delay of the second transition is relative to the first one, i.e. only starts when the first transition is finished. This approach does however require you to have these nested calls, which may or may not be feasible depending on what you're looking for.

If you can start transitions without delay, all works as expected:

d3.select("svg").append("circle")
  .attr("transform", "translate(180,20)")
  .attr("r", 20)
  .attr("fill", "black")
  .transition().duration(1000)
  .attr("fill", "orange")
  .transition().duration(1000)
  .attr("fill", "blue");

Here the second transition starts when the first one is finished.

Complete demo here.

Lars Kotthoff
  • 107,425
  • 16
  • 204
  • 204