Jump to content
GreenSock

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

Kill TimelineMax instance and all tweens in it, then add tweens with the same target as before

Recommended Posts

Hi, I'm still new to GSAP and considering that I couldn't find anything helpful, I suppose that I'm missing something obvious. 

 

Basically, I have a timeline which I need to kill/clear, then rebuild it. The new tweens in the timeline have the same target as the old ones, although they might have different properties. This is the simplest demo of my problem: 

See the Pen gAcjI by nyordanov (@nyordanov) on CodePen

 

You will see that #test gets stuck. What is the correct way of doing this?

Link to post
Share on other sites

I figure it's because it's using the last value of the Timeline, so I updated your kill line to do this, and it worked:

timeline.go(0).kill();
I'm also new to timelines, so can't guarantee it's the "correct" answer.
Link to post
Share on other sites

Hi Nikolay and welcome to the GreenSock forums.

 

What happens here is a combination of things.

 

First when you kill a Tween/Timeline it's passed to garbage collection so it's a good idea to create the timeline again as well, using the same variable (no issues with that).

 

Then when the timeline is killed, it's stopped immediately, at that point the element is at a given position and later in your code you create a new instance for that element. For performance reasons GSAP records the current/starting values of the element's properties (rotation and x in this case) for future reference, so if the element's x and rotation values are not zero, GSAP will animate the element from the values given in the instance (x:200 and rotation:360) to the current ones. If the timeline is not killed/cleared at the end of it, the current values won't be zero for any of the properties. For example let's presume that the timeline is killed when the element is at x:95 and rotation:75, GSAP will animate the element from x:200 to x:95 and from rotation:360 to rotation:75.

 

So what you can do is pause the timeline at the end, kill it, create it again and finally add the new instance, like this:

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

timeline.add( TweenMax.from( '#test', 1, { x: 200, rotation: 360 } ), 0 );

// set the timeline position at the very end and kill it
// we set the timeline to that position by getting it's duration
timeline.pause(timeline.duration()).kill();

//create the timeline again and add a new instance
timeline = new TimelineMax({repeat:-1})
  .add( TweenMax.from( '#test', 1, { x: 150, rotation: 90 } ), 0 );

I forked your codepen:

 

See the Pen fhIsr by rhernando (@rhernando) on CodePen

 

Another pointer is that is better to use this methods (clear, kill, etc) in event handlers.

 

Finally for rotation transforms GSAP uses it's own syntax:

  • rotateX => rotationX
  • rotateY => rotationY
  • rotateZ => rotation

Rodrigo.

Link to post
Share on other sites

Thank you! I actually tried pause(0) initially, but it didn't work. I don't know why I didn't try pausing at the end of the timeline, but that's what did the trick.

Link to post
Share on other sites

You're welcome.

 

Well this is a very common situation when dealing with from() instances for the first time. The issue is that when you create your CSS there's no transforms in it (translate or rotation) so when the page renders for the first time both values (x and rotation) are zero. Then in your JS you create a from() instance with some values for x and rotation. The thing is that from() and fromTo() instances work by taking the element/object property from the value you've indicated to the value it had before the instance was created. So in this scenario the element goes from the values you pass in the config object to x:0 and rotation:0. So when the instance is at zero seconds the values are the ones passed in the config object and at the end of the Tween/Timeline are the ones that the element had when the instance was created, this because from(), fromTo() and set() instances are rendered immediately. In case you need it in another time, this can be changed by passing the corresponding boolean in the config object:

// lets assume that there's a button that will start the tween
var button1 = document.getElementById("button1"),
    t = TweenLite.from(element, 1, {x:200, rotation:360, immediateRender:false, paused:true});

// the immediateRender:false indicates that the element's position and rotation
// shouldn't change until the tween starts

button1.onclick = function()
{
  // once the user clicks on the button the tween starts and the element's position and
  // rotation are changed to the values indicated in the config object
  t.play();
}

Hope that this helps clearing things up.

  • Like 1
Link to post
Share on other sites

Thanks.

 

What if don't know whether the tween at the end of the timeline is a from() tween? I tried mixing to/from tweens in the same timeline and pausing at timeline.duration() only works for from() tweens. Is there any way to detect what's the last tween and act accordingly?

Link to post
Share on other sites

Hi Nikolay,

 

Well there's no official way to know what type of instance you're referencing in a Timeline, in fact this is the first time I address this question.

 

Since you're referencing the last tween in the timeline there might be a way. You can use the getChildren() method in order to get back an array with all the timeline instances. Then you can subtract 1 to the array length in order to point to the last instance. Finally when you have that you can check if the immediateRender string is present in the instance's vars object, something like this:

var tl = new TimelineLite(),
    tlChilds, tlChildsLength;

tl
  .to(element1, 1, {left:100})
  .to(element1, 1, {top:100})
  .to(element2, 1, {opacity:0.5})
  .from(element3, 1, {left:200});

// now get the nested instances in the timeline
tlChilds = tl.getChildren();
tlChildsLength = tlChilds.length;

// now check if the last instance is a from instance or not
if("immediateRender" in tlChilds[tlChildsLength - 1].vars)
{
  // in this case this code is executed because the last instance is a from instance
}

You must beware that, as far as I know, "in" and "for in" iterations are not the fastest's ones, specially when the object size is too big. Also I'm not completely sure if this is a recommended way of finding out if the instance is a from() or to() instance. Ultimately in this point the Big Kahuna himself could give us some pointers.

 

Rodrigo.

  • Like 1
Link to post
Share on other sites

The issue here is that if your timeline has a from() tween (like in your initial example) then as Rodrigo suggested, advancing the playhead to the end will successfully set the properties of the targets back to their "pre-tweened" state.

 

As you noticed, doing this for to() tweens requires going back to the beginning.

 

In either case, the desired result is a reset of the targets' properties to the pre-tweened state.

 

To avoid the hassle of assessing if your timeline has from() or to() tweens (which Rodrigo had a clever solution for) I would suggest 

 

1: keep track of all targets of your timeline (perhaps in an Array)

2: use a set() with clearProps:true to get rid of any and all inline styles set on the targets by GSAP

 

Also, in this case I don't see a reason to kill() the timeline and then re-instantiate a new one with the same name. I think I would just use clear() and reset the playhead back to time(0)

 

var timeline = new TimelineMax( {
  repeat: 5
} );


var tweened = [$("#test")]


timeline.from( '#test', 2, { x: 200 })
  .to("#test", 2, {x:100});


$("#kill").on("click", clearAndRebuild)


function clearAndRebuild() {
  //clear the timeline of all child tweens and set playhead back to beginning
  timeline.clear().time(0)
  //use clearProps to nuke inline styles of all tweened elements
  TweenLite.set(tweened, {clearProps:"all"})
  timeline.from( '#test', 1, { x: 200, y:200, rotateZ: 360 });
}

 

http://codepen.io/GreenSock/pen/mqdHx?editors=001

  • Like 1
Link to post
Share on other sites

Thanks, Carl. I only had time to try it today, but I think that's exactly what I need.

  • Like 1
Link to post
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.

×