Jump to content
Search Community

Invalidate & from confusion

x0b 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,

 

Firstly, let me say a huge thanks to Greensock for providing such amazing tools over the years, I've been using your products since AS2 Tweenlite and they never fail to amaze me with their power and usability...thank you!! 

 

I have made a simple fiddle to demo the problem here : http://jsfiddle.net/x0b/cXR7L

 

My situation is this: I want to have a main timeline that has 3 sections - an intro, a changeable middle section and an outro, in that order. Once the user has completed the middle section and the outro, they click a button and a new middle section replaces the current one, the rest remains the same.

 

Once the button is clicked I pause(0) both the outro and middle section to reset their tweens, then kill them both so they get removed from the main timeline (incidentally - remove does not seem to do anything for me as the duration of the main timeline remains the same if I check it after doing remove - is this a correct behaviour?). Then I add the new middle section and the outro back to the timeline.

 

The timeline is controlled by scrolling the output window and runs correctly initially; the green box moves down (intro) the blue box goes left 100px further than the yelow (middle section) and then they come back to their starting positions whilst the red box comes from 1000px to cover the green box (outro).

 

The problems once the button is clicked are two fold

 

1) The intro runs ok, the new middle section runs ok, but then as soon as the timeline enters the outro, the blue box jumps out to 200px and the yellow box jumps to 100px. I guess this is because the outro tween has for some reason stored these values the first time it is run, even though it was killed.

 

2) If I invalidate() the outro timeline, the blue box glitch disappears but then the from tween does not work correctly, I presume this is because the invalidate means the timeline has forgotten where the from tween started from?

 

So I'm kind of stuck between two problems and not sure whether I'm using the API wrong or the API can't do what I need. Can anyone please provide some insight?

 

Thanks!  8-)

Link to comment
Share on other sites

Hi,

 

First thanks for providing the fiddle with the reduced issue, it makes the job so much easier :)

 

For the timeline duration after you've killed the nested instances is normal, because the timeline's duration is recorded upon creation and I'm pretty sure that for optimization reasons it doesn't change.

 

What invalidates does is to remove the data recorded the first time the tween runs, which is ideal for this case. The issue with the from instance is a little more tricky. When a from() instance is created it renders immediately and the element's starting position is the one given by the CSS style (left:0 in this case), then the tween goes from 1000px to the initial value 0px. When you invalidate you're removing the initial data which is left:0px and setting a new one, where the element is when the tween starts again, which is 1000px, therefore the next time the tween plays it goes from 1000px to 1000px. The solution is to change the from() instance to a to() instance and use a set() instance to adjust the element's initial position, like this:

TweenLite.set($("#element4"), {left:1000});

tl3.to(element1, 2, {left:"0"}, "move3");
tl3.to(element2, 2, {left:"0"}, "move3");
tl3.to(element4, 2, {left:"0px"}, "move3");

Like that when you invalidate tl3 the red square will animate as expected.

 

Also since the part you're changing is the one that correspond to tl2, there's no need to remove tl3 as well. For doing that you can add the timelines to the parent one with labels, then you remove tl1 and then add tl2 to the indicated label, like this:

//add the original timelines to the parent
mainTL.add(tl0.play(), 'intro');
mainTL.add(tl1.play(), 'middle');
mainTL.add(tl3.play(), 'outro');

//remove tl2

//no need to pause all the timelines, just the parent
//since it controls the playhead of the nested ones
mainTL.pause(0);
     
tl3.invalidate();
    
mainTL.remove(tl1);

//add tl2
mainTL.add(tl2.play(),'middle');

I updated your fiddle:

http://jsfiddle.net/cXR7L/36/

 

Rodrigo.

  • Like 2
Link to comment
Share on other sites

It looks like Rodrigo beat me again, with perhaps a simpler solution;)

 

Often in situations where you want to build a sequence that varies (contains different tweens) each time it plays, I more often opt to just dynamically re-build the entire thing again.

 

No need to kill() and invalidate() a whole bunch of stuff. Just rebuild it.

 

