d3 / d3-transition

Animated transitions for D3 selections.
https://d3js.org/d3-transition
ISC License
224 stars 65 forks source link

Schedule a following transition. #15

Closed mbostock closed 8 years ago

mbostock commented 8 years ago

Related mbostock/d3#2423.

If there were an easy way to say “schedule a transition after the currently-active transition, if any”, it would be easier to create looped transitions. Currently, you have to remember this syntax:

selection.transition()
    .duration(2500)
    .delay(function(d) { return d * 40; })
    .each(slide);

function slide() {
  var circle = d3.select(this);
  (function repeat() {
    circle = circle.transition()
        .attr("cx", width)
      .transition()
        .attr("cx", 0)
        .each("end", repeat);
  })();
}

An alternative:

selection.transition()
    .duration(2500)
    .delay(function(d) { return d * 40; })
    .each("start", slide);

function slide() {
  d3.select(this).activeTransition()
      .attr("cx", width)
    .transition()
      .attr("cx", 0)
    .transition()
      .each("start", slide);
}

Or, at the expense of repeating the tweens in the first transition:

selection.transition()
    .duration(2500)
    .delay(function(d) { return d * 40; })
    .attr("cx", width)
    .each("end", repeat);

function repeat() {
  d3.select(this).transitionAfter()
      .attr("cx", 0)
    .transition()
      .attr("cx", width)
      .each("end", repeat);
}
mbostock commented 8 years ago

So it doesn’t make sense to have a selection.activeTransition return a transition because a transition has a single id and there could be multiple transitions active if there are multiple selected elements. But here’s a working implementation for a single node:

d3.activeTransition = function(node, name) {
  var ns = name == null ? "__transition__" : "__transition_" + name + "__",
      id = node[ns] && node[ns].active;
  if (!id) return null;
  var transition = [[node]];
  transition.__proto__ = d3.transition.prototype; // d3_subclass
  transition.namespace = ns;
  transition.id = id;
  return transition;
};

And here’s an example usage:

selection.transition()
    .duration(2500)
    .delay(function(d) { return d * 40; })
    .each("start", slide);

function slide() {
  d3.activeTransition(this)
      .attr("cx", width)
    .transition()
      .attr("cx", 0)
    .transition()
      .each("start", slide);
}