Как сделать анимацию линии спидометра с выводом числовых значений скорости

Необходимо сделать подобный спидометр

пример,

но я мало работал с svg, поэтому прошу помощи) Будет достаточно хотя бы направления, куда копать, как гуглить. Может какие то ссылки на похожие примеры. Заранее благодарен!


Ответы (2 шт):

Автор решения: Айболит

В принципе, можно управлять увеличчением скорости с помощью input type="range" из которого на javascript можно олучить value и присвоить его маске которая по сути дублирует наш с вами path через use то есть на самом деле мы увеличиваем/уменьшаем ширину(width) этого самого rect который имеет более яркую расцветку

Ну и соббственно весь мой код смотрите в работе

let range = document.getElementById("inp");
let rect = document.querySelector("#rect");
let text = document.querySelector("#text");
let data = document.querySelector("#data");

range.oninput = function() {
  rect.style.width = this.value + "%";
  text.innerHTML = this.value;
  data.setAttribute("x", 50 + this.value / 10);
}
<svg width="200px" viewBox="0 0 152.97 49.075" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <mask id="mask">
      <rect width="100%" height="100%" fill="#000" />
      <use  href="#path" fill="#fff" />
    </mask>
  </defs>
 <path id="path" d="m2.4223 48.852c3.0345-33.053 23.447-46.321 49.398-46.376 18.889-0.04009 41.213-0.15614 65.136 0.29209 10.311 0.19319 21.446-0.18148 35.939 0.24748" fill="none" stroke="#ccc" stroke-width="4.8"/>
  
<rect id="rect" width="50%" height="100%" fill="#F50D86" mask="url(#mask)" />
  
<text id="text" x="20" y="49" style="text-transform: uppercase; font-size: 20px; font-family: sans-serif; font-weight: 900;" fill="#000">20</text>
  
<text  id="data" x="50" y="49" style="text-transform: uppercase; font-family: sans-serif; font-size: 14px; font-weight: 100;" fill="#000">км.ч</text>
</svg>

<input style="display: block; margin-top: 50px; width: 200px;" id="inp" type="range" min="20" max="100" value="20">

→ Ссылка
Автор решения: Alexandr_TT

Решение stroke-dasharray

Для решения используются значения параметров атрибута path
stroke-dasharray="dash,gap", где
dash - тире
gap - пробел

максимальная длина линии получена с помощью метода JS getTotalLength() и равна 664.4px

  • при значении stroke-dasharray="0,664.4" линия спидометра будет полностью скрыта, так черта имеет нулевое значение, а пробел равен максимальной длине

  • при значении stroke-dasharray="664.4;0" линия спидометра будет полностью нарисована, так как длина черты имеет максимальное значение

На этом и основана анимация рисования линии спидометра от нуля до максимума

Анимация начинается при наведении курсора

.container {
width:75vw;
height:75vh;
}
svg {
background:#131525;
}
#trace {
fill:none;
stroke:#444551;
stroke-width:16;
} 
#velocity {
fill:none;
stroke:#F9118D;
stroke-width:16;
stroke-dasharray:0,664.4;

}
svg:hover #velocity {
animation: move 5s forwards;
}

@keyframes move {
to{stroke-dasharray:664.4,0}
}
<div class="container">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" preserveAspectRatio="xMinYMin meet" fill="#131525" id="svg4" viewBox="0 0 650 243">
  <path id="trace" d="M60.4 215.2c.4-19.4 3.9-30.8 8-45.6a171 171 0 0 1 14.2-36.3c9-16.1 13.4-20.8 20.7-30.2 7.6-9.7 17.8-17.3 27.8-24.6 8.5-6.1 17.5-11.5 27-15.9 12-5.5 24.5-9.9 37.4-12.7 10.4-2.3 21.1-2.6 31.8-3.2 15.6-.9 46.8-.8 46.8-.8l355.2-.8"     /> 
  <path id="velocity" d="M60.4 215.2c.4-19.4 3.9-30.8 8-45.6a171 171 0 0 1 14.2-36.3c9-16.1 13.4-20.8 20.7-30.2 7.6-9.7 17.8-17.3 27.8-24.6 8.5-6.1 17.5-11.5 27-15.9 12-5.5 24.5-9.9 37.4-12.7 10.4-2.3 21.1-2.6 31.8-3.2 15.6-.9 46.8-.8 46.8-.8l355.2-.8" />
</svg>
</div>

Анимация при управлении input

Я выбрал максимальное значение спидометра 360 км/ч Это max = "360" input
Принцип анимации линии спидометра точно такой же, как и в примере выше- увеличение dash и уменьшение gap

let total = velocity.getTotalLength(),
 input = document.querySelector("[type='range']"),
 txt = document.querySelector("#txt1");

input.addEventListener("input",()=>{  
  speedometr();  
})

window.addEventListener("load",()=>{  
  speedometr();  
})

function speedometr(){
  let val = Number(input.value);
  let dash = total * val / 360;
  let gap = total - dash;
  velocity.style.strokeDasharray = dash + " " + gap
txt.innerHTML = (val + "км/ч"); 
}
.container {
width:70vw;
height:70vh;
}
svg {
background:#131525;
}
#trace {
fill:none;
stroke:#444551;
stroke-width:16;
stroke-dasharray:664.4,0;
} 
#velocity {
fill:none;
stroke:#F9118D;
stroke-width:16;
stroke-dasharray:0,664.4;
}
<div class="container">
<div><input id="size" type="range" min="0" step="10" max = "360" value="0" /></div>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" preserveAspectRatio="xMinYMin meet" fill="#131525" id="svg4" viewBox="0 0 650 243">
  <path id="trace" d="M60.4 215.2c.4-19.4 3.9-30.8 8-45.6a171 171 0 0 1 14.2-36.3c9-16.1 13.4-20.8 20.7-30.2 7.6-9.7 17.8-17.3 27.8-24.6 8.5-6.1 17.5-11.5 27-15.9 12-5.5 24.5-9.9 37.4-12.7 10.4-2.3 21.1-2.6 31.8-3.2 15.6-.9 46.8-.8 46.8-.8l355.2-.8"     /> 
  <path id="velocity" d="M60.4 215.2c.4-19.4 3.9-30.8 8-45.6a171 171 0 0 1 14.2-36.3c9-16.1 13.4-20.8 20.7-30.2 7.6-9.7 17.8-17.3 27.8-24.6 8.5-6.1 17.5-11.5 27-15.9 12-5.5 24.5-9.9 37.4-12.7 10.4-2.3 21.1-2.6 31.8-3.2 15.6-.9 46.8-.8 46.8-.8l355.2-.8" /> 
  <text id="txt1" y="60%" x="50%" font-family="sans-serif" text-anchor="middle" font-size="56px" fill="white">100 км/ч</text>
</svg>
 
</div>

→ Ссылка