Не могу понять, как работает stroke-dasharray при заполнении прогресс бара

Если нужно сделать анимацию заполнения окружности (прогресс бара) с помощью stroke-dashoffset, то это не вызывает затруднений.
Уменьшая максимальный отступ линии, это и есть - stroke-dashoffset от максимума до нуля, получаем заполнение линии от нуля до максимума.

<svg id="svg1"  xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink"
         width="220" height="220" viewBox="0 0 220 220" style="background:#131525"  >  
         
  <circle id="trace" cx="110" cy="110" r="100"  stroke="#DBDBDB" stroke-width="20" fill="none" />
<circle id="circle" cx="110" cy="110" r="100" transform="rotate(-90,110,110)" stroke-dashoffset="628" stroke-dasharray="628" stroke="#1E90FF" stroke-width="20" fill="none" >
       <animate attributeName="stroke-dashoffset" begin="svg1.click" dur="3s" values="628;0"  repeatCount="3" fill="freeze"/>      
</circle> 
  <text x="50%" text-Anchor="middle" y="52%" font-size="32px" fill="white">Click Me</text>
</svg>

Теперь пытаюсь анимировать полосу с помощью stroke-dasharray при тех же значениях values="628;0"

<svg id="svg1"  xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink"
         width="220" height="220" viewBox="0 0 220 220" style="background:#131525"  >  
               <!-- Серая Трасса   -->
 <circle id="trace" cx="110" cy="110" r="100"  stroke="#DBDBDB" stroke-width="20" fill="none" />
                   <!-- Цветная анимированная полоса -->
<circle id="circle" cx="110" cy="110" r="100" transform="rotate(-90,110,110)" stroke-dashoffset="628" stroke-dasharray="628" stroke="#1E90FF" stroke-width="20" fill="none" >
       <animate attributeName="stroke-dasharray" begin="svg1.click" dur="3s" values="628;0"  repeatCount="3" fill="freeze"/>      
</circle> 
  <text x="50%" text-Anchor="middle" y="52%" font-size="32px" fill="white">Click Me</text>
</svg>

Происходит что-то непонятное, хотя параметры атрибутов те же.

По какому принципу вычисляются и устанавливаются параметры атрибута stroke-dasharray для заполнения прогресс бара и любых других контуров?


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

Автор решения: Alexandr_TT

По какому принципу вычисляются и устанавливаются параметры атрибута stroke-dasharray для заполнения прогресс бара и любых других контуров?

У атрибута stroke-dasharray может быть несколько пар параметров.
В одной паре первый параметр - dash – длина черты, второй параметр gap - пробел.

И еще, важно заранее вычислить максимальную длину контура
Например для окружности c радиусом r=100px длина контура ~= 628px

Вычисляется с помощью getTotalLength()

<svg id="svg1"  xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink"
         width="220" height="220" viewBox="0 0 220 220" style="border:1px splid" >  
          <!-- Серая трасса, на которой будет заполнение -->
  <circle id="trace" cx="110" cy="110" r="100"  stroke="#DBDBDB" stroke-width="20" fill="none" />
 
</svg>
<script>
 console.log('Длина контура ~= ' + Math.round(trace.getTotalLength()) +'px')
</script>      

Линия полностью скрыта 0%

длина черты dash равна нулю, пробел gap максимальный 628px => stroke-dasharray="0,628"

<svg id="svg1"  xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink"
         width="220" height="220" viewBox="0 0 220 220" style="background:#131525"  >  
               <!-- Серая Трасса   -->
 <circle id="trace" cx="110" cy="110" r="100"  stroke="#DBDBDB" stroke-width="20" fill="none" />
                   <!-- Цветная анимированная полоса -->
<circle id="circle" cx="110" cy="110" r="100" transform="rotate(-90,110,110)" stroke-dashoffset="0" stroke-dasharray="0,628" stroke="#1E90FF" stroke-width="20" fill="none" >
</svg>

