Jump to content
Search Community

Negative delay of Tweens when appended to Timeline

ZachSaucier 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

Greetings,

 

I have been at this for a couple of hours now to no avail. I am trying to append some tweens to a timeline and use negative delays to offset them (they are the same animation otherwise).

 

My problem is that the timeline is waiting each to finish before restarting, which is what I do not want

 

Here's a link to what I have so far 

See the Pen sGbku by Zeaklous (@Zeaklous) on CodePen

 and my code:

var timeline = new TimelineMax({repeat:-1}),
    electrons = document.querySelectorAll('.electron'),
    paths = document.querySelectorAll('.path'),
    atom = document.querySelectorAll('#atom'),
    startDuration = 2;

for(var i = 0; i < electrons.length; i++) {
  var myDelay = -(i * 0.5);  
  orbit(electrons[i], paths[i], myDelay);  
}

function orbit(electron, path, delay) {
  var e = TweenLite.to(electron, startDuration, {rotationY:'-360', ease:Linear.easeNone, 
    onComplete: function(){
      //e.restart();
    }, delay:delay
  });
  //timeline.append(e);
  var p = TweenLite.to(path, startDuration, {rotationZ:'360', ease:Linear.easeNone, 
    onComplete: function(){
      //p.restart();
    }, delay:delay
  });
  //timeline.append(p);
  // The following line doesn't seem to add a negative offset...
  timeline.insertMultiple([e, p], 0, TweenAlign.START, -0.5);
}

atom.onmouseover = function() {
  timeline.timeScale(.2);
}

function TweenAlign() {
}

