Jump to content
Search Community

Dynamic property in nested timelines

Torrfura test
Moderator Tag

Recommended Posts

I've hit a wall, tried to simplify my issue as good as possible.

I have a couple of nested timelines, within one child timeline, I want to dynamically update from X property, on each iteration, to make it somewhat dynamic and responsive... I've spent all day figuring this out, thought ModifiersPlugin would do, but there is obviously something I'm missing.


The example is stupid, but it displays my issue atleast. Please help!

See the Pen YzzJgLB by joseelsantos (@joseelsantos) on CodePen

Link to comment
Share on other sites

Hey Torrfura, and welcome.

 

Creating new tweens in the onComplete is the best way to do it using GSAP 2. However, in the new GSAP 3, there's a built in way to do this: repeatRefresh! This is actually a perfect example of how GSAP 3 is significantly better than GSAP 2 :) Using GSAP 3 also removes the need to use handlebars because it has built in utility methods like random but you should probably just use separate but similar string random() that GSAP 3 has.

 

Currently I believe that repeatRefresh only works with repeating tweens, not repeating timelines. But I'll talk to @GreenSock to discuss how to best implement it on timelines. 

 

See the Pen jOOeovj?editors=0010 by GreenSock (@GreenSock) on CodePen

 

P.S. GSAP automatically uses querySelectorAll on selector text that you give it so you don't need jQuery for that.

Link to comment
Share on other sites

Hi, Going for gsap 3 is not possible at the moment, unfortunately. :( And as you can see, it doesn't work at all in my example above. The start (from) position is only set the first iteration / inclusion. It never updates later on, even though it is a tween.

 

Is there some other way I can accomplish this?

GSAP 3 looks awesome, but i'm on a big boat, and cannot switch overnight.

 

Thanks for your tips and quick reply!

Link to comment
Share on other sites

10 minutes ago, Torrfura said:

GSAP 3 looks awesome, but i'm on a big boat, and cannot switch overnight.

GSAP 3 is mostly back-compatible with GSAP 2. I think you'd be surprised how easy it is to switch :) 

 

10 minutes ago, Torrfura said:

Is there some other way I can accomplish this?

Using onComplete is the way to go in GSAP 2. It takes a little more code, but you can do this:

 

See the Pen vYYVwor?editors=0010 by GreenSock (@GreenSock) on CodePen

Link to comment
Share on other sites

Thanks again, just to be clear, I really appreciate your efforts! :) 

 

The problem is when I have nested timelines (multiple, and quite deep, 5 - 6 nested timelines), and I restart my main timeline before the timeline that contain the Tween which has modifiers properties, has been run, it never updates. Then a onComplete function wouldn't do the job neither, since it'll never fire.

 

So, my main issue, which is a real showstopper here, is that I cannot update (neither via .set or .call etc) the start X position, of an object in a Tween deep within nested timelines, when it iterates / restarts.

Please don't give up on helping me :) I need this bad!

(I will try upgrading, and getting my team with me for doing it. Loooads of automated tests that need to verify :)

Link to comment
Share on other sites

Ok, so I managed to get my team along on the ride of upgrading. :) 

 

I've minified my example as much as I can. Remember, this problem I have is deep within nested timelines, so using onComplete etc on main tl, to re-draw sub timelines 3-4 levels deep, feels vastly inefficient. 

 

repeatRefresh does not help me, so I'm starting to wonder what that property really do? 

In short: I want the sub-tween / sub-timeline to update it's start (from position) x, each time the playhead of the parent timeline get to the first frame of that tween. So if i'm repeating the timeline, or choose to restart etc. It calculates a new from x value, when the playhead is on 0 in that tween...

 

var tl = gsap.timeline({
  repeat: -1,
  delay: 5
});

tl.add(getTween());
tl.play();

function getTween() {
  return gsap.fromTo('.box', {
    x: () => {      
      var rnd = gsap.utils.random(-200, 200, 1);
      console.log('[tween] from x: ', rnd);
      return rnd;
    },
    repeatRefresh: true,
    immediateRender: false
  }, {
    duration: 2,
    x: 0
  });   
}

 

See the Pen YzzJgLB?editors=1111 by joseelsantos (@joseelsantos) on CodePen

Link to comment
Share on other sites

8 minutes ago, Torrfura said:

Remember, this problem I have is deep within nested timelines, so using onComplete etc on main tl, to re-draw sub timelines 3-4 levels deep, feels vastly inefficient. 

I understand that is your setup. I don't understand why you can't use one of the approaches that I've outlines in the posts above.

Link to comment
Share on other sites

2 minutes ago, ZachSaucier said:

I understand that is your setup. I don't understand why you can't use one of the approaches that I've outlines in the posts above.


As you see in my last example, repeatRefresh within my tween, added to a timeline, does not fire whenever the timeline repeats.
But yeah, I'm probably approaching my problem from a weird angle, but that's why I'm here asking for help :)
 

The problem I am trying to solve:
The sequence / timeline I am writing, is mostly dynamic depending on user input before the timeline begin. The user can whenever they choose, pause, restart or skip to the end of the timeline. 

 

Since we live in a world of a million devices, I need to make sure it is responsive. In that sense, I must recalculate the start position of some tweens, if the user has resized / rotated their device somehow, before the playhead in the main timeline has reached start position of that specific tween. I am animating from a set value, to x/y 0 (to keep it dynamic / responsive when the tween / timeline ends).

Link to comment
Share on other sites

5 minutes ago, Torrfura said:

I need to make sure it is responsive. In that sense, I must recalculate the start position of some tweens, if the user has resized / rotated their device somehow, before the playhead in the main timeline has reached start position of that specific tween. I am animating from a set value, to x/y 0 (to keep it dynamic / responsive when the tween / timeline ends).

If they change the window size, you should kill the old timeline and create a new one with the correct values.

Link to comment
Share on other sites

Just now, ZachSaucier said:

If they change the window size, you should kill the old timeline and create a new one with the correct values.

 

That feels a bit submissive? :) If I have a timeline that has over 60 second total duration, I'd kind of kill the experience for the user if they are 45 seconds in the animation, and their mobile device happends to change orientation, to just kill the animation and start over? That's just my opinion ofcourse.

Back to topic, so what you are saying is that is impossible to have a tween to update it's starting position whenever the timeline reaches it's start, when it has looped / repeated? (As we can see, it works when the timeline runs the first iteration...) 

Link to comment
Share on other sites

Just now, Torrfura said:

kill the animation and start over

Or kill the animation and start the new version right where they were when it stopped? 

 

1 minute ago, Torrfura said:

you are saying is that is impossible to have a tween to update it's starting position whenever the timeline reaches it's start, when it has looped / repeated?

AFAIK, without modification to how timelines work, yes. Timelines are meant to be set so they can be seeked through forwards and backwards. Otherwise you should be using chained tweens. 

Link to comment
Share on other sites

1 minute ago, ZachSaucier said:

Or kill the animation and start the new version right where they were when it stopped? 

 

AFAIK, without modification to how timelines work, yes. Timelines are meant to be set so they can be seeked through forwards and backwards. Otherwise you should be using chained tweens. 


Crap, the wall I hit yesterday, was indeed a wall then :) Need to figure out some other way to tackle this then... 

Many thanks for your engagement Zach, much appreciated!

Link to comment
Share on other sites

8 hours ago, Torrfura said:

if I have a timeline that has over 60 second total duration, I'd kind of kill the experience for the user if they are 45 seconds in the animation, and their mobile device happens to change orientation, to just kill the animation and start over? That's just my opinion of course.

It should actually be pretty easy - you just put your animation code into a function that you call initially as well as onresize. Store a variable for the timeline outside of that function. Record its position and re-set it on the new stuff so it all feels seamless. Pseudo code:

var tl; // timeline

function buildAnimation() {
  var time = tl ? tl.time() : 0;
  if (tl) {
    tl.kill();
  }
  tl = gsap.timeline();
  tl.to(...)
    .to(...); // do your animation
  tl.time(time); // set the playhead to match where it was
}

buildAnimation(); //kick things off

window.addEventListener("resize", buildAnimation);

 

8 hours ago, Torrfura said:

is impossible to have a tween to update it's starting position whenever the timeline reaches it's start, when it has looped / repeated?

You can invalidate() a timeline anytime - that'll force it to re-record its starting values on the very next render. Feel free to do that in an onRepeat if you'd like (or whatever). 

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