How to create a radial progress bar with SVG
What is it for?
A while back we implemented a little countdown timer, which involved creating a radial progress bar. We ended up building a SVG radial timer, however we found that a lot of online resources were a bit complicated. In the end we built a straight forward simple radial progress bar using SVG, CSS and JS.
We chose SVG over images because it can be styled with CSS, allowing us to quickly change look and feel of the progress bar without asking for another image from designer. It also has a lower memory footprint than an image since we don’t need to load any additional assets. The most important reason is of course “it is vector based” so it works well on different resolutions.
Creating a circle with SVG
Our basic SVG structure is the
<circle cx="60" cy="60" r="50"/>
r are the minimum attributes which are needed to describe a circle.
cx and cy
cy are attributes describing the position of the circle center, relative to SVG starting position in the top left corner
r attribute specifies the radius of the
Creating a ring using a circle!
Ring is nothing but a
<circle> which has only a visible border. To achieve this we need to make the inner part of the circle transparent and add some thick border.
In SVG we can’t directly use
border-color to achieve what we are aiming for.
So let’s look how we can achieve this using the SVG attribute
The easiest way to illustrate the stroke attribute, is to consider the
<line> element as an example.
For a SVG element
stroke is similar to what borders are in CSS. Size, color and style can be modified in order to create a dashed effect. In addition to defining color and width with the
stroke attribute, we also use
stroke-dasharray describes the length of a dash.
<line stroke-dasharray="2em" x1="0" y1="0" x2="8em" y2="0" />
In the example each dash is
stroke-dashoffset describes the offset from the default position of our stroke.
<line stroke-dashoffset="1em" stroke-dasharray="2em" x1="0" y1="1em" x2="8em" y2="1em" />
In the example the green line has a
1em, which means that the starting position of the stroke moved
1em to the left.
fill is used to set the fill color of the SVG element.
In our case we set it to
transparent so that we get a ring at the end.
Creating layers in SVG
In order to create a progress bar we need to create some layers. One background layer, and one layer actually moving as the timer counts down. So in our example there is one ring at the bottom creating the background for the progress bar, and then another ring on top where we use
stroke-dashoffset. This allows us to modify the state of the progress bar by adjust the
There is however a problem with our current example it start at 90° and moves counter clockwise. In order to have the initial position to 0°, we rotate the circles 270° degrees. To make it move clockwise we’ll have to adjust the
stroke-dashoffset. We’ll address that in the animation step.
Since we wanted to fill the center with text, we added a circle at the bottom with
fill so the whole radial progress bar has a background.
stroke-offset of the progress-cover ring every second.
As mentioned in the previous section if we increase the
stroke-dashoffset it will move counter clockwise. And since this a time we want the animation to move clockwise, we set the
stroke-dashoffset to an negative value. And by decreasing the
stroke-dashoffset by 1/60 part of the circumference of the ring, we get a nice one minute countdown timer.