Jump to content
Search Community

Can't set position of TweenMax.to with 0 duration

qarlo 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

Hello,

I'm trying to make an animation where at some point there's a sequence of images, one on top of each other, with each image just disappearing to show the one right below. They are absolute positioned and I'm controlling their appearance by simply tweening their opacity. Since I don't want a fade effect, I thought I would set the duration to 0. But this way it seems to ignore the position parameter I set.

 

In the pen I created, I'm expecting to see the number 1, first. And after 1 second of scrolling down, the number 2. Instead, it appears directly the number 2 and the weird thing is that if I scroll back, it actually appears the number 1.

Setting both duration to 1 make it actually to work, but I don't get what the issue is. Am I missing something about position and duration?

See the Pen QKpkaB by qarlo (@qarlo) on CodePen

Link to comment
Share on other sites

With a tween of zero duration, it happens immediately. It's the same as using the .set() method, so you will have to consider turning the immediateRender property to false or, instead of having zero, just have something super-duper quick, like "0.01" and the issue goes away.

 

More info on immediateRender.

 

  • Like 2
Link to comment
Share on other sites

With a tween of zero duration, it happens immediately. It's the same as using the .set() method, so you will have to consider turning the immediateRender property to false or, instead of having zero, just have something super-duper quick, like "0.01" and the issue goes away.

 

More info on immediateRender.

 

 

I've watched that video, but it's mentioning only the TweenMax.from method and not TweenMax.set. The same goes for the documentation.

Anyway, with TweenMax.set it seems that it just doesn't respect the position in the timeline and execute the tween at the beginning, which it seems different than the behavior with TweenMax.from. Is this how it is supposed to be? If I put a TweenMax.set in the middle of a timeline it's really weird that it gets executed before anything else. And it's true that I can use a TweenMax.to with a very small duration, but this seems a bit of an hacky workaround

Link to comment
Share on other sites

Hey,

 

Having a .to() method with a super small duration is not really a hacky workaround, it is actually expected behaviour when you think about it.

 

Going back to where I say that a .to() (or any other method, actually) tween with 0 duration is the same as a .set(). What it means is, with a 0 duration, there's really zero time, they all happen immediately. So quick we don't see it. No matter how many calls you place (within reason obviously, if you put a loop that creates a billion calls, we might start to see things), they all effectively happen at the exact same time.

 

Now into your specific case.

 

Here's a fork of your pen with a tiny modification where I believe the behaviour is what you are looking for:

 

See the Pen QKvEdP?editors=0011 by dipscom (@dipscom) on CodePen

 

The only difference being the immediateRender toggled to false. From the docs:

 

immediateRender : Boolean - Normally when you create a tween, it begins rendering on the very next frame (update cycle) unless you specify a delay. However, if you prefer to force the tween to render immediately when it is created, setimmediateRender to true. Or to prevent a from() from rendering immediately, set immediateRender to false. By default, from() tweens set immediateRender to true.

 

 

Here's the source. If you expand the Parameters box you will be able to read more.

 

What I see happens is if you don't set the immediateRender to false is that, since there is nothing taking up any time at all in your timeline, the two 0 duration .to() tweens simply move back in time all the way back to the very start of the timeline.

 

That leads into your your question about putting a .set() in the middle of a timeline. If that timeline contain tweens with some amount of time, it will not execute before anything prior to it (unless you change its position parameters.

 

See the Pen LRykXZ?editors=0010 by dipscom (@dipscom) on CodePen

 

 

:)

  • Like 1
Link to comment
Share on other sites

  • Solution

In addition to the excellent advice from Dipscom I want to add a further point of clarification.

 

Using the set() methods of TimelineLite and TimelineMax is slightly different that using TweenMax.set() inside of add().

 

In your example you are using the latter:

tl.add(TweenMax.set(obj, {props}), somePosition);

When the TweenMax.set() is called the engine says "Oh TweenMax is creating a tween with no duration it must render immediately because technically it completes as soon as it starts". At the time TweenMax.set() is called the engine has no idea that you called it inside of add() and that the resulting tween may be placed on a timeline at a time in the future. This is why it is absolutely necessary in this case to use immediateRender:false to override the default behavior.

 

when you use TimelineLite/Max .set() its different. 

tl.set(obj, {props}, somePosition);

Since the set() above is a timeline method, the engine knows that even though the resulting tweens have no duration and they should not render until scheduled based on their time in the timeline.

 

I recommend that you use the timelines' set() over nesting TweenMax.set() inside of an add().

  • Like 3
Link to comment
Share on other sites

I think you will find the resulting code shorter and more legible:

 

 
    tl.add("slide2", "+=1")
      .set('.slide-1',  {opacity: 0}, "slide2")
      .set('.slide-2',  {opacity: 1}, "slide2")
    
    .add("slide3", "+=1")
      .set('.slide-2',  {opacity: 0}, "slide3")
      .set('.slide-3',  {opacity: 1}, "slide3")

 

http://codepen.io/GreenSock/pen/xEdRzb?editors=0011

 

If you have more than 3 slides you could do this in very little code with a loop or using staggerFrom() / staggerTo()

  • Like 1
Link to comment
Share on other sites

Hey,

 

Having a .to() method with a super small duration is not really a hacky workaround, it is actually expected behaviour when you think about it.

 

Going back to where I say that a .to() (or any other method, actually) tween with 0 duration is the same as a .set(). What it means is, with a 0 duration, there's really zero time, they all happen immediately. So quick we don't see it. No matter how many calls you place (within reason obviously, if you put a loop that creates a billion calls, we might start to see things), they all effectively happen at the exact same time

 

I understand it, but the way I thought it was: it happens immediately, but in the exact position in the timeline where I set it, which means that if I add a "+=1" to it, it happens immediately, but after 1 second. 

 

In addition to the excellent advice from Dipscom I want to add a further point of clarification.

 

Using the set() methods of TimelineLite and TimelineMax is slightly different that using TweenMax.set() inside of add().

 

In your example you are using the latter:

tl.add(TweenMax.set(obj, {props}), somePosition);
When the TweenMax.set() is called the engine says "Oh TweenMax is creating a tween with no duration it must render immediately because technically it completes as soon as it starts". At the time TweenMax.set() is called the engine has no idea that you called it inside of add() and that the resulting tween may be placed on a timeline at a time in the future. This is why it is absolutely necessary in this case to use immediateRender:false to override the default behavior.

 

when you use TimelineLite/Max .set() its different. 

tl.set(obj, {props}, somePosition);
Since the set() above is a timeline method, the engine knows that even though the resulting tweens have no duration and they should not render until scheduled based on their time in the timeline.

 

I recommend that you use the timelines' set() over nesting TweenMax.set() inside of an add().

 

I guess this is what I was really missing, thanks.

 

Had to try. It would look like this:

 

 $(window).load(function(e) {
    //hide all but the first slide
    TweenLite.set(".slide:not(.slide-1)", {opacity:0});
    tl.staggerTo(".slide", 0, {opacity:1, immediateRender:false}, 1);
  });

See the Pen ALRpPG?editors=1111 by GreenSock (@GreenSock) on CodePen

 

 

Ahah, thanks, this is great!

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