Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
mkoskela

Reversing timeline animation and repeating it infinitely

Recommended Posts

Hi there,

 

I'm trying to create a simple infinitely looping animation with "planets" orbiting the "sun". The orbiting animation itself was a breeze with GSAP JS and bezier.

 

The problem I'm facing is the "infiniteness" of the orbiting animation when reversing the animation. I understand calling timeline.reverse() will run the virtual playhead from current point to the beginning and then stop. What I would like to accomplish is that after animation is reversed, the loop would continue again infinitely to the opposite direction.

 

You can see my current animation here:

See the Pen qBhlz by anon (@anon) on CodePen

 

If you click on the "sun" it reverses the main timeline animation and runs until it reaches the beginning. What should I do to keep the reversed animation going?

 

I'd appreciate any help on how to approach this.

 

Thanks for your great work, GSAP is amazing!

Share this post


Link to post
Share on other sites

Welcome to the forums. Your planets seem to be coming along quite nicely.

 

I don't have much time at the moment to adapt your codepen, but you should be able to get a 'reverse repeat' by using onReverseComplete (check it out in the Special Properties of TimelineMax), e.g.

var tl = new TimelineMax({
  repeat:-1,
  onReverseComplete:reverseRepeat,
  onReverseCompleteParams:['{self}']
});

var reverseRepeat = function(tl) {
  tl.reverse(0); // 0 sets the playhead at the end of the animation
}
If that can't get you started, hopefully someone else might have a chance to fix up your sample directly.
  • Like 3

Share this post


Link to post
Share on other sites

Jamie had a great suggestion with using reverse(0), but unfortunately it doesn't work so well with infinite animations as they don't have a finite end time.

 

We can still implement the reverse(0) technique with callbacks for both onComplete and onReverseComplete like this:

 

var tl = new TimelineMax({
  onReverseComplete:reverseRepeat,
  onReverseCompleteParams:['{self}'],
  onComplete:complete,
  onCompleteParams:['{self}']
});


tl.to("img", 3, {rotation:360, transformOrigin:"150px 150px", ease:Linear.easeNone});


function reverseRepeat(tl) {
  tl.reverse(0); // 0 sets the playhead at the end of the animation
}


function complete(tl) {
  tl.restart(); // 0 sets the playhead at the end of the animation
}




$("button").on("click", function() {
  tl.reversed(!tl.reversed());
})

http://codepen.io/GreenSock/pen/lznLE

 

use the toggle direction button to see how the animation plays infinitely in both directions.

  • Like 2

Share this post


Link to post
Share on other sites

Ok guys, I almost got my orbiting planets to work:

See the Pen igrld by anon (@anon) on CodePen

 

Everything seems ok if browser tab stays active. Reversing timeline rotations also works nicely if you click on the "sun".

 

But strangely enough, if you switch to other browser tab for a while (animation tab becomes inactive) the planets tend to come together and lose their position in the orbit. Is this a bug, expected behaviour or am I doing something wrong here?

Share this post


Link to post
Share on other sites

The problem here is that you're using callbacks and when the tab isn't active (and requestAnimationFrame is used), the core timing pulse only updates once every 2 seconds or so (maybe even longer). So imagine a scenario where you've got 6 timelines set up that will each expire 0.25 seconds apart from each other over the course of the next 1.5 seconds and you switch tabs. Nothing happens, but then you switch back to the tabs and GSAP updates, moving the virtual playhead forward and says "oh, let's fire all these callbacks that exist between the old and new virtual playhead position". So they all fire basically at the same time and your code tells them all to go to their end and play in reverse. 

 

See the issue? 

 

It's not a problem with GSAP or anything - it's just the nature of the beast. Don't worry, there's a better way you can build this that will keep things perfectly synchronized...

 

First, check this out: http://codepen.io/GreenSock/pen/a09308867365738559e06749a065f910

 

The basic concept is to drop your animations into a single master TimelineLite. You can build each planet's animation in its own TimelineMax that you'll nest into that master timeline. Each planet's TimelineMax should be set to repeat infinitely which ensures that all the timing is perfectly synced. The only challenge is when you reverse() that master timeline, it'll eventually get back to the beginning and you'll want to loop there. No problem - just drop a callback into that spot on the master timeline that tells it to jump forward to a synchronized spot in the future (in my example, I'll use 1000 orbits/rotations, but you could use almost any number). Then it'll jump there and continue playing in reverse, repeating that process when it reaches that callback again.

 