This approach uses a bunch of functions that spit back timelines on demand:

http://jsfiddle.net/UsvcL/2/

 

function getIntro() {
  var tl = new TimelineLite();
  tl.to(blue, 1, {left:100});
  return tl;  
}


function getMiddleEffect1(){
  var tl = new TimelineLite()
  tl.to(yellow, 1, {left:100});
  return tl;
}


function getMiddleEffect2(){
  var tl = new TimelineLite()
  tl.to(yellow, 1, {left:200, rotation:360});
  return tl;
}


function getOutro() {
  var tl = new TimelineLite();
  tl.to(green, 1, {left:100});
  return tl;
}


mainTL.add(getIntro());
mainTL.add(getMiddleEffect1()); //yellow box moves right
mainTL.add(getOutro());

and then to later rebuild the timeline

 

    mainTL.pause(0).clear();
    mainTL.add(getIntro());
    mainTL.add(getMiddleEffect2()); // yellow box moves farther right and spins
    mainTL.add(getOutro());

 

 

This approach makes it very easy to create and manage complex animations. Its how we build things like the homepage animation http://www.greensock.com

 

 

-----

 

For solving your exact problem, Rodrigos solution is great. 

  • Like 3
Link to comment
Share on other sites

Even with a solution in place I agree with Carl, is much better to just kill the whole thing and create it again. Just a function with the variable parameters and you're set to go.

 

Imagine if instead of 4 elements you're animating 20, and instead of 3 nested timelines you have 10, you're in for a freaking nightmare, and since I've in that position where everything breaks down because of that it's a lesson learned the "hard way".

Link to comment
Share on other sites

Thanks for the replies!

 

I've tried both your solutions, unfortunately I use a LOT of from tweens and initialise them with a dynamically created off screen position. Because the from tween sets the position when they are created, this means all these elements start off screen as required.

 

I do this so it is easier for me to line everything up visually in the css at the design stage rather than put them off screen in the css (with a guessed off screen position) and then tween them to their correct position in the js file, that seems like a lot more clunky method and I guess rhernando's solution was in a similar vein to this.

 

If I use either of your suggestions then seemingly I cannot use from tweens, Carl's seems like it should work but unfortunately it doesn't, see here - http://jsfiddle.net/x0b/UsvcL/18/

Link to comment
Share on other sites

So I resolved the issue. I ended up using an amalgamation of both of your solutions.

 

Instead of relying on 'from' to position everything off screen initially, I wrapped all of the sections elements in a div and set that to display : none, removed the 'from' tweens and used 'set' and 'to' in it's place. Then every time I needed a fresh timeline I got a new instance returned from a function, and then using 'onStart' I set the container div to display : block.

 

This works well, it's a bit more code than I wanted to write but at this stage I'm past caring!

 

Thanks a lot for the pointers.

Link to comment
Share on other sites

Hi, 

 

I think the problem with the from() tweens was that once the mainTL was cleared and rewound back to time(0), the DOM elements still had inline-styles that GSAP had applied remaining (which is normal). Clearing and killing tweens does not affect the styles applied to the target elements.

 

So to truly rewind the main timeline and return all the objects back to their pre-GSAP states and have only your original css control their position / display you can call clearProps on them like so:

 

 

mainTL.pause(0).clear();
    TweenLite.set([blue, yellow, green], {clearProps:"all"});
    mainTL.add(getIntro(), "intro");
    mainTL.add(getMiddleEffect2(), "middle"); //yellow box moves and spins
    mainTL.add(getOutro(), "outro");
    mainTL.play();
 
The code above in bold will remove all the inline styles.
 
You can see it working here:
 
NOTE I removed the scrolling behavior as either I broke it somehow or it wasn't updating with the proper values once I reset the timeline. Might have to look into that further.
 
When watching the latest fiddle, notice I am using the same from() tweens as you and after you watch the first animation and click "change tween" the yellow box will spin and move.
  • 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.
×
×
  • Create New...