Jump to content
Search Community

Is it correct to spawn a lot of nested child timelines?

akobenzu 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, this is more of a theoretical question, so I don't think I can do a codepen.

 

Let's say I have 3 Vue components: parent and two children. Parent defines in what sequence children will be animating things. So in parent I want to have

new TimelineLite()
.add("x")
.add(child1.doA(), "x")
.add(child2.doB(), "x")
.add(child1.doC())

 

or something like that. Which approach would be correct for code in these `do` methods? In my app I have more components, and I want parent's code to look like this orchestration of what must be animated in children and in what order.

 

Right now I'm spawning a new TimelineLite in every `do` method. In children, code looks like this:

function doA() {
 return new TimelineLite().fromTo(...);
}
function doB() {
 return new TimelineLite().staggerFromTo(...).add(grandChild.doZ());
}

 

It's super convenient, but I'm not sure if spawning that many child timelines is good for performance or if it will become a problem with... not sure what... but maybe there are some issues with this? Child components have their own child components that also return new timelines every time they animate a piece, so I end up with a very big tree of very small timelines (and by "very small" I mean that they might be doing only one `fromTo` for example). It works like a charm though.  I also looked at the GSAP homepage demo code, and I think it's written in the same manner.

 

I started thinking about this because I wanted to move a bunch of code from the parent component into a new child, and that made me realize that this will be creating new child timelines — right now the animations are on the parent timeline, and with my approach I will spawn a new TimelineLite for things like only changing `autoAlpha` on a div.

 

So the questions are:

  1. is this correct approach?
  2. is there a noticeable/considerable performance penalty for spawning TimelineLite?
  3. will it go well with reversing, changing timescale or doing things like that regarding this army of nested timelines?
  4. are there any other concerns?
  5. should I be using TweenLite instead? I haven't grasped the difference
Link to comment
Share on other sites

Yep, nesting a bunch of timelines is totally fine. I doubt you'd ever notice a performance hit. If your child timeline only contains one tween, though, I'd say there's no point in wrapping it in a timeline. Only use timelines when you've got groups of tweens that you want to control or nest.

  • Like 2
Link to comment
Share on other sites

Hi @GreenSock! Yes that was my concern — it feels weird to only create a timeline for one tween... But let's say there are two components, each has a bunch of divs, and I want to bring them to the scene in an intertwined fashion. So

  1. change autoAlpha on div1 in component1
  2. change autoAlpha on div2 in component2
  3. change autoAlpha on div3 in component1
  4. change autoAlpha on div4 in component2
  5. ...

This is actually kinda the case for what I'm doing right now — I would like to say "See this thing in component1? It corresponds to this thing in component2". So it might not be `autoAlpha` to change, but maybe background color or text property or whatever, but it isn't much tweening going on in that spot.

 

What would you suggest to be a better pattern?

1. create a new timeline for every method

Component1 {
  function show1(){
   return new TimelineLite().fromTo("div1", 1, {autoAlpha:0}, {autoAlpha:1}) 
  }
  
  function show3(){
   return new TimelineLite().fromTo("div3", 1, {autoAlpha:0}, {autoAlpha:1}) 
  }
}

Component2 {
  function show2(){
   return new TimelineLite().fromTo("div2", 1, {autoAlpha:0}, {autoAlpha:1}) 
  }
  
  function show4(){
   return new TimelineLite().fromTo("div4", 1, {autoAlpha:0}, {autoAlpha:1}) 
  }
}

 

2. initialize component timeline somewhere on component instance and add tween to it

Component1 {
  const timeline = new TimelineLite() 


  function show1() {
   return timeline.to("div1", 1, {autoAlpha:0}, {autoAlpha:1}) 
  }

  function show3() {
   return timeline.to("div3", 1, {autoAlpha:0}, {autoAlpha:1}) 
  }
}

Component2 {
  const timeline = new TimelineLite() 


  function show2() {
   return timeline.to("div2", 1, {autoAlpha:0}, {autoAlpha:1}) 
  }

  function show4() {
   return timeline.to("div4", 1, {autoAlpha:0}, {autoAlpha:1}) 
  }
}

 

3. define all tweens upfront and pretend nothing has been done yet, then use `tweenTo`

Component1 {
 const timeline = new TimelineMax().fromTo("div1", 1, {autoAlpha:0}, {autoAlpha:1}, "show1").fromTo("div3", 1, {autoAlpha:0}, {autoAlpha:1}, "show3").progress(0).pause()

 function show1() {
   return timeline.tweenTo("show1")
 }
  
  function show3() {
   return timeline.tweenTo("show2")
 }
}

Component2 {
 const timeline = new TimelineMax().fromTo("div2", 1, {autoAlpha:0}, {autoAlpha:1}, "show2").fromTo("div4", 1, {autoAlpha:0}, {autoAlpha:1}, "show4").progress(0).pause()
 
 function show2() {
   return timeline.tweenTo("show2")
 }
  
  function show4() {
   return timeline.tweenTo("show4")
 }
}

 

Sorry if I'm getting too stubborn on getting THE ANSWER, it's just that I'm going to have several big scenes that work in this fashion (I'm creating an lengthy animation explaining a complex piece of calculation), so I would love to get your opinion on the best way to write this, so I don't have to rewrite a lot of stuff when I realize my approach was wrong. You guys are the best!

Link to comment
Share on other sites

Definitely avoid #2 because that'd keep appending tweens to a timeline, so they'd stack up and not get released for garbage collection (unless you set autoRemoveChildren to true). Your timeline would keep getting longer and longer. And depending on where the playhead of that timeline is when you append the tweens, they may not happen for a while (because they get added to the end of the timeline by default). All of those things could be controlled, of course, but my point is that it just seems kinda messy. 

 

Technically approach #3 is probably the most efficient. However, that bakes in all the tweens from the beginning which is great for performance but not so good if you need things to be dynamic. For example, let's take a simple scenario - you have three buttons that tween a box's color to red, blue, and green. All tweens are 1 second long. What if the user clicks red, then blue, then halfway through that tween they click green? If you dynamically create your animations on-the-fly with each click, it'll work beautifully because a to() tween grabs whatever the current value is and uses it for the "from" value. So if it's halfway between blue and red, and then they click green, it'll be totally smooth. But if you try pre-baking everything, that can't work. See what I mean? 

 

I noticed your tweens are all fromTo(), so you're forcing the "from" every time. That may be perfect, but beware that it'll cause a jump if the element is partially tweened when that one fires.

 

Make sense? 

 

And again, if you're only putting one tween into a timeline, just use a tween instead. In other words: 

//NOT AS GOOD:
function show1(){
   return new TimelineLite().fromTo("div1", 1, {autoAlpha:0}, {autoAlpha:1});
}

//BETTER:
function show1(){
   return TweenMax.fromTo("div1", 1, {autoAlpha:0}, {autoAlpha:1});
}

 

Those tweens can still be added to a master timeline, of course, just like a TimelineLite could. No difference at all. 

 

Does that help? 

  • Like 4
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...