2

Is there a simple way to animate the Polygon element from the react-native-svg library? I need to animate his shape by animating the points. I found few examples on how to animate Path element or Circle, but couldn't find anything regarding the Polygon. Thanks in advance.

cinemanja
  • 481
  • 6
  • 19

2 Answers2

5

Bit late to the party, but I've found a solution if you're still interested. It's not exactly 'simple', but it works. There's a library called React Native Reanimated, and it extends the functionality of Animated components substantially. Here's what I was able to achieve:

enter image description here

The reason animating Polygons isn't available out of the box is because the standard Animated API only handles simple values, namely individual numbers. The Polygon component in react-native-svg takes props of points, which is an array of each of the points, themselves array of x and y. For example:

<Polygon
        strokeWidth={1}
        stroke={strokeColour}
        fill={fillColour}
        fillOpacity={1}
        points={[[firstPointX, firstPointY],[secondPointX, secondPointY]}
 />

React Native Reanimated allows you to animate even complex data types. In this case, there is useSharedValue, which functions almost identical to new Animated.value(), and a function called useAnimatedProps, where you can create your points (or whatever else you want to animate) and pass them to the component.

     // import from the library 
import Animated, {
      useSharedValue,
      useAnimatedProps,
    } from 'react-native-reanimated';

 // creates the animated component 
 const AnimatedPolygon = Animated.createAnimatedComponent(Polygon);

const animatedPointsValues = [
  {x: useSharedValue(firstXValue), y: useSharedValue(firstYValue)},
  {x: useSharedValue(secondXValue), y: useSharedValue(secondYValue)},
];

const animatedProps = useAnimatedProps(() => ({
      points: data.map((_, i) => {
        return [
          animatedPointValues[i].x.value,
          animatedPointValues[i].y.value,
        ];
      }),
    })),

Then in your render/return:

  <AnimatedPolygon
  strokeWidth={1}
        stroke={strokeColour}
        fill={fillColour}
        fillOpacity={1}
        animatedProps={animatedProps}
      />

Then whenever you update one of those shared values, the component will animate.

I'd recommend reading their docs and becoming familiar with the library, as it will open up a whole world of possibilities:

https://docs.swmansion.com/react-native-reanimated/

Also, the animations are handled in the native UI thread, and easily hit 60fps, yet you can write them in JS.

Good luck!

FlyingKitlets
  • 324
  • 3
  • 7
  • 1
    thank you. To those of you looking at this solution, remember to add "import Animated from react-native-reanimated" and remove the" import Animated from react-native"!! – maxgalbu Sep 13 '21 at 18:39
  • 1
    also, it looks like react-native-gesture-handler doesn't work well with react-native-svg. I reverted to use PanResponder for drag-n-dropping stuff with react-native-svg, and everything works – maxgalbu Sep 13 '21 at 18:42
0

react-native-reanimated also supports flat arrays for the Polygon points prop, so we can simplify the animation setup even more.

Full example which will animate the react-native-svg's Polygon when the points prop changes looks like this:

import React, { useEffect } from 'react'
import Animated, { useAnimatedProps, useSharedValue, withTiming } from 'react-native-reanimated'
import { Polygon } from 'react-native-svg'

interface Props {
    points: number[]
}

const AnimatedPolygonInternal = Animated.createAnimatedComponent(Polygon)

export const AnimatedPolygon: React.FC<Props> = ({ points }: Props) => {
    const sharedPoints = useSharedValue(points)

    useEffect(() => {
        sharedPoints.value = withTiming(points)
    }, [points, sharedPoints])

    const animatedProps = useAnimatedProps(() => ({
        points: sharedPoints.value,
    }))

    return <AnimatedPolygonInternal fill="lime" animatedProps={animatedProps} />
}

k2rks
  • 181
  • 8