DEV Community

Alejandro Augusto Gomez Rodriguez
Alejandro Augusto Gomez Rodriguez

Posted on


Tutorial: How to make a circular progress bar widget with React and SVG.

Today I decide to make something special. I was chilling on my bed looking some beautiful UI concept art on Instagram when I got interested in circular progress bars. So I decide to make a simple progress bar made with react and SVG.

You may not know but SVG can be edited with React since the beginning but is not so much used for complex widgets. SVG can be an excellent tool to make powerful tools where quality and performance are needed.

Some theory first or some calculus

Let's make an arc that represents the percentage value of the progress, it means that we need to evaluate the radiant coordinates of each point interest to design the arc on each percentage value. So let us represent each value as:

radius1, radius2 //inner and outer radius of the arc
omegaStart //angulus of the beginning of the arc (0%)
omegaEnd //angulus of the ending of the arc (100%)
omegaValue //angulus of the value (X%)
centerX, centerY //coordinates of the centre of the widget
xStart1, yStart1, xStart2, yStart2 //coordinates of the beginning of the arc (0%)
xEnd1, yEnd1, xEnd2, yEnd2 //coordinates of the ending of the arc (100%)
xValue1, yValue1, xValue2, yValue2  //coordinates of the value (X%)

In a blueprint we should see them like this:


So each formula should be:

omegaValue = omegaStart + (omageEnd-OmegaStart)*X
Coordinate[X,Y] = radius[cos(omega), sin(omega)]

The React Element (with hooks)

const ArcProgressBar = ({value, width, omega}) => {

     const omegaRadStart = -omega*Math.PI/180;
     const omegaRadEnd = Math.PI*(1+omega/180);
     console.log(omegaRadStart, omegaRadEnd)
     const radius = 40;
     const innerRadius = (width*40);
     const coonerRadius = (radius-innerRadius)/2;
     const omegaRadValue = omegaRadStart + (omegaRadEnd-omegaRadStart)*value;
     const xyPoint = (r, angle) => [Math.cos(angle), Math.sin(angle)].map(x => 50-(x*r))
     const [x1Start, y1Start] = xyPoint(radius, omegaRadStart);
     const [x2Start, y2Start] = xyPoint(innerRadius, omegaRadStart);
     const [x1End, y1End] = xyPoint(radius, omegaRadEnd);
     const [x2End, y2End] = xyPoint(innerRadius, omegaRadEnd);
     const [x1Value, y1Value] = xyPoint(radius, omegaRadValue);
     const [x2Value, y2Value] = xyPoint(innerRadius, omegaRadValue);

     return (
          <svg viewport="0 0 100 100">
             M ${x1Start} ${y1Start} 
             A ${radius} ${radius} 0 1 1 ${x1End} ${y1End}  
             A ${coonerRadius} ${coonerRadius} 0 1 1 ${x2End} ${y2End} 
             A ${innerRadius} ${innerRadius} 0 1 0 ${x2Start} ${y2Start} 
             A ${coonerRadius} ${coonerRadius} 0 0 1 ${x1Start} ${y1Start}
             M ${x1Start} ${y1Start} 
             A ${radius} ${radius} 0 0 1 ${x1Value} ${y1Value}  
             A ${coonerRadius} ${coonerRadius} 0 1 1 ${x2Value} ${y2Value} 
             A ${innerRadius} ${innerRadius} 0 0 0 ${x2Start} ${y2Start} 
             A ${coonerRadius} ${coonerRadius} 0 1 1 ${x1Start} ${y1Start}


Check it:

Top comments (0)

Top Posts from the React Ecosystem

1. Changes In The Official React Documentation

The former React Docs Beta has been officially released as the updated React documentation at after years of hard work and refinement. Check out the brand new React Docs: What’s New in the Updated React Docs

2. CRA's Time is Over

React developer team has removed create-react-app (CRA) from official documentation rendering it no longer the default setup method for new projects. The bulky setup, slow, and outdated nature of CRA led to its removal: create-react-app is officially dead

3. How to Fetch Articles for Your Portfolio

Integrate the articles of your profile into your personal portfolio with either React, Vue, or Next.js by following these simple steps. It outlines how to include frontend to pull the information and correctly utilizes the API: How to Fetch Your Articles for Your Portfolio with React