Everything about rings and arc (which is technically the same thing) being done via SVG. Unfortunately, it is not that easy with SVG. We can't simply specify a value from 0 to 100%. Gotta dig into the SVG code and the mathematics of circles.
There are five ring in the pie: 3 colored arcs and 2 white rings around that works as separators. Separating SVG part from the pie we are getting this:
1) Creating SVG. Size is 96x96.
<svg width="96" height="96" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none"> </svg>
2) Rings are drawn with a <ellipse> tag, and filled with stroke attribute. -- this is sort of a border being drawn on both sides of the circle.
At the point (48,48) we draw such a circle with a radius of 46px (two pixels less than the image itself). Then add stroke="#69A818" and stroke-width="4" -- two pixels on each side of the circle outline.
<svg width="96" height="96" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none"> <ellipse cx="48" cy="48" rx="46" ry="46" stroke="#69A818" stroke-width="4"/> </svg>
3) Draw the second purple ring on top of it:
<svg width="96" height="96" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none"> <ellipse cx="48" cy="48" rx="46" ry="46" stroke="#69A818" stroke-width="4"/> <ellipse cx="48" cy="48" rx="46" ry="46" stroke="#523EA7" stroke-width="4"/> </svg>
Things are getting complicated with the purple ring since it must be filled only partially. First we need to catch up with stroke-dashoffset and stroke-dasharray attributes. We will code something similar to the animation of the loading indicator or the animation of filling the curves: https://css-tricks.com/svg-line-animation-works/.
In our case, the curve is a circle of 46px of radius.
Circumference C = 2Οr.
So C = 2*Ο*46 = 289px.
Normally in code I round all calculations in SVG to four decimal places, but in this demo we will cut off the decimal part for simplicity.
We can say for sure this one and all following rings will be stroke-dasharray="289" long. Always. But stroke-dashoffset="i" will be counted dynamically. Here i is a value from 0 to 289px. Actually it's opposite to be precise. Zero is 100% of filling, and 289px is 0%.
Let's fill in a quarter (i.e. 25% of purple progress).
It will be a stroke-dasharray="289-(289*25/100)" or stroke-dasharray="217"
<svg width="96" height="96" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none"> <ellipse cx="48" cy="48" rx="46" ry="46" stroke="#69A818" stroke-width="4"/> <ellipse stroke-dasharray="289" stroke-dashoffset="217" cx="48" cy="48" rx="46" ry="46" stroke="#523EA7" stroke-width="4"/> </svg>
If we want filling to start from the leftmost point (as in the Figma), we need rotate the entire circle by 180 degrees: transform="rotate(180 48 48)".
Let's also add stroke-linecap="round":
<svg width="96" height="96" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none"> <ellipse cx="48" cy="48" rx="46" ry="46" stroke="#69A818" stroke-width="4"/> <ellipse stroke-dasharray="289" stroke-dashoffset="217" cx="48" cy="48" rx="46" ry="46" stroke="#523EA7" stroke-width="4" transform="rotate(180 48 48)" stroke-linecap="round"/> </svg>
4) Now drawing 3rd, grey ring. Let's fill 10% of it.
Then stroke-dasharray="289-(289*10/100)" or stroke-dasharray="260"
<svg width="96" height="96" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none"> <ellipse cx="48" cy="48" rx="46" ry="46" stroke="#69A818" stroke-width="4"/> <ellipse stroke-dasharray="289" stroke-dashoffset="217" cx="48" cy="48" rx="46" ry="46" stroke="#523EA7" stroke-width="4" transform="rotate(180 48 48)" stroke-linecap="round"/> <ellipse stroke-dasharray="289" stroke-dashoffset="260" cx="48" cy="48" rx="46" ry="46" stroke="#E1E1F5" stroke-width="4" transform="rotate(180 48 48)" stroke-linecap="round"/> </svg>
Now we need to move the grey arc clockwise so that it looks like it is extending the purple one. In other words it starts where purple one ends. We want to use transform="rotate...", but we already have this a transformation on the rings (from the moment when we moved the starting point of the arcs). So let's wrap all the rings in <g> and use original transformation once on all arcs:
<svg width="96" height="96" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none"> <g transform="rotate(180 48 48)"> <ellipse cx="48" cy="48" rx="46" ry="46" stroke="#69A818" stroke-width="4"/> <ellipse stroke-dasharray="289" stroke-dashoffset="217" cx="48" cy="48" rx="46" ry="46" stroke="#523EA7" stroke-width="4" stroke-linecap="round"/> <ellipse stroke-dasharray="289" stroke-dashoffset="260" cx="48" cy="48" rx="46" ry="46" stroke="#E1E1F5" stroke-width="4" stroke-linecap="round"/> </g> </svg>
Now back to the shifting gray arc. It needs to be moved clockwise by 15% (25% blue arc minus 10% gray arc). We need to convert 15 percents to degrees.
15 x --- = --- β x = 15*360/100 = 54 100 360
So we need to rotate the third ring by 54 degree:
<svg width="96" height="96" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none"> <g transform="rotate(180 48 48)"> <ellipse cx="48" cy="48" rx="46" ry="46" stroke="#69A818" stroke-width="4"/> <ellipse stroke-dasharray="289" stroke-dashoffset="217" cx="48" cy="48" rx="46" ry="46" stroke="#523EA7" stroke-width="4" stroke-linecap="round"/> <ellipse stroke-dasharray="289" stroke-dashoffset="260" transform="rotate(54 48 48)" cx="48" cy="48" rx="46" ry="46" stroke="#E1E1F5" stroke-width="4" stroke-linecap="round"/> </g> </svg>
5) Now drawing white rings around colored ones. These white rings work like shadow: they are a little wider and a little longer. So we duplicate code of the purple and gray rings, color them white and increase the stroke-width to 10:
<svg width="96" height="96" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" fill="none"> <g transform="rotate(180 48 48)"> <ellipse cx="48" cy="48" rx="46" ry="46" stroke="#69A818" stroke-width="4"/> <ellipse stroke-dasharray="289" stroke-dashoffset="217" cx="48" cy="48" rx="46" ry="46" stroke="#FFFFFF" stroke-width="10" stroke-linecap="round"/> <ellipse stroke-dasharray="289" stroke-dashoffset="217" cx="48" cy="48" rx="46" ry="46" stroke="#523EA7" stroke-width="4" stroke-linecap="round"/> <ellipse stroke-dasharray="289" stroke-dashoffset="260" transform="rotate(54 48 48)" cx="48" cy="48" rx="46" ry="46" stroke="#FFFFFF" stroke-width="10" stroke-linecap="round"/> <ellipse stroke-dasharray="289" stroke-dashoffset="260" transform="rotate(54 48 48)" cx="48" cy="48" rx="46" ry="46" stroke="#E1E1F5" stroke-width="4" stroke-linecap="round"/> </g> </svg>
--- β±πΎπ ---
Placing resulting SVG back, with .pie__chart class: