Частичное заполнение дуги SVG с помощью stroke-dasharray
<template>
<div class="bottom-right-block">
<div class="meter">
<svg class="background" width="248" height="269" viewBox="0 0 248 269" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="path-1-inside-1_7_62" fill="white">
<path d="M247.53 42.7624C233.157 28.29 215.922 17.0221 196.945 9.69003C177.967 2.35792 157.67 -0.874605 137.371 0.202203C117.073 1.27901 97.2255 6.6411 79.1179 15.9405C61.0103 25.2399 45.0469 38.2689 32.2635 54.1819C19.4801 70.0949 10.1623 88.5364 4.91489 108.31C-0.332547 128.083 -1.39243 148.746 1.80402 168.959C5.00048 189.171 12.3818 208.481 23.4691 225.636C34.5564 242.79 49.1019 257.405 66.1617 268.534L72.2668 259.045C56.5281 248.778 43.109 235.295 32.8803 219.469C22.6517 203.643 15.8419 185.828 12.893 167.181C9.94405 148.534 10.9219 129.471 15.7629 111.228C20.604 92.9863 29.2002 75.9729 40.9937 61.2922C52.7871 46.6115 67.5144 34.5915 84.2197 26.0122C100.925 17.4329 119.235 12.4861 137.962 11.4926C156.689 10.4992 175.414 13.4814 192.922 20.2457C210.43 27.0101 226.33 37.4053 239.591 50.757L247.53 42.7624Z"/>
</mask>
<path d="M247.53 42.7624C233.157 28.29 215.922 17.0221 196.945 9.69003C177.967 2.35792 157.67 -0.874605 137.371 0.202203C117.073 1.27901 97.2255 6.6411 79.1179 15.9405C61.0103 25.2399 45.0469 38.2689 32.2635 54.1819C19.4801 70.0949 10.1623 88.5364 4.91489 108.31C-0.332547 128.083 -1.39243 148.746 1.80402 168.959C5.00048 189.171 12.3818 208.481 23.4691 225.636C34.5564 242.79 49.1019 257.405 66.1617 268.534L72.2668 259.045C56.5281 248.778 43.109 235.295 32.8803 219.469C22.6517 203.643 15.8419 185.828 12.893 167.181C9.94405 148.534 10.9219 129.471 15.7629 111.228C20.604 92.9863 29.2002 75.9729 40.9937 61.2922C52.7871 46.6115 67.5144 34.5915 84.2197 26.0122C100.925 17.4329 119.235 12.4861 137.962 11.4926C156.689 10.4992 175.414 13.4814 192.922 20.2457C210.43 27.0101 226.33 37.4053 239.591 50.757L247.53 42.7624Z" stroke="#404040" stroke-width="12" mask="url(#path-1-inside-1_7_62)"/>
<path id="playerVehicleSpeed" d="M247.53 42.7624C233.157 28.29 215.922 17.0221 196.945 9.69003C177.967 2.35792 157.67 -0.874605 137.371 0.202203C117.073 1.27901 97.2255 6.6411 79.1179 15.9405C61.0103 25.2399 45.0469 38.2689 32.2635 54.1819C19.4801 70.0949 10.1623 88.5364 4.91489 108.31C-0.332547 128.083 -1.39243 148.746 1.80402 168.959C5.00048 189.171 12.3818 208.481 23.4691 225.636C34.5564 242.79 49.1019 257.405 66.1617 268.534L72.2668 259.045C56.5281 248.778 43.109 235.295 32.8803 219.469C22.6517 203.643 15.8419 185.828 12.893 167.181C9.94405 148.534 10.9219 129.471 15.7629 111.228C20.604 92.9863 29.2002 75.9729 40.9937 61.2922C52.7871 46.6115 67.5144 34.5915 84.2197 26.0122C100.925 17.4329 119.235 12.4861 137.962 11.4926C156.689 10.4992 175.414 13.4814 192.922 20.2457C210.43 27.0101 226.33 37.4053 239.591 50.757L247.53 42.7624Z" stroke="#D6A100" stroke-width="12" mask="url(#path-1-inside-1_7_62)"/>
</svg>
</div>
</div>
</template>
<script>
export default {
methods: {
updateSpeed(i) {
var speedValue = Math.round((132 / 180) * i / 1.050);
document.getElementById("playerVehicleSpeed").style = `stroke-dasharray: ${speedValue}% 500%;`;
}
},
mounted() {
window.speedometer = this;
this.updateSpeed(20);
}
}
</script>
не могу понять, как подсчитать число вместо 500%, т.е. сейчас заполняется только половина, а должно заполнять две.