Since everything is on one master timeline, things will NEVER get out of sync. Even though technically we are using a callback to do that reverse loop, it's okay because the actual timing of all the planets' animations are housed in a single master timeline, so the playhead moves across it consistently.

 

I hope that clears things up. 

  • Like 5

Share this post


Link to post
Share on other sites

Thank you Jack, this is very clean and just what I was after! Originally I tried something a bit similar but failed miserably  :D

  • Like 1

Share this post


Link to post
Share on other sites

This is very similar to what I'm looking for - basically I want to build a roll over state that scales up a div. Then play a looping animation, then on roll out reverse the whole thing without playing all of the loops again.  I did something similar to the approach below. The problem is that when I play reverse, it's going through all of the loops again where I just want it to go back to the first state. Is this possible?

var timeline1 = new new TimelineMax();
var timeline2 = new new TimelineMax({repeat: -1});

 timeline2.add(TweenLite.to('#smallerDiv', .5, {left: 20});
 timeline2.add(TweenLite.to('#smallerDiv', .5, {left: 0});

timeline1.add(TweenLite.to('#div', .5, {scaleX:1.5,scaleY:1.5});
timeline1.add(timeline2);
timeline1.add(TweenLite.to('#div', .5, {scaleX:1.0,scaleY:1.0});

Share this post


Link to post
Share on other sites

Hi,

 

One chance would be to add a label in the master timeline's first tween, or just add a label after that tween.

 

Add label at first tween:

timeline1.add(TweenLite.to('#div', .5, {scaleX:1.5,scaleY:1.5}, 'label1');
timeline1.add(timeline2);
timeline1.add(TweenLite.to('#div', .5, {scaleX:1.0,scaleY:1.0});

Add label after first tween:

timeline1.add(TweenLite.to('#div', .5, {scaleX:1.5,scaleY:1.5});
timeline1.add('label1');
timeline1.add(timeline2);
timeline1.add(TweenLite.to('#div', .5, {scaleX:1.0,scaleY:1.0});

And in the roll out event you just indicate where the reverse should start, and that point will be the label, like this:

timeline1.reverse('label1');

Another choice could be to add a callback in timeline1 to start timeline2 and in the roll out event add the reverse call and a stop call for timeline2, like this:

timeline1.add(TweenLite.to('#div', .5, {scaleX:1.5,scaleY:1.5});
timeline1.call(timeline2Function);
timeline1.add(TweenLite.to('#div', .5, {scaleX:1.0,scaleY:1.0});

function timeline2Function()
{
    timeline2.play();
}

//ON ROLL OUT EVENT
timeline1.reverse('label1', true);
timeline2.stop(0);

The second parameter in the reverse call is to avoid the callback being triggered when you reverse the timeline.

 

Let us know how it works and if you need more help.

 

Hope this helps,

Cheers,

Rodrigo.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks Rodigo, this was really helpful! It's odd, I've been using TweenLite for years, but never thought about using anything for TimelineLite. With Flash I always just animated on the timeline. Now that I have switched to JS, it's really opening my eyes to what it can do. It's really great! 

  • Like 1

Share this post


Link to post
Share on other sites

Hi Guys, Just thought I'll ask on the back of this thread. I'm really new to all of this. I'm trying to repeat a timeline twice and stop play at a label. I've worked out the repeat part but how do I make it stop at the label 'stop-point' at the end of the last repetition? Thanks in advance!

 

(function(){
var tl1 = new TimelineMax({repeat: 2});
tl1.to('#myAd', .4, { opacity: 1})
.from('#myAd_text1', 0.5, { left: -600, opacity: 0, ease:Power2.easeOut})
.to('#myAd_text1', 0.3, { left: 700, ease:Power2.easeIn}, '=1.5')
.from('#myAd_text2', 0.5, { left: -1300, ease:Power2.easeOut})
.to('#myAd_text3', 0.5, { opacity: 0, ease:Power2.easeOut},'=-0.7', 'stop-point')
.to('#my-logo', 0.5, { opacity: 0, ease:Power2.easeOut},'=2')
.to('#myAd_cta-container', 0.5, { opacity: 0, ease:Power2.easeOut})
;


}());

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×