Jump to content
GreenSock

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

TimelineMax, selecting a dynamic set of elements.

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 there, love the GSAP library, but having a strange issue that I've never really had to address before.

 

I wish to create elements dynamically on the page outside of the GSAP timeline, then within a created timeline, have the selector pick up whatever set of elements are currently matching the selector. The issue is the set appears to be 'cached' with repeat loops of the timeline.

 

The codepen is similar to my code, but stripped down to just the basics of what's not working.

In the last staggerTo, the elements are moved and then removed from the DOM. The onRepeat calls the same function to add new ones to the DOM, but repeat loops of the timeline don't evaluate the selector contents each time.

 

As a side note, I was a little surprised that the onStart function didn't run before the rest of the constructed timeline, including the staggerTo's. I guess just a failure in how I comprehend the staggerTos are functioning, it's related to the same issue really, in that I need to be able to tell staggerTo, only evaluate the selector once you get to whichever part of the timeline.

 

I did manage to get this working by using .add instead of the stagger, and inside there creating new timelines being passed the same selector and returning a set of tweens. These at least seem to be executed as the timeline 'reaches' them.

 

Hope someone can provide some assistance or help me get my thinking straight about why this is expected behaviour and the correct method I should use to achieve what I'm after.

 

 

Thanks!

See the Pen ayGREB by othbert (@othbert) on CodePen

Link to comment
Share on other sites

Hi and welcome to the GreenSock forums,

 

 The issue is the set appears to be 'cached' with repeat loops of the timeline.

 

Yes, the targets of tweens are recorded by the engine. GSAP puts a huge emphasis on performance. If animations had to search the DOM for targets and read their appropriate css values every time an animation repeated or restarted it would slow things down considerably. By storing references to targets and recording certain animated values the engine is able to run super fast. It does all the "heavy lifting" only once.

 

Although it may seem like an optimization, re-using the same timeline isn't going to save you much. In your case I would suggest that you just create a new timeline each time you need a new set of animations. GSAP is great at creating timelines on the fly, even one's with thousands of tweens.

 

Destroying and creating new DOM elements is going to be incredibly more processor intensive than creating a new timeline. 

 

If you still have questions or concerns just let us know.

 

 

 

 

 

  • Like 5
Link to comment
Share on other sites

Thanks Carl! I kinda figured it could be something like this and due to a great boost in performance for typical (i.e. every other scenario where the DOM shouldn't need to be re-read) scenarios.

 

Nevermind, I wrote a new version where I use a parent timeline to keep the abstraction of the repeat, and repeat delay parameters etc. then onStart and onRepeat of that timeline I call a function which generates a new timeline running the staggerTo's. My only issue now is a nicer way to control the timing of everything, as the parent timeline doesn't know or care about "waiting" for the child timelines to finish before repeating. Been a while since I had to handle that control and I'd like to be able to do it programmatically seing as the functionality I am creating should be used in multiple places with varying parameters etc and I don't want to have to calculate the delays for everything manually.

 

Am I missing something easy here? A parameter on the parent timeline that can listen to the children, or something in the children to block the parent? The answers I found so far are from 2014 and involve a lot of finding out exact timings etc and extending the addPause method. Wondering if this is now implemented in the core seeing as it would seem (to me at least) to be quite a valuable and typical scenario when nesting parent and child timelines.

 

Cheers!

Link to comment
Share on other sites

Cool. Seems you have a solid understanding of the core mechanics and are quite capable of finding creative solutions.

 

I may not be understanding things completely but I get the sense you are dynamically injecting child timelines into a timeline while its running or at least after it is initially created. 

 

As you know, when you are creating a timeline initially, all animations get added at the end.

var tl = new TimelineLite();
tl.to(obj1, 1, {x:100})
  .to(obj2, 1, {x:100})
  .to(obj3, 1, {x:100})

 

So in the code above obj1, obj2, obj3 will animate in direct succession.

 

From what I gather from your question, you may want to inject another animation between obj1 and obj2.

 

if you do something later to add an animation at a time of 1 second (immediately after obj1 finishes)

 

tl.add(newAnimation, 1);

 

that animation will not push obj2 and obj3 further along in time based on the duration of newAnimation. newAnimation and obj2 will both start at a time of 1. Timeline's weren't designed to be auto-adjusting when new things get added (performance, file-size, etc).

 

My assumption is that in this scenario you would like to shift obj2 and obj3 forward. 

 

Take a look at shiftChildren() it will allow you to grab all the animations after a time of 1 second and move them forward based on the duration of the new thing(s) you are adding. 

 

Let us know if that helps

 

 

 

 

 

  • Like 3
Link to comment
Share on other sites

Thanks Carl, that's not really quite what I meant though... 

 

Here's a fleshed out codepen with more of what I'm trying to achieve. Didn't want to take it too much out of the project structure, so sorry if it's a little illegible or strangely written.

 

There are a couple of issues with how I have it this way.

1) repeatDelay appears to affect the timing of the timeline in the sense that the "selectAndDraw" function is called multiple times per repeat iteration if there is a delay value. Without the repeatDelay, the function is correctly called only 3 times.