Ответ:
исправил, просто сделал ширину 24 вместо 12 у активной дуги. но теперь нужно сделать так, чтобы она заполнялась в противоположном направлении, т.е. снизу вверх
Ответы (2 шт):
Зачем здесь кубические кривые Безье? Зачем здесь clipping mask? Кто этот SVG делал и каким образом к нему можно применить stroke-dasharray? Вы хоть понимаете, какая фигура описана в этом path? Вот такая:
<svg class="background" width="248" height="269" viewBox="0 0 248 269" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="
M 247.53 42.7624
C 233.157 28.29 215.922 17.0221 196.945 9.69003
C 177.967 2.35792 157.67 -0.874605 137.371 0.202203
C 117.073 1.27901 97.2255 6.6411 79.1179 15.9405
C 61.0103 25.2399 45.0469 38.2689 32.2635 54.1819
C 19.4801 70.0949 10.1623 88.5364 4.91489 108.31
C -0.332547 128.083 -1.39243 148.746 1.80402 168.959
C 5.00048 189.171 12.3818 208.481 23.4691 225.636
C 34.5564 242.79 49.1019 257.405 66.1617 268.534
L 72.2668 259.045
C 56.5281 248.778 43.109 235.295 32.8803 219.469
C 22.6517 203.643 15.8419 185.828 12.893 167.181
C 9.94405 148.534 10.9219 129.471 15.7629 111.228
C 20.604 92.9863 29.2002 75.9729 40.9937 61.2922
C 52.7871 46.6115 67.5144 34.5915 84.2197 26.0122
C 100.925 17.4329 119.235 12.4861 137.962 11.4926
C 156.689 10.4992 175.414 13.4814 192.922 20.2457
C 210.43 27.0101 226.33 37.4053 239.591 50.757
L 247.53 42.7624 Z" stroke="black"/>
</svg>
Ну и что для этой фигуры даст атрибут stroke-dasharray? Пунктиром её нарисует?
Я могу предположить, что исходной задачей было нарисовать дугу некой толщины и отобразить на ней некий показатель. Ну так для этого у нас есть специальная команда для рисования дуги (документация). Если у нас есть координаты центра окружности, радиус окружности, и начальный/конечный углы начала и конца дуги, то координаты точек начала и конца дуги рассчитываются по формулам, которые проходят ещё в школе, если я правильно помню:
x = cx + r * cos(θ)
y = cy + r * sin(θ)
К такому отрезку - дуге окружности - уже действительно можно применить атрибут stroke-dasharray. Но надо учесть, что если размер SVG у нас, допустим, 300x300 пикселей, а длина окружности получается равной 400 (формулу для расчёта длины дуги окружности напоминать, или не надо?), то полный размер такой дуги в процентах для stroke-dasharray будет равен
400 / 300 * 100% = 133.33%
Если длина и ширина SVG отличаются, то для расчёта длины дуги в процентах с некоторым приближением подойдёт среднее арифметическое длины и ширины SVG. Впрочем, для нашего случая можно вообще уйти от процентов, и если считать, что максимальное значение скорости, при котором вся дуга должна быть закрашена, равно некоему maxSpeed, то для некоторого конкретного значения скорости длина закрашенной дуги будет равна
currentLength = arcLength / maxSpeed * currentSpeed
Вот пример кода, который делает то, чего, насколько я понимаю, вы хотите добиться:
// Параметры шкалы (дуги окружности)
const cx = 150, cy = 150, r = 140,
startAngle = 122.82, endAngle = 314.726;
// Максимальная скорость, при которой шкала будет полностью закрашена
const maxSpeed = 160;
// По заданным координатам центра окружности,
// радиусу окружности и начальному/конечному углу дуги
// получаем длину этой дуги и path для SVG
function arcToSvgPath(cx, cy, r, startAngle, endAngle) {
const toRadians = deg => deg * Math.PI / 180;
const radStart = toRadians(startAngle);
const radEnd = toRadians(endAngle);
const xStart = cx + r * Math.cos(radStart);
const yStart = cy + r * Math.sin(radStart);
const xEnd = cx + r * Math.cos(radEnd);
const yEnd = cy + r * Math.sin(radEnd);
const normalize = a => (a + 360) % 360;
const angleDiff = normalize(endAngle - startAngle);
const largeArcFlag = angleDiff > 180 ? 1 : 0;
// Рисуем всегда по часовой стрелке
const sweepFlag = 1;
const path = `M ${xStart},${yStart} A ${r},${r} 0 ${largeArcFlag} ${sweepFlag} ${xEnd},${yEnd}`;
const arcLength = r * toRadians(angleDiff);
return { path, arcLength };
}
const svgContainer = document.getElementById('speed-gauge');
const { path, arcLength } = arcToSvgPath(cx, cy, r, startAngle, endAngle);
// Добавляем первый path, "пустой" индикатор скорости
const playerVehicleGauge = document.createElementNS("http://www.w3.org/2000/svg", "path");
playerVehicleGauge.setAttribute("d", path);
playerVehicleGauge.setAttribute("fill", "none");
playerVehicleGauge.setAttribute("stroke", "black");
playerVehicleGauge.setAttribute("stroke-width", "12");
svgContainer.appendChild(playerVehicleGauge);
// Длина отрезка дуги в пикселях, соответствующего одной единице скорости
const unitLength = arcLength / maxSpeed;
// Добавляем второй path, отображающий текущую скорость, поверх первого
const playerVehicleSpeed = document.createElementNS("http://www.w3.org/2000/svg", "path");
playerVehicleSpeed.setAttribute("d", path);
playerVehicleSpeed.setAttribute("fill", "none");
playerVehicleSpeed.setAttribute("stroke", "red");
playerVehicleSpeed.setAttribute("stroke-width", "12");
playerVehicleSpeed.setAttribute("stroke-dasharray", `0 ${arcLength} `);
svgContainer.appendChild(playerVehicleSpeed);
const speedText = document.getElementById("speed-span");
document.getElementById("speed").addEventListener("input", function() {
const speed = this.value;
speedText.innerHTML = speed;
playerVehicleSpeed.setAttribute("stroke-dasharray", `${unitLength * speed} ${arcLength} `);
});
<svg width="300" height="300"
xmlns="http://www.w3.org/2000/svg"
id="speed-gauge">
</svg>
<p>
<input id="speed" type="range" min="0" max="160" step="1" value="0"> Скорость: <span id="speed-span">0</span>
</p>
Начальный и конечный углы дуги примерно соответствуют дуге на картинке в исходном вопросе (высчитывал по опорным точкам). Первое значение для stroke-dasharray я высчитываю динамически, для второго (остатка полосы) всегда беру полную длину дуги.
Дополнение
Оказывается, у SVG-элемента path есть метод getTotalLength(), о котором я на момент написания первой версии ответа даже и не знал. Это несколько упрощает нам жизнь, рассчитывать длину дуги по её углу нам больше не надо, необходимый path мы можем рассчитать и добавить в HTML заранее. Вот сокращённый пример, который должно быть немного легче понять. В качестве начального и конечного углов я взял 120 и 315 градусов.
const svgContainer = document.getElementById("gauge-svg");
const playerVehicleGauge = document.getElementById("gauge-arc");
// Создаём дубликат элемента SVG path
const playerVehicleSpeed = playerVehicleGauge.cloneNode();
// Вычисляем длину шкалы (дуги) в пикселях
const gaugeLength = playerVehicleSpeed.getTotalLength();
// Заполняем отличающиеся от "прародителя" атрибуты
playerVehicleSpeed.setAttribute("id", "gauge-speed");
playerVehicleSpeed.setAttribute("stroke", "red");
playerVehicleSpeed.setAttribute("stroke-dasharray", `0 ${gaugeLength}`);
// Добавляем новый элемент в SVG контейнер
svgContainer.append(playerVehicleSpeed);
// Максимальная скорость, при которой шкала будет полностью закрашена
const maxSpeed = 160;
const speedText = document.getElementById("speed-span");
document.getElementById("speed-input").addEventListener("input", function() {
const currentSpeed = this.value;
speedText.innerHTML = currentSpeed;
playerVehicleSpeed.setAttribute("stroke-dasharray", `${gaugeLength * currentSpeed / maxSpeed} ${gaugeLength}`);
});
<svg width="300" height="300"
xmlns="http://www.w3.org/2000/svg"
id="gauge-svg">
<path id="gauge-arc" d="M80,271.24 A140,140 0 1 1 249,51" fill="none" stroke="black" stroke-width="12"/>
</svg>
<p>
<input id="speed-input" type="range" min="0" max="160" step="1" value="0"/>
Скорость: <span id="speed-span">0</span>
</p>
Цитата из комментария автора вопроса:
исправил, просто сделал ширину 24 вместо 12 у активной дуги. но теперь нужно сделать так, чтобы она заполнялась в противоположном направлении, т.е. снизу вверх
Направление движения при анимации заполнении дуги зависит от заданного направления рисования дуги в векторном редакторе, то есть от положения первого узла path к последнему узлу.
Изменил направление на обратное. Теперь дуга будет рисоваться снизу в верх.
Векторный редактор по умолчанию добавляет 6 цифр после запятой, что значительно увеличивает размер файла. Здесь такая точность не нужна.
С помощью оптимизатора - SVGOMG установил одну цифру после запятой, попутно оптимизатор убирает лишнюю служебную информацию добавленную векторным редактором, что значительно уменьшает размер файла.
Результат:
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="269" height="269" viewBox="0 0 269 269" >
<rect fill="#141414" width="100%" height="100%" />
<!-- Цветная полоса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#FCBD00" stroke-width="12" >
</path>
</svg>
Цитата из ответа Ivan Shatsky:
Зачем здесь кубические кривые Безье? Зачем здесь clipping mask? Кто этот SVG делал и каким образом к нему можно применить stroke-dasharray? Вы хоть понимаете, какая фигура описана в этом path? Вот такая:
Код вероятно скопирован из чужого ответа, реализующего технику -Handwriting, когда нужно реализовать анимацию появления контура разной ширины.
Суть метода: рисуется фигурная линия, как правило в векторном редакторе пером, имитирующим разную ширину и нажим (каллиграфия).
Так как ширина разная, то фигура всегда имеет двойной контур.
Анимация появления линии достигается первоначальным маскированием её линией, которая шире начальной фигуры с двойным контуром.
Далее верхняя линия постепенно сдвигается и показывается нижняя линия, тем самым создавая эффект анимации роста цветной линии.
Notice:
К фигуре с двойным контуром можно применить анимацию stroke-dasharray, но желаемого эффекта заполнения контура не получить, так как будет анимироваться граница контура, а не заполнение фигуры.
Решение:
Так как фигура имеет одинаковую ширину, то достаточно одной широкой линии (path)
Маска в этом случае не нужна
Появление линии достигается либо с помощью анимации
stroke-dashoffsetлибоstroke-dasharrayС помощью stroke-dasharray варианты анимации будут поинтересней.
Вариант 1
Анимация с помощью stroke-dashoffset
максимальная длина дуги: вычислена с помощью getTotalLength() = 423;
Появление дуги достигается уменьшением от максимально отступа до нуля values="423;0" реализуя тем самым рост цветной линии от нуля до 423 px
Анимация начинается после клика по холсту svg - begin="svg1.click"
.container {
width:40vw;
height:40vh;
}
<div class="container">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 269 269" >
<!-- Фон -->
<rect fill="#141414" width="100%" height="100%" />
<!-- Трасса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#7D7D7D" stroke-width="12" stroke-dasharray="none"/>
<!-- Цветная полоса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#FCBD00" stroke-width="12" stroke-dashoffset="423" stroke-dasharray="423">
<animate attributeName="stroke-dashoffset" begin="svg1.click" dur="3s" values="423;0" fill="freeze" />
</path>
</svg>
</div>
Вариант 2
Анимация с помощью stroke-dasharray
При значениях stroke-dasharray="0 423" длина черты равна нулю, длина пробела равна максимальному значению равной длине линии 423px;
values="0 423; 423 0" - черта растет от нуля до 423px
.container {
width:35vw;
height:35vh;
<div class="container">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 269 269" >
<!-- Фон -->
<rect fill="#141414" width="100%" height="100%" />
<!-- Трасса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#7D7D7D" stroke-width="12" stroke-dasharray="none"/>
<!-- Цветная полоса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#FCBD00" stroke-width="12" stroke-dashoffset="423" stroke-dasharray="0 423">
<animate attributeName="stroke-dasharray" begin="svg1.click" dur="3s" values="0 423; 423 0"
fill="freeze" />
</path>
</svg>
</div>
Вариант 3
repeatCount="indefinite" - бесконечное повторение циклов заполнения:
values="0 423; 423 0; 423 0" пауза в конце одного цикла, устанавливается повторением последней группы цифр 423 0
.container {
width:30vw;
height:30vh;
<div class="container">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 269 269" >
<!-- Фон -->
<rect fill="#141414" width="100%" height="100%" />
<!-- Трасса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#7D7D7D" stroke-width="12" stroke-dasharray="none"/>
<!-- Цветная полоса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#FCBD00" stroke-width="12" stroke-dashoffset="423" stroke-dasharray="0 423">
<animate attributeName="stroke-dasharray" begin="svg1.click" dur="3s" values="0 423; 423 0; 423 0 "
repeatCount="indefinite" />
</path>
</svg>
</div>
Вариант 4
Пауза в середине, пауза в конце
values="0 423; 211 212; 211 212; 423 0; 423 0"
.container {
width:30vw;
height:30vh;
<div class="container">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 269 269" >
<!-- Фон -->
<rect fill="#141414" width="100%" height="100%" />
<!-- Трасса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#7D7D7D" stroke-width="12" stroke-dasharray="none"/>
<!-- Цветная полоса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#FCBD00" stroke-width="12" stroke-dashoffset="423" stroke-dasharray="0 423">
<animate attributeName="stroke-dasharray" begin="svg1.click" dur="3s" values="0 423; 211 212; 211 212; 423 0; 423 0 "
repeatCount="indefinite" />
</path>
</svg>
</div>
Вариант 5
Реализация нелинейных ease функций.
calcMode="spline"
keySplines=" 0.185,0.675,0,0.995"
замедление в конце
.container {
width:30vw;
height:30vh;
<div class="container">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 269 269" >
<!-- Фон -->
<rect fill="#141414" width="100%" height="100%" />
<!-- Трасса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#7D7D7D" stroke-width="12" stroke-dasharray="none"/>
<!-- Цветная полоса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#FCBD00" stroke-width="12" stroke-dashoffset="423" stroke-dasharray="0 423">
<animate attributeName="stroke-dasharray" begin="svg1.click" dur="3s" values="0 423;423 0 " calcMode="spline"
keySplines=" 0.185,0.675,0,0.995"
repeatCount="indefinite" />
</path>
</svg>
</div>
Дискретное заполнение:
calcmode="discrete"
values="423;381;339;297;255;213;163;121;79;37;0;0"
.container {
width:30vw;
height:30vh;
<div class="container">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 269 269" >
<!-- Фон -->
<rect fill="#141414" width="100%" height="100%" />
<!-- Трасса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="#7D7D7D" stroke-width="12" stroke-dasharray="none"/>
<!-- Цветная полоса -->
<path d="M83.8 249.6S60 229.7 51.3 217.1a134.2 134.2 0 0 1-22.2-49 133 133 0 0 1 1.7-55.3 124 124 0 0 1 20-44.4 126.1 126.1 0 0 1 33.5-30.8 122.5 122.5 0 0 1 44-19.4 133 133 0 0 1 61.5 3.5c19 5.7 51.3 30.2 51.3 30.2"
fill="none" stroke="cyan" stroke-width="12" stroke-dashoffset="423" stroke-dasharray="423 423">
<animate attributeName="stroke-dashoffset" begin="svg1.click" dur="6s" values="423;381;339;297;255;213;163;121;79;37;0;0" calcMode="discrete" repeatCount="indefinite" />
</path>
</svg>
</div>
Теория:
