Dipscom

Pause nested timeline created from function call

Recommended Posts

We all know using functions to generate timelines is the way to go but sometimes I find myself needing to stop halfway inside the child timeline but without creating a master timeline scrubber.

 

But for the life of me, I can't pause the nested animation. I can fake it by adding a .call() in the child to pause the master but I assumed if I paused the child, the master timeline would stop as well. But it does not seem the case. Is that expected behaviour?

 

See the attached pen for a super-duper simple example.

 

Ta.

  • Like 1

Share this post


Link to post
Share on other sites

Children don't tell their parents what to do... at least well behaved children don't.

 

Think about elements. A child element cannot change the position of its parent, and it cannot stop its parent's position from changing.

 

So you would need to do to do something like this. Not pretty, but when you see repetition, that usually means you can use a loop to simplify things.

 

var master = new TimelineLite()
  .add(fadeIn(".d1"))
  .addPause()
  .add(fadeOut(".d1"))
  .add(fadeIn(".d2"))
  .addPause()
  .add(fadeOut(".d2"))
  .add(fadeIn(".d3"))
  .addPause()
  .add(fadeOut(".d3"))

function fadeIn(el) {
  return new TimelineLite().from(el, 0.5, {xPercent:-50, autoAlpha:0})
}

function fadeOut(el) {
  return new TimelineLite().to(el, 0.5, {xPercent:50, autoAlpha:0}, "+=0.2")
}

 

 

  • Like 3
  • Haha 2

Share this post


Link to post
Share on other sites

Thanks for the demo with your question.

Blake beat me to the punch with those pesky children trying to control their parents.

 

Like Blake said, the paused state of a child animation does not affect the paused state of its parent. Pausing the parent will always pause the children. The position of the parent’s playhead dictates what is rendered in all child animations. This is a very purposeful design rule that dictates how the entire engine performs. 

 

Stepping back a bit, consider that GSAP has a root timeline that all animations belong to. When you create even a simple TweenLite tween it is added to this root timeline

 

var t = TweenLite.to("body", 1, {rotation:1})
console.log(t.timeline); // logs out a timeline

 

 

It is very good that pausing t does not pause the root timeline thus making every animation pause. Of course Jack could write code that made it so that the root timeline doesn’t get paused in this case, but its good to have consistent behavior throughout. I can understand in your situation how you would like pausing the child to pause the parent, but I think in the grand scheme of things the current design makes the most sense in the most common use-cases.

 

Imagine if pausing the parent did not make the children stop playing? you would have to identify every child tween and pause it (I know you’re not suggesting that).

 

That probably doesn’t give the most clear or accurate explanation of why pausing the child doesn’t pause the parent, but hopefully you trust me that it works that way for good reason and maybe Jack can find the obvious thing I’m not remembering;)


As for your demo, its an interesting scenario. The timeline that is created inside your function has no idea what timeline it is being put inside of after it gets created and returned so there is no great way to write code in there that says “pause my parent”. Your current solution of using call() to call a function that pauses the parent is probably the best thing there is but it isn’t entirely accurate as some minuscule amount of time will elapse while the function is being called and code is being executed. So the pause will not happen at the exact same time your call() happens. A few milliseconds of time drift probably won’t impact what you’re doing but figured I’d mention it anyway. This is the very reason we created a specific addPause() function so that it would ensure the timeline gets paused exactly when it should. Prior to addPause() folks were writing there own calls() to pause the timeline.

 

For pausing the parent with call(), the only slight enhancement I can offer is dynamically finding the parent of the timeline that the call() is in like:

console.clear();
function fadeInOut(el) {
    var tl = new TimelineLite({id:"child"});
    tl.from(el, 0.5, {xPercent:-50, autoAlpha:0})
    tl.call(pauseMyParent);
    tl.to(el, 0.5, {xPercent:50, autoAlpha:0}, '+=0.2');
    return tl;
}

var master = new TimelineLite({id:"master"})
master.add(fadeInOut('.d1'))
master.add(fadeInOut('.d2'))
master.add(fadeInOut('.d3'))
function pauseMyParent() {
  console.log(this.timeline.vars.id);
  console.log(this.timeline.timeline.vars.id)
  this.timeline.timeline.pause();
}
$("#resume").click(function(){
  master.resume();
})


https://codepen.io/hansel234/pen/vJjwWp?editors=1111


Maybe that helps a little. Don’t know. There will still be some slight time-drift. 

  • Like 4

Share this post


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.