2) The whole idea I meant in my previous reply was that the parent timeline I create and attach to project.timeline, should have child timelines attached to it. The parent should repeat and call the child timeline functions again each iteration. The parent should be return a timeline which will help it determine when the children have 'finished' and therefore it is time for the parent to repeat. However, parent timing is unaffected by the children, it loops and that's that. Specifying a delay is just an absolute. If the child timelines take longer, they overlap with the next iteration. Setting the position on the second staggerTo in the child timeline demonstrates this.

 

I strongly suspect I have misunderstood how to add the child timelines properly, or to call functions properly.

Any assistance would be great! :)

 

Thanks!

 

 

See the Pen dzKJgo by othbert (@othbert) on CodePen

 

 

Link to comment
Share on other sites

Hi OSUblake,

 

That's sort of it... I see the animation is fixed here, however your version of the 'staggered' function calls itself as the last action before returning a timeline. While that works in this example with just a few iterations of the cycling characters, The original intent (which I apologise for not making clear, or showing as an example in the code, I wanted to try to demonstrate just the parts of the problem I am having), is to repeat indefinitely choosing a random set of elements to 'selectAndDraw'.

 

Would this not cause memory to get gobbled up as the timeline creates new subtimelines in the staggered function and attaches them nested to a main timeline that never completes? I do not know enough about how GSAP handles this, but if it were 'normal' JS with a recursive function in a callback that would be the case, correct?

 

Interesting that this animation works so much better though, I can't see any difference except for the delay and repeat parameters (or the fact you call the removeLayer effectively 'onCompleteAll' of the whole hiding staggerTo, instead of after each hiding staggerTo like I've done), between this adding to itself, or my version adding to a parent timeline, that could cause such wonky animation in mine.

 

Cheers

Link to comment
Share on other sites

Hi @othbert

 

I probably should have commented out the return statement for the subtimeline. All I'm doing is a recursive call to the same method when the animation ends, and I'm not saving a reference to all the timelines it's creating, so no, it shouldn't create a memory leak.

 

Here's a post you should check out. I think it might clear up some confusion about how a function/method works when you add it to a timeline. All you were doing, and what I did, is add some callbacks to a timeline. Returning a subtimeline in a callback does not add it to the timeline that called it. So your main timeline had no child timelines, which is why its duration was not being affected when you created a new subtimeline.

 

 

 

  • Like 1
Link to comment
Share on other sites

Ahh that's interesting, I certainly was thinking that the sub-timelines were somehow added into the execution flow of a parent timeline by virtue of having their tweens incorporated into it or something along those lines. I see now that if it's just a function call with no stored reference there would be no excessive memory usage, the return did catch me out a little bit :)

 

Very cool linked post too, thanks! I think that covers it... if I have something else I'll ask but I guess the way to go about it is to add child timelines properly instead of callbacks, or change the structure to recursively call itself.

 

EDIT: What am I thinking? child timelines wouldn't work in this case anyway, right? seeing as they would be created / evaluated on load (and not at runtime) for adding to a parent timeline.

Edited by othbert
need more coffee obviously
  • Like 1
Link to comment
Share on other sites

Othbert,

 

Glad to hear that @OSUblake could come to the rescue!

I have to admit I had some trouble wrapping my head around the demo ;) but it seems you have been in good hands.

Good luck with the project!

 

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