введите сюда описание изображения

Анимация роста длины линии до 25%

По мере роста длины линии dash будет увеличиваться, gap уменьшаться:

При максимальной длине линии равной 628px для 25% заполненности линии
dash = 628 * 0.25 = 157px
gap = 628 * 0.75 = 471px
0% - stroke-dasharray:0,628;
25% - stroke-dasharray:157,471;

введите сюда описание изображения

Условие для анимации роста с нуля до 25% - values="0,628;157,471"

<svg id="svg1"  xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink"
         width="220" height="220" viewBox="0 0 220 220" style="background:#131525" >  
            <!-- Серая трасса движения -->
  <circle id="trace" cx="110" cy="110" r="100"  stroke="#DBDBDB" stroke-width="20" fill="none" />
           <!-- Анимированная полоса -->
  <g transform="rotate(-90,110,110)">
<circle id="circle" cx="110" cy="110" r="100"  stroke-dashoffset="0" 
 stroke-dasharray="0, 628" stroke="#1E90FF" stroke-width="20" fill="none" >
        <animate attributeName="stroke-dasharray" begin="svg1.click" dur="3s" values="0,628;157,471"  repeatCount="1" fill="freeze"/>  
</circle>
</g> 
  <text x="50%" text-Anchor="middle" y="50%" font-size="32px" fill="white">25%</text>
</svg>

Линия полностью заполняет контур - 100%

При достижении конца линии прогресcа dash (черта) станет максимальной, а gap (пробел) будет равен нулю stroke-dasharray:628,0;

введите сюда описание изображения

Условие для анимации заполнения до 100%: values="0,628;628,0"

<svg id="svg1"  xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink"
         width="220" height="220" viewBox="0 0 220 220" style="background:#131525" >  
            <!-- Серая трасса движения -->
  <circle id="trace" cx="110" cy="110" r="100"  stroke="#DBDBDB" stroke-width="20" fill="none" />
           <!-- Анимированная полоса -->
  <g transform="rotate(-90,110,110)">
<circle id="circle" cx="110" cy="110" r="100"  stroke-dashoffset="0" 
 stroke-dasharray="0, 628" stroke="#1E90FF" stroke-width="20" fill="none" >
        <animate attributeName="stroke-dasharray" begin="svg1.click" dur="3s" values="0,628;628,0"  repeatCount="1" fill="freeze"/>  
</circle>
</g> 
  <text x="50%" text-Anchor="middle" y="50%" font-size="32px" fill="white">100%</text>
</svg>

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

Утилиты для расчета параметров линейного и кругового прогресс-бара

Утилита для Кругового прогресс-бара

Допустим вам надо заполнить линию с 36% до 100%

Двигайте ползунок input и забирайте значения stroke-dasharray="226,402"

let total = prog.getTotalLength(),
 input = document.querySelector('#size'),
 txt = document.querySelector("#txt1"),
 txt2 = document.querySelector("#txt2"),
 txt3 = document.querySelector("#txt3");
 input.addEventListener("input",()=>{  
  progress();  
})
window.addEventListener("load",()=>{  
  progress();  
})
function progress(){
  let val = Number(input.value);
  let dash = total * val / 100;
  let gap = total - dash;
  prog.style.strokeDasharray = dash + " " + gap
txt.innerHTML = (val + "%"); 
txt2.innerHTML = (`dash = ` + Math.round(dash) + "px"); 
txt3.innerHTML = (`gap = ` + Math.round(gap) + "px"); 
}
.container {
width:25vw;
height:25vh;
}
svg {
background:#131525;
}
#trace {
fill:none;
stroke:silver;
stroke-width:16;
stroke-dasharray:628,0;
} 
#prog {
fill:none;
stroke:dodgerblue;
stroke-width:16;
stroke-dasharray:0,628;
}
text {
font-family:sans-serif;
text-anchor:middle;
fill:white;
}
<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 400 400">
        <!-- Серая трасса движения -->
  <circle id="trace" cx="200" cy="250" r="100"  stroke="#DBDBDB" stroke-width="20" fill="none" />
           <!-- Анимированная полоса -->
 
