Jump to content
GreenSock

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

Stagger is not being honoured?

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

Hello. Thanks for the priceless GSAP. 
 
However, not sure why stagger isn't honoured with this code:
 

function getButtonsInAnimation(callback) {
    var i, spots, spot, tween = new TimelineLite({paused: true, onComplete: callback});
    for(i in spots = shuffle(hotspots)) {
        spot = spots[i];
        tween.add(TweenLite.fromTo(spot, 0.3,
            {scale:0, alpha:0, left:290, top:168},
            {scale:1, alpha:1,
                left:parseInt(spot.css('left')),
                top:parseInt(spot.css('top')),
                ease:Expo.easeOut}
        ), undefined, 'start', 0.05);
    }
    return tween;
}

 
As you can see, I'm adding new TweenLite object with TimelineLite.add() method. But it executes added tweens in sequence, ignoring the stagger value. Also tried to pass stagger value to the TimelineLite constructor. Same result.
 
As of position property of TimelineLite.add() method, I also tried values, without any luck: '+=0', 0, false.
 
Is there something I misunderstand?

Link to comment
Share on other sites

Just tried another approach:

 

function getButtonsInAnimation(callback) {
    var i, spots, spot, tweens = [];
    for(i in spots = shuffle(hotspots)) {
        spot = spots[i];
        tweens.push(TweenLite.fromTo(spot, 0.3,
            {scale:0, alpha:0, left:290, top:168},
            {scale:1, alpha:1,
                left:parseInt(spot.css('left')),
                top:parseInt(spot.css('top')),
                ease:Expo.easeOut}
        ));
    }
    return new TweenLite({paused: true, onComplete: callback, tweens: tweens, stagger: 0.3});
}

And all Tweens are executed immediately. Hm.

Link to comment
Share on other sites

For now I'm using a workaround with manual delay attribute, which does work as expected:

 

 

 

 function getButtonsInAnimation(callback) {
    var i, spots, spot, tweens = [];
    for(i in spots = shuffle(hotspots)) {
        spot = spots[i];
        tweens.push(TweenLite.fromTo(spot, 0.3,
            {scale:0, alpha:0, left:200, top:100},
            {scale:1, alpha:1,
                left:parseInt(spot.css('left')),
                top:parseInt(spot.css('top')),
                ease:Expo.easeOut,
                delay:0.05 + 0.2 * Math.random()}
        ));
    }
    return new TimelineLite({paused: true, onComplete: callback, tweens: tweens});
}
Link to comment
Share on other sites

Hi,

 

In your first approach try changing the align method (check the api) to "stagger", like this:

function getButtonsInAnimation(callback) {
    var i, spots, spot, tween = new TimelineLite({paused: true, onComplete: callback});
    for(i in spots = shuffle(hotspots)) {
        spot = spots[i];
        tween.add(TweenLite.fromTo(spot, 0.3,
            {scale:0, alpha:0, left:290, top:168},
            {scale:1, alpha:1,
                left:parseInt(spot.css('left')),
                top:parseInt(spot.css('top')),
                ease:Expo.easeOut}
        ), undefined, 'stagger', 0.05);
    }
    return tween;
}

 

For your last approach you could try multiplying the delay time by the i value in the for loop, something like this:

 

function getButtonsInAnimation(callback) {
    var i, spots, spot, tweens = [];
    for(i in spots = shuffle(hotspots)) {
        spot = spots[i];
        tweens.push(TweenLite.fromTo(spot, 0.3,
            {scale:0, alpha:0, left:200, top:100},
            {scale:1, alpha:1,
                left:parseInt(spot.css('left')),
                top:parseInt(spot.css('top')),
                ease:Expo.easeOut,
                delay:0.05 * i}
        ));
    }
    return new TimelineLite({paused: true, onComplete: callback, tweens: tweens});
}

Like that your tweens will be add in your timeline starting with the first value of i and then going up.

 

And finally you could also try creating the array of tweens in the for loop and then add the array, like that your code will be more simple and you'll be tackling one thing first and then the other, so if you want to change something it will take less time doing so, like this:

function getButtonsInAnimation(callback) {
    var i, spots, spot, tweens = [], timeLline = new TimelineLite;
    for(i in spots = shuffle(hotspots)) {
        spot = spots[i];
        tweens.push(TweenLite.fromTo(spot, 0.3,
            {scale:0, alpha:0, left:200, top:100},
            {scale:1, alpha:1,
                left:parseInt(spot.css('left')),
                top:parseInt(spot.css('top')),
                ease:Expo.easeOut}
        ));
    }
    return timeLine.add(tweens, "stagger", 0.05)
}

Hope this helps,

Cheers,

Rodrigo.

Link to comment
Share on other sites

Hey Rodrigo.

 

Thanks for the reply. I will check the code, but the problem is that 'stagger' property isn't documented in the api:

 

 

