0

I've looked for over 3 hours now trying to find a way to chain transitions indefinitely...

My only solution is wrapping the code in a function, then repeatedly calling the function with setInterval or waiting for the transition 'end' event

Example one liner:

d3.selectAll('circle').data([1,2,3]).enter().append('circle').attr('cy':function(d){return d * 100},'cx':function(){Math.random() * window.innerWidth},'r':'10px')

//sets initial locations for circles that are created to match data array

.transition().attr('cy':function(){Math.random() * window.innerHeight},'cx':function(){Math.random() * window.innerWidth}})
.transition().attr('cy':function(){Math.random() * window.innerHeight},'cx':function(){Math.random() * window.innerWidth}})
.transition().attr('cy':function(){Math.random() * window.innerHeight},'cx':function(){Math.random() * window.innerWidth}})
.transition().attr('cy':function(){Math.random() * window.innerHeight},'cx':function(){Math.random() * window.innerWidth}})
.transition().attr('cy':function(){Math.random() * window.innerHeight},'cx':function(){Math.random() * window.innerWidth}})

//I'm looking for something that can repeat the transition without using setInterval)
neaumusic
  • 10,027
  • 9
  • 55
  • 83
  • What's wrong with waiting for the transition end event, and then invoking another transition? – Jon S. Jan 19 '14 at 00:13
  • I want to invoke the same transition without leaving the chain of commands. I want to be able to invoke the last N steps, every few seconds (whether that's a transition or just a repeat binding of some data object to the DOM element when the data changes) – neaumusic Jan 22 '14 at 19:45

1 Answers1

0

One way or another, I think you're going to have to wrap your transition settings in a function, so that you can call it recursively. However, @Jon S. is right, you can use the transition's "end" event instead of a separate timer.

The complication is that the callback function in transition.each("end", callback) is (as the method name suggests) called for each element in the array. A simple check can make sure the recursion only happens once, for the first element, and doesn't branch indefinitely.

Here's an example: http://fiddle.jshell.net/UD9ng/1/

Key code:

var moving = false;

function move(selection) {

    moving = true;
    selection.transition().duration(5000).ease("sin-in-out")
        .attr("cx", function(){return Math.random()*width;})
        .attr("cy", function(){return Math.random()*height;})
        //.call(move); //stack overflow error!
        .each("end", function(d,i){ 
            if (!i) circles.call(move); //only run for i==0
        });

}

As you can see from the comments, I tried using the transition's .call() method (which invokes a function once for the entire transition object), but there is no way currently to delay that call until the end of the transition, so repeated sub-transition calls were being added to a queue until the console spit out an error with a huge stack trace behind it. The weird thing was, it didn't look like anything was wrong, since all the queued-up transitions were still moving smoothly -- but they would have run out of transitions eventually.

The each/end approach -- with the recursive function called on the original selection -- replaces the finished transition instead of chaining to it, so it can continue indefinitely without consuming increasing resources.

AmeliaBR
  • 27,344
  • 6
  • 86
  • 119
  • Yea, I know that I can do this but I want to avoid the function declaration, not just the "setInterval(move,1000)" – neaumusic Jan 22 '14 at 19:46
  • Well, in that case, the answer to your question is no, it's not possible with transitions. Transitions are designed to go from one state to another, not for indefinite animations. – AmeliaBR Jan 22 '14 at 21:48
  • P.S. Maybe if you updated the question with more specific examples of why you don't think a function call will work, then we could help you make it happen. – AmeliaBR Jan 22 '14 at 21:50