<circle id="prog" transform="rotate(-90,200,250)" cx="200" cy="250" r="100"  stroke-dashoffset="0" 
 stroke-dasharray="0, 628" stroke="#1E90FF" stroke-width="20" fill="none" />

  <text id="txt1" y="65%" x="50%"  font-size="56px" fill="white">100%</text>
  <text id="txt2" y="20%" x="50%"  font-size="24px" fill="white">0px</text> 
   <text id="txt3" y="30%" x="50%" font-size="24px" fill="white">628px</text> 
   <text id="txt4" y="10%" x="50%" font-size="36px" fill="white">stroke-dasharray</text>
   
</svg>
 <div><input id="size" type="range" min="0" step="1" max = "100" value="0" /></div>
</div>
    

введите сюда описание изображения

Получается анимация заполнения с 36% до 100%

Анимация начнется после клика:

<svg id="svg1"  xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink"
         width="220" height="220" viewBox="0 0 220 220" style="background:#131525" >  
            <!-- Серая трасса движения -->
  <circle id="trace" cx="110" cy="110" r="100"  stroke="#DBDBDB" stroke-width="20" fill="none" />
           <!-- Анимированная полоса -->
  <g transform="rotate(-90,110,110)">
<circle id="circle" cx="110" cy="110" r="100"  stroke-dashoffset="0" 
 stroke-dasharray="226, 402" stroke="#1E90FF" stroke-width="20" fill="none" >
        <animate attributeName="stroke-dasharray" begin="svg1.click" dur="3s" values="226,402;628,0"  repeatCount="1" fill="freeze"/>  
</circle>
</g> 
  
</svg>

Утилита для линейного прогресс-бара

Все точно так же, как и для круглого прогресс бара, отличие только в path анимируемого элемента

let total = prog.getTotalLength(),
 input = document.querySelector('#size'),
 txt = document.querySelector("#txt1"),
 txt2 = document.querySelector("#txt2"),
 txt3 = document.querySelector("#txt3");
input.addEventListener("input",()=>{  
  progress();  
})
window.addEventListener("load",()=>{  
  progress();  
})
function progress(){
  let val = Number(input.value);
  let dash = total * val / 100;
  let gap = total - dash;
  prog.style.strokeDasharray = dash + " " + gap
txt.innerHTML = (val + "%"); 
txt2.innerHTML = (`dash = ` + Math.round(dash) + "px"); 
txt3.innerHTML = (`gap = ` + Math.round(gap) + "px"); 
}
.container {
width:25vw;
height:25vh;
}
svg {
background:#131525;
}
#trace {
fill:none;
stroke:silver;
stroke-width:16;
stroke-dasharray:628,0;
} 
#prog {
fill:none;
stroke:dodgerblue;
stroke-width:16;
stroke-dasharray:0,628;
}
<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 650">
  <path id="trace" d="M10,300 638,300"    /> 
  <path id="prog"  d="M10,300 638,300"  />
 <g font-family="sans-serif" text-anchor="middle" fill="white">
  <text id="txt1" y="70%" x="50%"  font-size="72px" fill="white">100%</text>
  <text id="txt2" y="20%" x="50%" font-family="sans-serif" text-anchor="middle" font-size="36px" fill="white">0px</text> 
   <text id="txt3" y="30%" x="50%" font-family="sans-serif" text-anchor="middle" font-size="36px" fill="white">628px</text> 
   <text id="txt4" y="10%" x="50%"  font-size="64px">stroke-dasharray</text>
 </g>  
</svg>
 <div><input id="size" type="range" min="0" step="1" max = "100" value="0" /></div>
</div>
   

→ Ссылка