JSFiddle - React, Tailwind, and code Playground
by RAX7
HTML
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 168 124">
<defs>
<mask id="mask">
<path id="mask-path" d="M151.2,103.5a70,70,0,1,0-134.4,0"
stroke="#fff" stroke-width="28" fill="none"
stroke-dasharray="259.65142822265625"
stroke-dashoffset="399.86319946289063"/>
</mask>
</defs>
<circle cx="84" cy="84" r="40" fill="#f8d248"/>
<text id="text"
x="84" y="95" text-anchor="middle">
54
</text>
<g id="chart" fill="none" stroke-width="28" stroke-dasharray="4.636632646833148">
<path d="M151.2,103.5a70,70,0,1,0-134.4,0" stroke="#f2f3fa"/>
<g mask="url(#mask)">
<rect width="100%" height="100%"/>
<path d="M151.2,103.5a70,70,0,1,0-134.4,0" stroke="#f8d248"/>
</g>
</g>
</svg>
CSS
body {
margin: 0.5rem 3rem;
}
#text {
font-family: Tahoma, sans-serif;
font-weight: 700;
font-size: 30px;
fill: #fff;
}
JavaScript
function animChar(duration) {
const mask = document.querySelector('#mask-path');
const chart = document.querySelector('#chart');
const text = document.querySelector('#text');
const divideBySegmets = 28;
const totalLen = mask.getTotalLength();
const segmetLen = totalLen / (divideBySegmets * 2);
mask.setAttribute('stroke-dasharray', totalLen);
chart.setAttribute('stroke-dasharray', segmetLen);
function setCharProgress(pct) {
const piece = divideBySegmets * pct;
mask.setAttribute('stroke-dashoffset', totalLen + segmetLen * 2 * piece);
text.textContent = Math.round(pct * 100);
}
let begin;
function draw(now) {
begin = begin || now;
const t = Math.min(1, (now - begin) / duration);
setCharProgress(t);
if (t !== 1) {
requestAnimationFrame(draw);
}
}
requestAnimationFrame(draw);
}
animChar(5000);