Jump to content
GreenSock

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

GSAP/VueJS Timeline issue when tracked in Vue's data

Recommended Posts

Hello,

 

I came around a strange behavior  when integrating GSAP/Timeline with VueJS. Needed to grab a reference to the timeline to be able to reverse play it later (and shallow watch for changes), used Vue's data to store the instance. This of course makes Vue add the reactivity to the object. It was working without any issues, now I found this strange behaviour. Not sure if it's some kind of obscure issue (with GSAP or VueJS) or it's just that generally GSAP objects (instances) shouldn't be added to Vue's data object?

 

The codepen shows the issue (and "workarounds"), in short, adding a new TimelineMax to Vue's data while a Tween is progressing makes a TimelineMax.fromTo behave something like a "to" only (startAt value is used for the final state). The same setup when the TimelineMax object is first assigned to Vue's data before or after the Tween makes everything work as expected.

 

I sort of worked around the issue for now, wondering though where the core issue is?

 

Thanks!

Petr

 

 

See the Pen XvzGbe by petredm (@petredm) on CodePen

Link to comment
Share on other sites

I'm not at all familiar with Vue or what it may be doing to tinker with the GSAP objects, but you mentioned a "shallow" watch for changes and I wonder it something is happening with Vue copying things but only in a shallow way, so that the vars.startAt doesn't actually get properly copied over (deeply)? I'm totally guessing. There isn't any "magic" going on in GSAP - it's relatively straightforward, so any weirdness here sounds like it'd be Vue-related (and again, I'm totally unfamiliar with that). I wish I had a better answer for you. 

Link to comment
Share on other sites

Vue's data system uses setters to detect changes, which is being triggered with this.timeline = new TimelineMax() in your mounted section because it's a different type than null. 

 

And you don't need reactivity for a timeline. Vue can't detect when you make changes to a timeline. 

  • Like 4
Link to comment
Share on other sites

Also, you should probably use $refs instead of selectors like ". moving-rect" and ".circle". Elements may be swapped out during rerenders e.g. when Vue detects a change. 

  • Like 1
Link to comment
Share on other sites

Hey, thanks for the replies (and for GSAP itself too!)

 

Yep, sure, Vue, agree on everything, it was a sort of minimal example replicating the issue and unfortunately seems to steered the original question :)  

 

I was just wondering if maybe anyone had any insight from GSAP's side of things, what interaction might be happening between the Tween and the Timeline since separated (by time or code) there are no issues observed with no changes in the Vue-related code that fails once the events are happening concurrently. (Only when the Tween is running it somehow interacts with the assignment of the Timeline object, as the codepen shows, otherwise no issues observed)

 

I'll likely look into the issue further just for the fun of it, but the workaround of assigning a placeholder "new TimelineMax()" to the Vue's data at start and then replacing it with the real deal is working without any issues for my case, and at worst, I won't be using Vue's data for these objects, no problem. This is likely also a good clue to start the investigation I guess!

 

Thanks again, will update you if I find out anything!

  • Like 1
Link to comment
Share on other sites

Wasn't try to steer the original question. My main point is that your data should be simple. Something that can be converted into json. 

 

And the more I looked into this, it appears to only happen with attributes, but I don't know why. I checked, and the startAt and end values are correct for the animation.

Link to comment
Share on other sites

That's a good catch! It is indeed failing only with attributes (attr plugin). Css works as expected in all cases AFAICT.

 

On my way of stripping the example code to a bare minimum, I also found out that it depends on how/what is included from GSAP. When included like this, the issue comes up:

 

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>

 

When included this way, all works as expected without further changes:

 

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenLite.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/plugins/AttrPlugin.min.js"></script>

 

Related pen:

 

See the Pen xvpmyx by petredm (@petredm) on CodePen

 

 

Link to comment
Share on other sites

Very interesting - it definitely seems Vue-related. If I remove Vue from the equation, it all works as expected. From what I can tell, the issue gets introduced as soon as you load CSSPlugin which enables the "autoCSS" feature, wrapping all the non-protected properties into a css:{} object in the vars (protected ones are things like onComplete, overwrite, etc.). If you set autoCSS:false on your first tween, it seems to resolve things too. I wonder if Vue is somehow swapping things out from underneath GSAP. Very odd indeed. 

  • Like 1
Link to comment
Share on other sites

Don't know about swapping things out. What I do know is that when you change something in the data object, Vue runs those changes asynchronously. It uses a Promise to make that change in the next event loop tick. Using a fromTo(), from(), or set() tween might be causing problems because those changes are supposed to be synchronous.

 

But again, I think the main issue here is that timelines don't belong in the data object. Just like in React, Timelines don't belong in the state object.

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