If you look at the demo it runs correctly the first iteration (before it's added to the timeline) but fails the next times

 

Can you guys help me get this looking the way I'd like it to?

 

Thanks

  • Like 1
Link to comment
Share on other sites

Hi and welcome to the GreenSock forums.

 

Cool demo. Thanks a ton for providing it. Very helpful.

 

I'm a little confused by what you are trying to achieve using negative delays in your tweens and a negative stagger in your insertMultiple.

 

Keep in mind that timelines are completely linear, they won't repeat until they are finished and they will always play again from the beginning. The playhead can only be at one place at a time so its not possible to be playing the end of the last tween and beginning of the first tween at the same time. 

 

Also, you are putting negative delays on your tweens, but when you use TweenAlign.START, delays are ignored.

 

http://www.greensock.com/as/docs/tween/com/greensock/TimelineLite.html#insertMultiple()

TweenAlign.START (aligns the start times of all of the tweens (ignores delays))

 

The link above is to older AS3 docs as methods like insert(), insertMultiple(), append(), appendMultiple() have all been deprecated. 

 

There is now 1 method called add() which does everything those methods did. Visit the v12 JS TimelineLite docs and take a look at add(), to(), from(), staggerFrom(). 

 

Check out some out these resources to see the new methods in action:

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

http://www.greensock.com/sequence-video/

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

 

---

 

Please realize I'm not trying to beat up on your code. I totally understand that you are probably used to the older Flash stuff and that you were in the middle of trying a bunch of stuff to get it to work. Just want to help you get up to speed on some things that will make your life much easier.

 

Back to your issue. I took a stab at creating what I think you are going for.

I basically just put a bunch of infinitely-repeating TweenMax tweens into a TimelineLite  with offset start times. 

 

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

 

Basically each tween  repeats and the timeline never does. The downside here is that your timeline is infinite which makes dealing with progress() and duration() a little awkward.

  • Like 3
Link to comment
Share on other sites

UPDATE:

 

I came up with a different approach.

 

Repeat each tween once

When the first iteration of the last tween ends I add a callback which tells the timeline to play from where the last tween started:

 

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

 

This creates a seamless loop without needing a whole bunch of infinitely repeating tweens.

 

I created this video to better explain and help visualize how this works:

  • Like 3
Link to comment
Share on other sites

Creative approach(es), for sure. I just wanted to point out, however, a caveat and another solution...

 

Using an onComplete callback to sequence (or in this case, repeat) something can cause a bit of a time drift, as explained here: http://forums.greensock.com/topic/9029-delay-after-tween/#entry36197. In many cases, you'd never notice and it's perfectly acceptable to use this approach.

 

You shouldn't be afraid of "infinite" repeats, by the way - I got the impression that maybe you thought those hog up a ton of memory or something. Not at all. It's just a simple logic flag that tells the engine to run certain code. So in my opinion, if your goal is to infinitely repeat in a seamless way that doesn't have any time drift, repeat:-1 is the way to go. 

 

One other hybrid approach is to do what Carl suggested (only one repeat), pause() the timeline, and use an infinitely repeating TweenMax to tween the time() of the timeline! Yeah, mind-bending, right? It'd look kinda like this:

tl.seek(lastTweenStartTime).pause();
var duration = lastTweenEndTime - lastTweenStartTime;
TweenMax.to(tl, duration, {time:lastTweenEndTime, ease:Linear.easeNone, repeat:-1});
  • Like 1
Link to comment
Share on other sites

Awesome, thanks for the great responses! I didn't expect such extensive answers.

 

I come from the CSS animation side of things with no Flash experience actually, haha. I got into GSAP a little after you, Jack, commented on one of my CSS-Tricks articles. The (evidently now deprecated) methods I used were in some examples I looked at. The business I'm looking to work for this summer also would like someone skilled at GSAP, so I figured I'd pick it up some more.

 

As for the methods you proposed, they're great and likely better than what I had, but ultimately not quite attaining the full functionality that I'm looking for. Admittedly you solved my original question posted here about the timings, thanks again, but I had a version with just two repeating Tweens that functioned as yours do.

 

My need for a timeline as well is to serve my final objective: to slow down (but not stop) the animation on hover in a smooth way. That's what the 

atom.onmouseover = function() {
  timeline.timeScale(.2);
}

was trying to accomplish. However, the `onmouseover` fires but the animations still go at the same speed. Any idea why that is the case?

 

Also, is there a way to gradually change the time scale as opposed to changing it instantly?

 

Thanks again for the great aid you've provided, I'll be going through all of the links reading what they have to offer

Link to comment
Share on other sites

Oh, hey Zach! I'm glad you mentioned the css-tricks article. That's why your name sounded familiar. Very cool. 

 

To answer your question, yes, you can absolutely tween the timeScale, like this:

TweenLite.to(timeline, 1, {timeScale:0.2});

Remember, GSAP can tween pretty much any numeric property (including function-based getters/setters) of any object. So since TimelineLite and TimelineMax have a timeScale() getter/setter function, you can tween it! Heck, you can tween the time() too for very precise control of the playhead itself. Once you get the hang of it, a world of possibilities open up. 

 

Here's a simple demo:

http://codepen.io/GreenSock/pen/9f80e386f434e6841f5d00d46500f894

 

Is that what you're looking for?

Link to comment
Share on other sites

That's odd, but the query selector doesn't seem to be triggering the mouse event. If you add a console.log() you wont see anything.

 

If you change it to this:

document.getElementById("atom").onmouseover = function() {
  timeline.timeScale(.2);
}

Works as expected.

 

Rodrigo.

  • Like 2
Link to comment
Share on other sites

Could you explain what you mean by "Is there no way to have the initial starting positions mid animation?" You should be able to do just about anything. 

 

You can put set() calls into your timeline so that things immediately jump to certain values when the playhead reaches that spot. You can rewind a tween to its starting position anytime with seek(0). You can move the playhead of the entire timeline using seek() too. 

  • Like 1
Link to comment
Share on other sites

Yes, that's what I am looking for. Interestingly though, in the first pure CSS version I had I used rotateY(-360deg)... 

 

I realize now that my main issue is that I need to combine a constant of rotationX(90), meaning from start to finish, and also have a rotationZ(-360). In order to do so I learned how to use fromTo.

 

Thanks for all the help, guys! The project is exactly as how I'd like it to be

Link to comment
Share on other sites

Excellent, Zach. 

 

In case it's helpful, here's a version that uses a lot less code by leveraging TweenMax.staggerTo():

 

http://codepen.io/GreenSock/pen/1cbdbccbadc27f0b521736895f4bac73

 

Only 3 lines of animation code, and it repeats seamlessly too. :)

 

Oh, and if you hover over the atom, notice that the timeScale eases to 0.1. That's the effect you wanted, right? 

  • Like 3
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...