align : String - Only used in conjunction with the tweens special property when multiple tweens are    to be inserted immediately. The value simply gets passed to the add() method. The default is "normal". Options are:
  • "sequence" : aligns the tweens one-after-the-other in a sequence
  • "start" : aligns the start times of all of the tweens (ignores delays)
  • "normal" : aligns the start times of all the tweens (honors delays)

 

And:

 

 

 
align:String (default = normal) — Determines how the tweens/timelines/callbacks/labels will be aligned in relation to each other before getting inserted. Options are: "sequence" (aligns them one-after-the-other in a sequence), "start" (aligns the start times of all of the objects (ignoring delays)), and "normal" (aligns the start times of all the tweens (honoring delays)). The default is "normal".
Link to comment
Share on other sites

Hi,

 

I tested a few things and came up with the fact that not defining the position in which each tween is added to the timeline could be causing this issue, check this fiddle and play around with it, if you delete the '+=0' there's no staggering but if you keep that it will respect the stagger time you're giving it. I also added some callbacks into the tweens so you can also check how 'sequence' align works with and without a stagger time.

tl.add([tween1, tween2, tween3], "+=2", "stagger", 0.5);

If you don't declare "+=2" or maybe in this case "+=0" all the tweens are added at time 0 in the timeline, even if you declare an align string and stagger time. Maybe Carl or Jack could explain why this happens, I at least don't know.

 

Cheers,

Rodrigo.

Link to comment
Share on other sites

I see what's causing the confusion here, and I've updated the docs to help address it...

 

The 3rd and 4th parameters of the add() method are only relevant in cases where you're passing in an ARRAY of tweens/timelines/callbacks/labels as the first parameter. In other words, "align" and "stagger" don't really matter when you're just adding one tween because there's no context (you can't stagger one tween and aligning doesn't matter when you don't have multiple tweens). 

 

It sounds like you assumed "align" and "stagger" were somehow related to the tweens that already existed in the timeline. Nope. And there are several reasons for that (I'll spare you the explanation unless you request it). 

 

By default, when you don't define any insertion point (the 2nd parameter), the tween will get appended to the end of the timeline (sequenced). You were using "undefined" as the insertion point, so it did the normal/default behavior of sequencing them. 

 

I think you meant to do something like this:

 

function getButtonsInAnimation(callback) {
    var i, spots, spot, tween = new TimelineLite({paused: true, onComplete: callback});
    for(i in spots = shuffle(hotspots)) {
        spot = spots[i];
        tween.add(TweenLite.fromTo(spot, 0.3,
            {scale:0, alpha:0, left:290, top:168},
            {scale:1, alpha:1,
                left:parseInt(spot.css('left')),
                top:parseInt(spot.css('top')),
                ease:Expo.easeOut}
        ), i * 0.05);
    }
    return tween;
}

Notice the i * 0.05 at the end. That is defining an absolute position in the timeline based on the loop iterator. 

 

Does that clear things up? 

 

Again, I've added a note in the docs to make it more clear that the last 2 parameters of add() are only pertinent for when you're adding arrays.

Link to comment
Share on other sites

Hi,

 

You know this was more simple than I thought. The thing is that in the first code you tried you were calling the add method every time the for loop executed so with that you're adding each tween at the end of the timeline.

 

The second and third approaches were right on the spot regarding the for loop, but the problem was the creation of the timeline. The thing is that you created the tweens but by doing this:

 return new TimelineLite({paused: true, onComplete: callback, tweens: tweens});

no tween was included in your timeline, so the tweens were created and immediately executed that is why no stagger was happening.

 

So what you should try is the last code I proposed:

function getButtonsInAnimation(callback) {
    var i, spots, spot, tweens = [], timeLine = new TimelineLite({paused:true, onComplete: callback});
    for(i in spots = shuffle(hotspots)) {
        spot = spots[i];
        tweens.push(TweenLite.fromTo(spot, 0.3,
            {scale:0, alpha:0, left:200, top:100},
            {scale:1, alpha:1,
                left:parseInt(spot.css('left')),
                top:parseInt(spot.css('top')),
                ease:Expo.easeOut}
        ));
    }
    return timeLine.add(tweens, 0, "stagger", 0.05)
}

Anyway I updated the fiddle.

 

Hope this helps,

Cheers,

Rodrigo.

Link to comment
Share on other sites

And for the record, you could probably simplify your code by using the staggerFromTo() convenience method like this:

 

function getButtonsInAnimation(callback) {
    var tl = new TimelineLite({paused:true, onComplete:callback});
    tl.staggerFromTo( shuffle(hotspots), 0.3, {scale:0, alpha:0, left:290, top:168}, {scale:1, alpha:1, left:parseInt(spot.css('left')), top:parseInt(spot.css('top')), ease:Expo.easeOut}, 0.05);
    return tl;
}
Link to comment
Share on other sites

Thank you GreenSock. That nails it.


And yes, the staggerFromTo is what I initially used, but then realised I'd rather add some randomness to it.

 

Rodrigo, thank you very much for the effort. Really appreciate that. Topic is now resolved.

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.
×