Не могу понять, как работает 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 шт):
По какому принципу вычисляются и устанавливаются параметры атрибута
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>
Утилиты для расчета параметров линейного и кругового прогресс-бара
Утилита для Кругового прогресс-бара
Допустим вам надо заполнить линию с 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>



