Jump to content
Search Community

`from` not returning to original value (only first object obeys)

MLM test
Moderator Tag

Go to solution Solved by Carl,

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

When using `TimelineMax.from`, only the first object returns to the original `TimelineMax.set` value.

 

All objects obey as I expect, when all of the `set`'s are done first, then `from`'s.

 

I understand the timeline is doing the following respectively. I know they are different but in either demo, I expect the all of the bars to be at a `y` value of `20px` at the end.

 

 

tl
	set
	from
	set
	from
	set
	from

See the Pen waPeOX by anon (@anon) on CodePen

tl
	set
	set
	set
	from
	from
	from

See the Pen aOVwXv by anon (@anon) on CodePen

Link to comment
Share on other sites

Hi,

 

Basically you have two instances battling for the immediate control of the element. From and set instances render the new values upon creation. Using immediateRender: false solves it:

tl
  .set(
    logoPieceNode,
    {
      x: `${20 * pieceIndex}px`,
      y: `20px`
    }
  )
		  .from(
			    logoPieceNode,
		    	0.25,
			    {
      				y: '50px', immediateRender:false
			    }
		  );
});

Rodrigo.

  • Like 3
Link to comment
Share on other sites

@Rodrigo Thank you for the reply. It wasn't quite clear after reading your reply although I think I understand.

 

`immediateRender` does solve the problem.

 

Here is my understanding: `set` gets run in timeline time, while the `from` sets it's state immediately. The `from` runs immediately (I assume at a timeline.start/timeline.restart) and remembers whatever current value, which is not the `set` value because that will run later down the road.

 

But I don't understand why the first one works as expected?

 

 

 

NOTE: By default, immediateRender is true in from() tweens, meaning that they immediately render their starting state regardless of any delay that is specified. You can override this behavior by passing immediateRender:false in the vars parameter so that it will wait to render until the tween actually begins.

 

Source: TimelineMax.from docs
Link to comment
Share on other sites

  • Solution

Just to expound on Rodrigos accurate solution, one of the trickiest aspects of the entire platform is how the immediateRender property works when multiple from() tweens are trying to control the same properties of the same objects. In your case a from() and set() were scheduled at the same time causing a similar type of conflict.

 

In simple terms, from() tweens always render their starting values immediately. Imagine you want to animate 3 objects fading in from opacity:0 to opacity:1 one after the next each with a duration of 1 second. 

 

TweenLite.from(obj1, 1, {opacity:0})
TweenLite.from(obj2, 1, {opacity:0, delay:1})
TweenLite.from(obj3, 1, {opacity:0, delay:2})

Chances are you would want each item to have opacity:0 set immediately so that they would all be hidden from the start. So even though obj3 may not start animating until its 2-second delay transpires, it should have opacity:0 set immediately. That's why from() tweens have immediateRender:true by default.

 

See this demo and experiment with toggling the immediateRender value: http://codepen.io/GreenSock/pen/oXoejW?editors=001

 

However if you try to do multiple from()-based animations on the same properties of the same element, immediateRender:true can give undesired results.

 

consider you want obj1 to fade in from opacity:0 twice

TweenLite.from(obj1, 1, {opacitty:0})
TweenLite.from(obj1, 1, {opacity:0, delay:1});

If you run that code, you will only see obj1 fade in once.

The reason is because the first tween immediately sets the opacity to 0, which means that when the second tween wants to record its end values (which are the current values) opacity is already 0. So its trying to tween from 0 to 0. 

 

The solution is to tell the second tween to wait until it is scheduled to run (after 1 second delay, which is after the first tween has run and has set opacity or obj1 to 1) by using immediateRender:false.

 

See it in action here:

 

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

 

I know that's a lot to chew on, hopefully some of it makes sense.

 

Oh, and it would help if you would resist using Babel in your demos. Plain JS is much easier for us to read. Thanks.

  • Like 3
Link to comment
Share on other sites

@Carl Thanks for the reply, I think I understand the situation now. btw, we replied at the same time in case you missed that message.

 

When exactly is the `from` state applied and the value remembered to return to (`restart`, `start`, non-paused timeline creation chained call)?

 

In my actual animation, it seems to still be borked, even when doing all the `set`'ing first(synchronously) and separate. But `immediateRender` does solve it.

 

My theory of operation in the demo: The first object works because the timeline is not paused when created, then the `set` is called and starts running, then `from` is called after in the chain and works as expected. But then first item takes longer to finish than the synchonous `forEach` so the rest of the items `from`'s get called before the `set` has a chance to go.

 

 

Sorry, I am using Babel for some ES6 features such as template strings, let(although they work in modern browsers anyway) but I will refrain from using in future demos.

Link to comment
Share on other sites

You have great questions and it seems like you are correct in understanding most of what is happening. This is definitely tricky territory. 

 

Here are just a few statements that should hopefully help you put it all together

 

  1. from() tweens will render their starting values (and record their ending values) as soon as they are created (thus immediateRender:true, by default).
  2. a set() that has a non-zero startTime() in a timeline will not render or record anything until the playhead reaches its startTime(). 
  3. a set() that has a startTime(0) will record and render its values immediately as it has no duration and it starts at a time of 0. Technically it completes as soon as it is created.

I think point 3 explains why in your first demo, the first set() worked. It got its job done immediately -- even more immediately than the first from() tween which was scheduled at the same time. Again, both scheduled to run at time(0) but the set was created first so it got to get to work first.

 

The from() tweens on the nodes 2 and 3 also immediately rendered properly, but the sets() for 2 and 3 did not do anything until they were scheduled to, which ended up being too late, since the from() tweens already "locked-in" their starting values.

 

I forked your first demo and forced the first set() and from() to be placed at non-zero start times. They now behave exactly like the others.

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

 

FWIW I confused myself a few times in trying to figure out how to explain this. Hopefully it makes better sense now.

 

Thx for understanding about the Babel. I really appreciate that you made demos that clearly illustrated the issues.

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