Jump to content
GreenSock

fastraxpos

Issue With Reverting Timeline -> Immediate Render

Recommended Posts

Hello,

 

We're faced with some strange issues, and have been for a long while.

 

We are trying to implement entrance effects with our software, so using immediateRender = true we can start our animations off screen, and bring them onto the screen using from() animations. For exit, we use to() animations.

 

Our animations consist of rotation in, sliding in from X/Y positions, etc.

 

I've made two sample videos, but making a codepen with this issue is difficult to replicate and we have lots of code involved in making this work.

 

I figured maybe I could get someone's help in figuring this out, by looking at the videos below. If not, I can try to replicate in code pen.

 

Issues: With rotation on 2 layer elements in our software, we can repeat the animation infinitely with no issues. I added parseTransform = true to all of our tweens so that they parse existing CSS. If we animate the rotated elements, and restart before or after the tween starts, it has no issues. I can even successfully click the restart animation to rebuild as many times as I'd like, as fast as I want and it has absolutely no issues.

 

In the second case, when elements have no prior transform they are breaking or not appearing on screen.

 

We've tried using clearProps 'all' or specifically 'transform' and even X, Y by themselves, but these end up breaking our already rotated elements.

 

So we found the following articles which led us in the direction of parseTransform property, which did work when using rotation perfectly as seen in the video (With Previous Rotation)

 

https://greensock.com/forums/topic/10735-transform-scale-is-broken-when-invoked-twice/

https://greensock.com/docs/#/HTML5/Plugins/CSSPlugin/

 

The results are below. We want this to work similar to the first video, but I cannot for the life of me figure it out.

 

Note: I kill timeline, clear timeline on each restart of the timeline, in case any properties such as timing sliders, or animation names have changed. I also have a function resetTimelineElements which loops through all elements from previous animation, and I stored the cssText, transform properties of the elements, and re-assigns them back to the elements.

 

VIDEOS

-----------------------------

With Previous Rotation

https://drive.google.com/file/d/0B1t3kDzocOAUSGZUM3FQS1doSXM/view

Without Previous Rotation

https://drive.google.com/file/d/0B1t3kDzocOAUZ0FoSkM2dktCdEk/view

 

If needed, I can do a video call with someone to go over the code usage, etc.

 

Thanks

Link to comment
Share on other sites

Nothing is immediately obvious, but it'd be SUPER helpful if you could provide a reduced test case in codepen or something because then we could see the issue in context. The process of creating that codepen might also help you identify if it's something in your code that's interfering. If there are any bugs in GSAP, we'd definitely want to make sure they're fixed ASAP. Oh, and what version of GSAP are you using? I'd of course recommend using the latest. 

Link to comment
Share on other sites

I'll spend some time creating a code pen for this... Give me a bit to do this.

 

Also, I was using 1.19.0 with the issue, and I just tested after updating to 1.19.1 and still the same result.

Link to comment
Share on other sites

I created 2 code pen demos, one matching each video and the issue we're facing.

 

In the first one below, this symbolizes what we have with rotated elements, using parseTransform. I'm able to repeat the animation multiple times, and if I click play again before, during or after the tween is being animated, it works and replays properly;

 

See the Pen mmrjVw?editors=0011 by jbevan2007 (@jbevan2007) on CodePen

- Relates to the working, rotated video example
 

