Jump to content
Search Community

Reversing timeline animation and repeating it infinitely

mkoskela test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

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!

Link to comment
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
Link to comment
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
Link to comment
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?

Link to comment
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
Link to comment
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});

Link to comment
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
Link to comment
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
Link to comment
Share on other sites

  • 2 years later...

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})
;


}());
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...