Animate Polygon in SVG Over a Predefined Path

While working on the True Sparrow and Slackmin we were supposed to create different SVG Shapes to follow a predefined path. After looking at different options to achieve it we found that greensock was our best option to go with. It is fast, robust and compatible with most of the js frameworks, html and css. It is also compatible with most of the modern browsers as well.

In order to achieve our animations, the first task was generating SVG. We tried generating SVG using Figma but the problem was that Figma generated SVG code was too lengthy and the animation paths were not smooth enough. So, we generated our own SVG paths, polygons and circles.

Let's take an example of generating SVG containing a path for a circle and a polygon.


<svg width="100%" height="100%" viewBox="0 0 1028 580" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path class="path" stroke="#FF522A" d="M 100 200 Q 200 400 300 200 Q 400 0 500 200 Q 400 300 500 400" />
  <circle class="circle" cx="238" cy="481" r="8.5" fill="#FF522A" stroke="#FFD8E6" stroke-width="3"/>
  <path class="triangle" d="M 1133 860 L 1133 880 L 1143 870" fill="#FF522A"/>
</svg>

There are three elements in above SVG:

  • Circle: Shape that will animate on the path.
  • Triangle: Polygon that will animate on the path.
  • Path: Which the elements would follow. You can also create your own using, M - Starting coordinates, L  - Intermediate coordinates, Q - Intermediate coordinates with one side curve, C - Intermediate coordinates with two side curve.

Once our SVG is ready, the next step is to animate the shapes on the predefined path. As we discussed earlier in this post we will be using greensock (gsap) to achieve it. Post requiring gsap library in your code, following function would animate the circle in the SVG.


  const animateCircleSvg = (circle, path, durationInSeconds) => {
    const val = { distance: 0 };
    gsap.to(val, {
      distance: path.getTotalLength(),
      repeat: -1,
      duration: durationInSeconds,
      ease: 'none',
      onUpdate: () => {
        const point = path.getPointAtLength(val.distance);
  circle.setAttribute('cx', point.x);
        circle.setAttribute('cy', point.y);
      },
    });
  };
  circle = document.getElementsByClassName('circle')[0];
  path = document.getElementsByClassName('path')[0];

  animateCircleSvg(circle, path, 5);
   

Above function would change the origin of the circle at every update. And In the given duration it takes a circle to the end of the path. Value of ‘repeat’ signifies how many trips to be done, -1 means infinite.

Another shape in our SVG is a triangle, let’s animate it now. For that you have to use a motionPath plugin.


import { MotionPathPlugin } from 'gsap/MotionPathPlugin';

 
const animateTriangleSvg = (triangleClass, pathClass, durationInSeconds) => {
  gsap.to(triangleClass, {
    duration: durationInSeconds,
    repeat: -1,
    repeatDelay: 0,
    ease: 'none',
    motionPath: {
      path: pathClass,
      align: pathClass,
      autoRotate: true,
      alignOrigin: [0.5, 0.5],
    },
  });
};
animateTriangleSvg('triangle', 'path', 10);

autoRotate helps polygon align on the path. alignOrigin helps to align a polygon from a given origin, in the above example its center.

Similarly, you can animate any shape and not just a circle or a triangle using greensock. For more details refer to greensock documentation.