Jump to content
GreenSock

Acccent

Dynamically creating/modifying timelines on window resize (general JS noobism...)

Go to solution Solved by GreenSock,

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

Hey everyone,
 
I'm having a bit of an issue that probably is partially, but not entirely, related to GreenSock... I figured you guys would be kind enough to lend me a hand :)
 
I'm making a slider, with elements fading in and out in a sequence. I want the height of the parent to change depending on the height of the child that's currently visible. Problem is, the height of the children depends on the window's width, so I need to do something to recalculate everything on resize.
 
 
First of all, the slider itself:

TweenMax.set(el, { height:h }); // set the height of the parent to the height of its last child (useful for looping)

els.each(function(){
    var xh = $(this).outerHeight(); // get the height of the child that we're about to display

    if ( h < xh ) { // if the child is taller: first make the parent grow, then make it appear

        if( delay == 0 ) { delay = 0.3; }
        loop.fromTo(el, 0.3, { height:h }, { height:xh, ease:Power1.easeInOut, immediateRender:false }, delay - 0.3)
            .to($(this), 0.4, { autoAlpha:1, ease:Linear.easeNone }, delay);

    } else { // if the child is smaller: make it appear and then make the parent shrink

        loop.to($(this), 0.4, { autoAlpha:1, ease:Linear.easeNone }, delay)
            .fromTo(el, 0.3, { height:h }, { height:xh, ease:Power1.easeInOut, immediateRender:false }, delay + 0.4);
    }

    h = xh; // store the new height
    delay += 3; // offset the position for the next child

    loop.to($(this), 0.4, { autoAlpha:0, ease:Linear.easeNone }, delay); // add the current child's fade out
});

This works as I want it to. (I don't use staggerTo because this gives me more control; I've simplified it for this example, there's some added tweaks normally, but nothing relevant for this topic.)

 

That code is executed on each element that has the .slider class, in the codepen there's just one but it's enough to illustrate the issue.

 

Now, what I want is to re-execute it all whenever the window's resized, so that the heights can be recalculated, so here's what I did:

if ( typeof loop != 'undefined' ) { // check if the current object already has a loop timeline defined
    var p = loop.time(); // store the timeline's position
    loop.kill();
}

loop = new TimelineMax({ repeat:-1 });

/*
 * Timeline code shown above goes here
 *
 */

if ( p ) { loop.time(p); } // restore the new timeline to the position it was had before I killed it

The problem is loop is always undefined. So what happens is, a new timeline is created whenever you resize the window... and it creates a lot of weird behaviours. You can see it in the codepen.

 

 

I'm pretty sure the problem here is one of scoping, but that's a concept I'm not super good with :(

Can anyone have a look and nudge me in the right direction? (Also, if you see something that feels wrong and should be done differently, feel free to let me know!)

 

edit: linked codepen is the fixed version!

See the Pen ZQggPW by Acccent (@Acccent) on CodePen

Link to comment
Share on other sites

  • Solution

If I understand your question correctly, perhaps the problem is simply that you're forgetting to return the elements to their beginning state each time, before running your code that's creating the timeline. So:

//OLD:
loop.kill();

//NEW:
loop.pause(0).kill();

Then again, maybe I misunderstood. Does that help at all? When I dropped that in, it seemed to work well (at least the way I expected it to). 

  • Like 2
Link to comment
Share on other sites

Haha! I can't believe it was that easy! I thought kill() also rewinded back timelines to their initial position.

 

 

I had to do another thing on top of that, which is storing the timelines I created in an external array, like so:

var loops = [];

function setupfade() {
    $fadecycle.each(function(i){

        /* other var declarations... */

        if ( typeof loops[i] != 'undefined' ) {
            var p = loops[i].time();
            loops[i].pause(0).kill();
        }

        loops[i] = new TimelineMax({ repeat:-1, repeatDelay:interval - delay });

        /* working with loops[i] */
        
    });
}

I'll update the codepen with my final code a bit later, in case anyone's interested in using the same slider :)

  • Like 1
Link to comment
Share on other sites

here's the updated codepen :) gave me quite a headache figuring out the maths to make it cycle at a fixed interval haha.

 

See the Pen ZQggPW by Acccent (@Acccent) on CodePen

  • Like 1
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.
×