Closed sdras closed 7 years ago
For instance, you can see that if you change the transition from 1 second to 0.5 seconds, it gets a little jumpy
I must be something missing. It's animating fine when changing it 0.5s
About the docs: @chrisvfritz wrote some of those examples, so he may have some insights to share Maybe the introduction of scoped slots can make up for better reusable transition state components I find the examples very nice, going from an easy version to an app-ready-reusable version of it. But It'd be nice to know what makes them feel not well broken-down in your opinion. There's always room for improvement 🙂
@sdras Thanks for the feedback! I'm certainly the one to blame for any lack of clarity in those examples. 😅 As a sidenote, you're one of my animation heroes and I really enjoy how you write about these topics, so I take your concerns to heart. If even you are encountering issues, I think there's definitely room for improvement - whether it's in the documentation, the API, or both.
I'll have some time tomorrow to take a look at your CodePen and find what might be going wrong, offer any suggestions, and probably ask some more questions. 🙂
@chrisvfritz your examples are awesome! I'm a huge fan of your work in the guides. I'd love to hear your thoughts on this- any help is appreciated and if you want to throw ideas around for docs improvement, I'm more than happy to offer some of my time if will help others. Thank you!
Just an update - I did confirm the strange behavior you were seeing. 🤔 I'm investigating now.
I'm not extremely familiar with how GSAP works under the hood, but it looks like it's out of sync with Vue's render cycle in this case. To avoid unnecessary re-renders, Vue waits for all synchronous state updates to finish. In this case, it seems to often be interpreting GSAP's use of requestAnimationFrame
with a series of synchronous updates, so it's waiting for them to finish before rendering again.
This seemed to work as a temporary fix:
TweenMax.ticker.useRAF(false)
I think that forces GSAP to fall back to setTimeout
. Before thinking through next steps though, can you confirm whether that does indeed solve the issues you noticed?
Apologies on the radio silence on my end- that does indeed fix it, nice work! That's interesting about the way that it handles the renderings, really smart. Makes sense. What do you think about offering an API hook for startingPoint and endingPoint? If that's not the direction you're interested in taking, totally understandable and I'll just close out the issue. Thanks for your time!
@sdras For an improved state transitions API, I'm not even sure we'd need to specify startingPoint
and endingPoint
, since we already track old/new values in the reactivity system. I'm imagining something like a transition
option, which would be a sort of hybrid between watch
and computed
.
For example, to create a transitioning version of a total
data property, we could include options like this:
data: function () {
return {
total: 0
}
},
transition: {
total: {
as: 'transitioningTotal',
duration: 300
}
}
This would create a new transitioningTotal
property, which would always contain the value of total
, though would transition from the old value to the new value over 300 milliseconds.
To avoid bloat in Vue core however, this could probably only ever work with:
We could also use a default timing function - probably the default ease
used by CSS. Then people could provide their own timing functions if they wanted, with a timing
or easing
option:
transition: {
total: {
as: 'transitioningTotal',
duration: 300,
// ease-in-out-quad
timing: function (t) {
return t < 0.5
? 2 * t * t
: -1 + (4 - 2 * t) * t
}
}
}
I believe a delay
option would also be fairly simple to implement. For more complex values, like animating SVG paths, these transitioning properties containing raw numbers could then be used in other computed properties. For example, in the example of an array of objects of x and y coordinates, you could pull parts of D3 into a component:
import { line as d3Line, curveBundle } from 'd3-shape'
const drawCurvedPath = d3Line()
.x(d => d.x)
.y(d => d.y)
.curve(curveBundle.beta(0.8))
And then use the transitioning coordinates to also animate changes in the path:
computed: {
animatedPath () {
return drawCurvedPath(this.transitioningCoordinates)
}
}
How would that kind of thing sound to you? Would it sufficiently improve the DX in the situations you're thinking of?
Wow, that would be amazing!
I agree that keeping an eye on bloat is really essential, and that interpolating numbers would really serve most use-cases. I also love that you're already thinking about pairing with d3- that also would be a pretty common use-case for this kind of animation.
This is really exciting, thank you so much. You all rock. 🤘🏼
Cool! Thank you for starting the discussion. 🙂 I think as a next step then, I'll try to create a proof-of-concept plugin that adds this API. I'm not sure when exactly I'll be able to carve out the time, but I'll keep this thread updated with my progress.
Sounds great, it's really appreciated, and take your time.
@chrisvfritz I forgot to tell you, I started a poc similar to https://github.com/chenglou/react-motion that allows to transition between values by using springs. The api looks something like this:
<Motion :to="someValue" :spring="springConf">
<template scope="val">
<p>{{vall}} is changing smoothly</p>
</template>
</Motion>
to
could be an object of values too
You can change someValue
as usual but val
will adapt smoothly. It won't allow you to control easing, though.
This doesn't change anything about your plugin idea, but I wanted to share in case it may inspire you 🙂
@posva That's great! I'm a big fan of react-motion, so I'm really glad to see Vue getting a similar project. 😄
Not entirely sure what's actionable here - imo pure state-based transitions is really about manipulating state variables in JavaScript and not a responsibility of Vue core. Easing curves, spring animations etc. should all be doable in userland and thus should be done in userland.
I completely forgot about posting the project back here: https://github.com/posva/vue-motion
Vue.js version
2.1.1
Reproduction Link
http://codepen.io/sdras/pen/OWZRZL
Suggestions
First of all, thank you for Vue! I'm so grateful for this framework, it's so elegant.
In the CodePen above, I'm using a watcher to transition state with GSAP. I've tried to comment the code well so it's clear what is going on. I think that though transitioning state is doable, it's a little bit clunky. For instance, you can see that if you change the transition from 1 second to 0.5 seconds, it gets a little jumpy. (Totally open to suggestions if you have ideas on how to make this better that I haven't explored.)
Even the examples in the guide, though interesting, aren't well broken-down and I think it's a barrier to entry for people. Improving the documentation there might make things more clear.
This might be a broad request, but it seems like the common pattern is the two parameters such as startingPoint and endingPoint or some variation, and then a little bit of heavy-lifting to actually tie that back to state in a way where it's not overwriting itself. Is there a way to expose something in the API that makes that binding a little more intuitive? Any feedback appreciated, even if you think it's out of scope for now and want to close this out. Thank you for your hard work.