If I look at this example, we get the exact opposite. I have 2 elements with no transforms, and not rotated by default. I play this, and it works. However I have to let the animation fully complete before I can replay it. If I stop it before the tween starts (when it's outside box and hidden) or during the animation, the elements do not show again. I've tried with a basic matrix like this : matrix(1, 0, 0, 1, 0, 0) as well, which is a non-rotated matrix

 

See the Pen wdzxMm?editors=1001 by jbevan2007 (@jbevan2007) on CodePen

- Relates to the non-working, non-rotated video example

 

You can see that pressing the first example multiple times (even very rapid) still repeats the animation properly, while the second example does not have this same effect, which is our desired effect.

Link to comment
Share on other sites

Note: Our goal here is to repeat the animation consistently, in all cases. We use this as a preview of animation which will show in store TV advertisements. So each time we rotate our slideshow image or video, we will need to "reset" this animation so on next iteration of loop it plays properly, in the same fashion.

 

This is more importantly used in our preview screen (as video examples show) so that the user can modify + adjust settings each time they need to, and the preview will play back their changes.

Link to comment
Share on other sites

Hmm...kinda tough to dig through the 200+ lines, but it looks like the problem is likely related to the logic in your resetTimelineElements() method, where there's a bunch of conditional logic, and it fails at this point:

if(processedLayer.styles && processedLayer.styles.cssText)

So it doesn't run anything to clear out the cached transforms (when it actually should). 

 

Let me take a step back and explain an important concept with regard to transforms in GSAP...

 

As I'm sure you know, GSAP is highly tuned for performance. Parsing existing CSS transforms is an expensive process (and often undesirable). The browser always reports them as a matrix() or matrix3d() which requires extracting all the components (scaleX, scaleY, rotation, x, y, skew, etc.). Once you rotate beyond 360 degrees, matrix math breaks down and you basically lose that data (720deg becomes 0deg, for example). As a convenience, GSAP does the parsing for you but then we cache the extracted components in a _gsTransform object attached to the element itself. That becomes the source of truth for transforms, and it's much faster to read those values rather than extracting things from a CSS matrix()/matrix3d() string. 

 

So I noticed you're setting cssText and the "transform" style to try to clear out values, but that doesn't get rid of what's in the _gsTransform. By default, GSAP will look for that and if it finds it, read things quickly from there (which was happening in your demo). 

 

Technically, you could get rid of the data with TweenLite.set(element, {clearProps:"transform"}) but in most cases, I really wouldn't recommend that. We always recommend setting your transforms directly through GSAP so that it can not only be faster, but also retain perfect accuracy regardless of how far your rotate something. Much cleaner. 

 

If your goal is to reset something, you have several choices:

  1. Just seek(0) your tween that animated the styles away from the starting values. In other words, just rewind it (and kill() it if you want). tween.seek(0).kill(). Done. 
  2. Or if you've got a bunch of things that might have messed with the transform-related values, you could manually reset them like TweenLite.set(element, {x:0, y:0, rotation:0, scale:1, skewX:0, skewY:0}); (don't forget the 3D properties too if you're animating those). That way, you'll keep the benefit of the cached values (speed and accuracy). 

And to be clear, the reason you didn't see the red/blue rectangles coming back if you clicked quickly was because you were using from() tweens which use the CURRENT value as the destination, thus if you clicked it while it was way off the screen, it'll end up tweening there. Be careful about using from() tweens as they can catch people in situations like this. It's not a flaw at all in GSAP - it's just a logic thing. 

 

Does that help? 

  • Like 3
Link to comment
Share on other sites

Just noticed your PM. Jack covered a lot, but I was going to say that using .fromTo() instead of .from() would probably fix your playback issues. 

Link to comment
Share on other sites

In our case, fromTo won't really work because we use from() to bring us back to the original location. So we pass an X or Y outside our canvas (center white area) and it transitions back to it's original position. If we were to change it, we'd need to pass in the starting location, and the current location for each of our elements. Also we'd need to pass our rotation as well.

 

I actually used some of your suggestions, removing the need for parseTransform = true. This now works, with the changes below.

 

In our resetTimelineElements function, I now simply use something like below:

var layerObj = FTXCanvas.getLayerById(layerId);

TweenLite.set(processedLayer.element, {
   x: 0,
   y: 0,
   rotation: layerObj.rotation.angle || 0,
   scale: 1,
   skewX: 0,
   skewY: 0,
   opacity: layerObj.opacity || 1
});

We store the entire layer's settings including X, Y, opacity, rotation (angles and radians) and many other attributes so we can easily obtain the rotation and opacity.

 

We use left/top for positioning, so resetting x/y to 0 is fine as well.

 

This works well, and we run it prior to running the new processed animation timeline, without changing the order (shown below)

 

- reset elements

- kill timeline

- clear timeline

Link to comment
Share on other sites

Yeah, I know it would require a little work, but aren't these essentially the "to" values?

TweenLite.set(processedLayer.element, {
   x: 0,
   y: 0,
   rotation: layerObj.rotation.angle || 0,
   scale: 1,
   skewX: 0,
   skewY: 0,
   opacity: layerObj.opacity || 1
});
  • Like 2
Link to comment
Share on other sites

Yes I could do this, but I've gotten it to work with a from() animation.

 

We have many things involved in our structure, for example we store the zoom states to have a certain X, Y factored by our zoom level, and our original layer objects contain 100% zoom level based values.

 

There is too much involved here for this to be using a fromTo(), but not saying it couldn't work.

 

I've made a mock codepen with an original rotation, original opacity using data-orig-rotation, data-orig-opacity tags on the element, as we don't have our framework baked into the code pen.

 

Thank you for your help and guidance in getting this to work. At least practice makes perfect, so I'm getting more and more fluent in the library after posting all these different posts :)

 

See the Pen dWOYpp?editors=0011 by jbevan2007 (@jbevan2007) on CodePen

 

This is working well in our codepen, with the set() function called when we need to reset the elements.

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