get your pixels movin'
The logo does tricks:

Unroll SVG circles, ellipses and spirals

Today, we’ll be using a bunch of complicated math to animate and unroll SVG circles, spirals and ellipses. WHAT? Nobody said there was gonna be math!

Nah. We’re gonna cheat and use a helper line. That way, we get our work done quicker and can go out for pizza. Let’s get rolling. See what I did there? Circle. Rolling. Very funny stuff at no additional charge.

This is a three-post series involving tricks with helper lines. Be sure to check out Unfolding Shapes and Unwrapping Circles too.

Let’s unroll something

Before diving into the details, let’s take a look at what we’re animating here. The demo shows a circle that appears to unroll from left to right. Pretty cool.

See the Pen Unroll It Single Circle by Craig Roblewsky (@PointC) on CodePen.

Artwork prep

We’ve seen the circle unroll in the demo, but we need to be mindful of how we prepare the artwork. You need a circle or ellipse. You should also have room for the circle to unroll. Remember the formula for the circumference of a circle? Of course you do, but just in case, it’s C=2πr. Your SVG should have a little wiggle room on each end too.

The circle path start point

The secret for the circle path is that we need the start point to be at the 6:00 o’clock position. To make this happen, you create a circle in Adobe Illustrator and cut the path at the bottom center and then, rejoin the cut. If you need more details about this technique, check out my cut path start points post.

The circle path direction

It’s not enough to have the start point at the 6:00 o’clock position. We also need the path to go counterclockwise. You can check this in Adobe Illustrator by adding a temporary arrowhead to the start (or end) of the path. More info can be found in my arrowhead trick post.

Once you have a circle path that starts at 6:00 o’clock and travels counterclockwise, you’re ready to go.

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="120" viewBox="0 0 420 120">
    <path d="M60,110A50,50,0,1,0,10,60,50,50,0,0,0,60,110Z" fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="4"/>
</svg>

The variables

To start the JavaScript, I’m adding a few variables and master timeline. I’m also setting the stroke-width and stroke color with JavaScript. You are welcome to set them in the CSS or as presentation attributes, but I prefer doing it in the JavaScript.

const dur = 1.25;
const mainEase = "sine.inOut";
const master = gsap.timeline({ repeat: -1, yoyo: true, repeatDelay: 1 });
const svgns = "http://www.w3.org/2000/svg";
const demo = document.querySelector("svg");
const strokeWidth = 4;
const strokeColor = "#5cceee";
let paths = gsap.utils.toArray("path");

You’ll also notice I used the handy gsap.utils.toArray() method to select the target path. Why? We only have one path in this demo, but later in the tutorial I’ll be adding more so I want to push those into an array. The master timeline will hold a nested timeline for each path.

The big secret — a helper line

To make this work, we’ll be drawing a horizontal line from the circle path’s 6:00 o’clock position to the length of the unrolled circle. In this case, that’s approximately 314 units. (The circle path has a radius of 50).

You probably noticed the helper line is not in the HTML. We’re going to create that on the fly. If you’d like more info, I wrote a whole post about creating SVG elements with JavaScript.

Our unroll() function takes one argument and that is simply our target circle path.

Line start and end points

What we really need to know is where the line should start and end. For the first answer, I’m using the MotionPathPlugin from GreenSock (free to use BTW). I feed the path into the getRawPath() method and we get back arrays of points. Depending on the complexity of your path, there may only be one array in there. All we really need is the first point in the first array.

function unroll(target) {
  let start = MotionPathPlugin.getRawPath(target)[0];
  let xPos = start[0];
  let yPos = start[1]

You could also look at the ‘d’ attribute of the path and manually enter the start coordinates, but this is far easier when you have multiple targets.

End point

Next, we need to know the length of the path to determine the end point of our helper line. I’ll use the getLength() method of GreenSock’s DrawSVG plugin for this info. You could use vanilla JavaScript, but I like to take advantage of GreenSock’s methods whenever possible.

Then, we create the line and append it to the SVG. Again, I’m using variables for the stroke color and width. That way, the target and helper line stay the same without too much effort. Feel free to use CSS, if you prefer.

  let length = DrawSVGPlugin.getLength(target);
  let lineTarget = document.createElementNS(svgns, "line");
  demo.appendChild(lineTarget);
  gsap.set([lineTarget, target], {
    stroke: strokeColor,
    strokeWidth: strokeWidth
  });

Position the helper line

All that’s left is to position the line. We create a timeline for the path target and helper line and then, use the set() method to position the line. Remember, at this setup point it has no length. It’s basically a dot we cannot yet see.

  let tl = gsap.timeline({
    defaults: { duration: dur, ease: mainEase }
  });
  tl.set(lineTarget, {
    attr: { x1: xPos, x2: xPos, y1: yPos, y2: yPos }
  });

Let’s animate

Time for the magic. All we need is two tweens. In the first, we erase the target circle path by using the GreenSock’s DrawSVG plugin. It will erase itself clockwise. That’s why we needed it to be positioned so the direction was counterclockwise. It also moves along the x axis to the full length at the same time as it erases itself.

The second tween simply draws the helper line to the full length by animating x2 attribute. Both tweens start at the same time via the position parameter of 0. The duration and ease are set as defaults so they’ll filter down to both tweens (if you need to make adjustments).

  tl.to(target, { drawSVG: 0, x: length }, 0);
  tl.to(lineTarget, { attr: { x2: "+=" + length } }, 0);

  return tl;
}

paths.forEach((obj, i) => {
  master.add(unroll(obj));
});

Note – I’m returning the nested timeline to the master and the master controls it. As I mentioned earlier, this will be handy with multiple paths.

See the Pen Unroll It Single Circle by Craig Roblewsky (@PointC) on CodePen.

Revealing the helpers

In this version, I’ve set the helper line stroke to yellow. See how the circle moves and erases while the yellow line draws?

See the Pen Unroll It Single Circle Show Helper Line by Craig Roblewsky (@PointC) on CodePen.

The circle target path

In this version, I’ve turned off the circle erasing itself. You can see how the circle moves on the x axis as the helper line draws itself.

See the Pen Unroll It Single Circle Show Circle Move by Craig Roblewsky (@PointC) on CodePen.

Multiple targets

As I mentioned earlier in the article, I’m using an array of paths because I added additional targets. Here’s the final demo showing four targets, all fed into the unroll() function and nested on the master timeline.

You can see I have a circle, a couple ellipses and even a spiral. This will work for any of those shapes as long as you set up the first point in the center bottom 6:00 o’clock position and make certain the path flows counterclockwise.

See the Pen Unroll It Tutorial Final by Craig Roblewsky (@PointC) on CodePen.

Final thoughts

You could also unroll from right to left. In that case, you would set up the paths in the opposite direction.

I hope you found some of this information to unroll SVG circles useful. Have fun rolling and unrolling your circles. Until next time, keep your pixels movin’.

If you found this information useful, please help me get the word out to the interwebs. I appreciate it. You're awesome!

Published: June 29, 2020 Last Updated: August 31, 2020

You might dig these articles too

No algorithm. Just hand chosen artisanal links.