More paths, more React Art, and more animations. What else have you come to expect of me. A question was posed on Reactiflux about morphing one path to another with React Art. Of course I took this as a “challenge”.
I say “challenge” because it took all of a few moments to check out the ART repo and see the Morph Demo which links to
art/morph/path. That’s of course what this all about, morphing a path. Sebastian Markbåge has thought of everything.
On Reactiflux the demo of morphing batman logos was proposed and linked to. You can read the orignal source with the linked SVG at http://tavmjong.free.fr/blog/?p=741.
What are we building
We’re going to take a path. In our case all of the Batman logos, and transform each SVG path into the next until we’re all out. Then we’re going to transform it into a square.
If you’re unsure how to get React Art running on React Native checkout my previous blog post here Getting react-art running on react-native.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
We bring in the usuals, but also require
art/morph/path which will do our magic morphing.
The SVG Paths
Thanks to the blog post I just parsed out the SVG paths, and tossed them into an array. For the sake of parsing, I map over each and convert them into native React Art paths.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Then we throw a square on the end.
There is nothing special here. We just add a
Surface the full width/height of the phone and instead of a string SVG path we give it the transition which just happens to be a
MorphPath, which extends from
Path which React Art knows what to do with. Fancy.
1 2 3 4 5 6 7 8 9
The person that created the SVGs made the central point the start of the SVG so we just set it back -100 to center it-ish. I don’t know. We fill it with black. Batman likes black.
1 2 3 4 5 6 7 8 9 10 11
We start the intial render with a
Morph.Tween of the first and second Batman logos. We do a little setup in
componentWillMount to say we’re currently animating to the second logo (it’s a 1 since we have 0 based array indexes).
Then once the component is mounted we kick off the animation with our
1 2 3 4 5 6 7 8 9 10 11 12
Our animate call takes a start, and a callback for when the animation is complete. Thanks to React Native with get a polyfilled
requestAnimationFrame. If we don’t have a start, then we set it to the timestamp that
requestAnimationFrame provides us. The start allows us to compute how far along in the animation we are.
delta is the current
timestamp which is some amount of time in the future, minus the
/1000 is the amount of time each animation will take. So each morph will take
1000ms to complete.
If our change is greater than 1 then we know our animation is complete and trigger are callback, and also return so we don’t keep animating a complete animation.
We tween our transition with the new
delta progress, we trigger a
setState to cause our UI to re-render, then we call ourself (aka
this.animate), with our
start and our
callback so we can trigger the next animation frame.
A lot of this is just boilerplate logic you can see here https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame.
Animate it Again
1 2 3 4 5 6 7 8
Okay so we need a little logic around keeping track of which logo is transitioning to which other shape. If this function is called it means an animation has completed and we need to trigger the next one.
We add one to the current to setup that we’re about to animate to the next logo path.
First we check if it’s equal to or somehow greater than the amount of logos we have. If it is we stop animating and just leave the current render as the last shape in the array.
If not we trigger a setState to adjust the
this.state.transition (which we pass into the
Shape). This just gets set to the
this._current - 1 logo and then the
this._current which is going to be the next logo. Because currently on screen is
this._current - 1 and we do a
setState, nothing will flash/jump since you’re rendering the same exact shape again.
setState also takes a success callback, meaning the UI has updated, we then kick off the animation. TahDah. Batman Animating.
More than Batman Logos?
Of course. You can animate from anything to anything with
Morph.Tween. See I animated Batman into a square at the end. But really you can do any sort of path to another path. If you’re animating a complex path to another compelx path they not animate elegantly but they’ll animate.
Clean it up
setState is hacky for animations, you could wrap this up just like Animated to make it all nice and performant with
setNativeProps but you can take care of that yourself. Vjeux shows how to do that in his React Rally talk, seriously watch it https://www.youtube.com/watch?v=xtqUJVqpKNo. Also slides here https://speakerdeck.com/vjeux/react-rally-animated-react-performance-toolbox
Okay, so now you know how to morph paths. Go make cool animated transitions on React Native now!
Live Demo: https://rnplay.org/apps/9txbFQ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105