react-native-svg-transformer
react-native-svg-transformer copied to clipboard
svg with animate is not useful
I have a svg file some code like:
<circle transform="translate(8 0)" cx="0" cy="16" r="10" fill="#fff"> <animate attributeName="r" values="0; 4; 0; 0" dur="1.2s" repeatCount="indefinite" begin="0" keytimes="0;0.2;0.7;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8" calcMode="spline" /> </circle>
but animate is not active
animate
does not seem to be supported by react-native-svg
:
https://github.com/react-native-community/react-native-svg#supported-elements
@jun58 I'd recommend using svgr to convert the content to react components, and then manually translate the animate element to use the react-native Animated api instead: https://facebook.github.io/react-native/docs/animated
The Easing api should have everything you need: https://facebook.github.io/react-native/docs/easing There's also https://github.com/osdnk/react-native-spline-interpolate which is for a unrelated problem, but also utilizes splines, but rather generates them to fit data, than just get them as input and calculate the output. Essentially the same logic could be used, but it's possible to implement more efficiently using the primitives from the Easing api.
Couldn't help myself 😄 https://snack.expo.io/@msand/animated-svg-with-bezier-spline-calcmode
import * as React from 'react';
import { Animated, Easing } from 'react-native';
import { Svg, Circle } from 'react-native-svg';
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
/*
<circle cx="16" cy="16" r="16">
<animate
attributeName="r"
values="0; 4; 0; 0"
dur="1.2s"
repeatCount="indefinite"
begin="0"
keytimes="0;0.2;0.7;1"
keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8"
calcMode="spline" />
</circle>
*/
const values = [0, 4, 0, 0];
const dur = 1.2 * 1000;
const keyTimes = [0, 0.2, 0.7, 1];
const keySplines = [
[0.2, 0.2, 0.4, 0.8],
[0.2, 0.6, 0.4, 0.8],
[0.2, 0.6, 0.4, 0.8],
];
export default () => {
const t = new Animated.Value(keyTimes[0]);
const splines = keySplines.map((spline, i) => {
const [x1, y1, x2, y2] = spline;
const fromValue = keyTimes[i];
const toValue = keyTimes[i + 1];
return Animated.timing(t, {
toValue,
duration: dur * (toValue - fromValue),
easing: Easing.bezier(x1, y1, x2, y2),
useNativeDriver: true,
});
});
Animated.loop(Animated.sequence(splines)).start();
return (
<Svg width="100%" height="100%" viewBox="0 0 32 32">
<AnimatedCircle
cx="16"
cy="16"
r={t.interpolate({
inputRange: keyTimes,
outputRange: values,
})}
/>
</Svg>
);
};
A bit refactored to make it more reusable:
import * as React from 'react';
import { Animated, Easing } from 'react-native';
import { Svg, Circle } from 'react-native-svg';
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
function animateSpline({
values,
dur,
repeatCount,
begin,
keyTimes,
keySplines,
}) {
const duration = dur * 1000;
const t = new Animated.Value(keyTimes[0]);
const splines = keySplines.map((spline, i) => {
const [x1, y1, x2, y2] = spline;
const fromValue = keyTimes[i];
const toValue = keyTimes[i + 1];
return Animated.timing(t, {
toValue,
delay: i == 0 ? begin : 0,
duration: duration * (toValue - fromValue),
easing: Easing.bezier(x1, y1, x2, y2),
useNativeDriver: true,
});
});
const iterations = repeatCount === 'indefinite' ? -1 : +repeatCount;
const animation = Animated.loop(Animated.sequence(splines), { iterations });
const value = t.interpolate({
inputRange: keyTimes,
outputRange: values,
});
return { t, animation, value };
}
export default () => {
/*
<circle cx="16" cy="16" r="16">
<animate
attributeName="r"
values="0; 4; 0; 0"
dur="1.2s"
repeatCount="indefinite"
begin="0"
keytimes="0;0.2;0.7;1"
keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8"
calcMode="spline" />
</circle>
*/
const { animation, value } = animateSpline({
values: [0, 4, 0, 0],
dur: 1.2,
repeatCount: 'indefinite',
begin: 0,
keyTimes: [0, 0.2, 0.7, 1],
keySplines: [
[0.2, 0.2, 0.4, 0.8],
[0.2, 0.6, 0.4, 0.8],
[0.2, 0.6, 0.4, 0.8],
],
});
animation.start();
return (
<Svg width="100%" height="100%" viewBox="0 0 32 32">
<AnimatedCircle cx="16" cy="16" r={value} />
</Svg>
);
};