Closed andreaferretti closed 9 years ago
I designed the second form of the API for this exact reason: animating nested data structure.
But I guess it's time to inject a bit of pragmatism into this library. Maybe animating an array of element is a frequent use case. You could totally write your own helper today that does this: traverses through an array/object and tweenState
each item (is that want you want?). The only question is: is it that frequent of a use-case?
@twobit (and @jiyinyiyong. That might make your use-case less boilerplat-y).
Yes, in this particular case I could just iterate over the array, but in general the data may be nested, and a recursive version in needed. I think this is best left to the tween library itself.
I cannot speak for other people, but the examples on my demo page more or less all require nested data.
For simplicity, I just wrote a simple mixin that interpolates arbitrarily nested structures here. You can see it in use in this component.
Of course, it is very rough: it does not stack animations together nicely as does react-tween-state, and every instance will call its own requestAnimationFrame
(as opposed to keeping a single call, and updating everything that needs animation, even in separate components), but it works for me, at least temporarily.
By the way, the version I linked just calls setState
on every frame - are there any reasons why you avoid doing this?
Just to make it clear: that API I linked to already can achieve what you want. You just need to write a wrapper on top of it.
Not sure what you mean by your question? What did I avoid doing?
I agree that what I want to do is possible with the advanced form. It is just that it is inconvenient, and in any case I would end end always calling the wrapper instead of the mixin, which is why I feel it should be part of the mixin itself.
About my second question: this mixin immediately calls setState
with the final value, and then one can access the intermediate value with this.getTweeningValue(stateNameString)
. I thought the obvious approach would be to call setState
repeatedly with the intermediate values, so that one could access the state normally. This would also make it easier to switch between no animation and animation - just change the calls from setState
to tweenState
.
I think that you probably have good reasons to keep the intermediate state in a different place than this.state
. Would you mind to explain this bit?
@andreaferretti @twobit what do you think of this API?
tweenState(['path', 'to', 'collection'], [0, 1, 2], config)
First param is unrelated: it's the new path API I'm think about (akin to mori/immutable-js get/update in a nested collection). Second part is an optional array of names you want animated (mandatory if the path doesn't point to a scalar but a collection, of course).
So the above example would animate the item 0 1 and 2 inside state {path: {to: {collection: ['a', 'b', 'c']}}}
(collection
could be an object with keys 0 1 2 as well).
I could have gone with an API that detects you're animating an array and just automagically animate each element. But I feel this is too magical and less flexible than the above counterpart. Suggestions?
Clojure style makes sense, also maybe like the React update style:
tweenState({path: {to: {collection: {$tweenArray: [...]}}}})
In any case, here's a snippet of how I've been tweening arrays for the time being. Might help somebody:
arrayTween: function(a0, a1) {
var points = a0.map(function(p, i) {
return d3.interpolate(p, a1[i]);
});
return function(t) {
return t < 1 ? points.map(function(p) {return p(t);}) : a1;
};
},
I am not convinced. It is still much more cumbersome than it needs to be.
My first two priorities are, in order:
setState
, so that the two can be used interchangeablyI have written a few lines that do exactly what I need here. It can be used with essentially no changes with respect to a version without animation, as in this example - see the live demo by clicking on the red dots.
Having a smooth interpolation for the case where two animations must play together is a nice plus, but it is of lower priority for my case. If anyone is interested, I can publish the mixin
Clojure style array for path is now implemented. React-motion now implements transitioning between arbitrary nested data!
A rather common case for animation involves tweening more than one field together inside some nested data structure.
For instance, I am trying to port to React the demo for my library Paths.js. If you look - say - at the first chart, you will notice that when you click on a slice, it opens, while other slices close at the same time. This is done by using a vector of coefficients, which initially looks like
If you click on the second slice, it is animated to
[0, 1, 0, 0, 0]
. Then if you click on the fourth slice, it is animated towards[0, 0, 0, 1, 0]
, and so on.In this particular case, I could fake the effect by having a fixed number of coefficients (namely 5) in the state. But I would like to write a reusable component, hence the number of slices is not known in advance.
Right now, it seems that react-tween-state works fine for animating scalar properties. It would be nice to support the animation of nested data structures. Ractive does this and makes it a breeze to write animated components