У меня приложение на Vue.js
и мне нужно прогресс-бар создать. Я использую Svg, потому что другие варианты не подойдут. Как можно разбить SVG-полукруг на равные части. У меня получается сплошная линия. Пытался манипулировать атрибутом stroke-dasharray
, но не получается.
Необходимо получить такой вид:
я пока добился такого
мой код:
<div class="radial">
<svg xmlns="http://www.w3.org/2000/svg" height="100" width="100" viewBox="0 0 200 200" data-value="40">
<path class="bg" stroke="#ccc" d="M41 149.5a77 77 0 1 1 117.93 0" fill="none"/>
<path class="meter" stroke="#D15F45" d="M41 149.5a77 77 0 1 1 117.93 0" fill="none" pathLength="100" stroke-dasharray="38, 100"/>
</svg>
</div>
Самый простой вариант, если фон белый, можно закрыть 2мя белыми линиями, идущими от центра:
requestAnimationFrame(draw)
function draw(dt) {
document.querySelector('.meter').setAttribute('stroke-dasharray', `${dt/10%100}, 100`);
requestAnimationFrame(draw)
}
<div class="radial">
<svg xmlns="http://www.w3.org/2000/svg" height="200" width="200" viewBox="0 0 200 200" data-value="40">
<path class="bg" stroke-width="22" stroke="#ccc" d="M41 149.5a77 77 0 1 1 117.93 0" fill="none"/>
<path class="meter" stroke-width="22" stroke="#D15F45" d="M41 149.5a77 77 0 1 1 117.93 0" fill="none" pathLength="100" stroke-dasharray="38, 100"/>
<path stroke="white" stroke-width="5" d="M100 100 l-100 -100"/>
<path stroke="white" stroke-width="5" d="M100 100 l100 -100"/>
</svg>
</div>
Вариант с масками
Тут для бордера используется другая фигура, с большей толщиной линии, от которой маской мы отрезаем ненужное:
<body style="margin:0; overflow:hidden">
<svg height="200" width="640">
<defs>
<mask id="m">
<rect width="100%" height="100%" fill="white"/>
<path stroke="black" stroke-width="2" d="M100 100 l100 -100"/>
<path stroke="black" stroke-width="2" d="M100 100 l-100 -100"/>
<path fill="black" d="M100 100 l-115 100 l115 100 l115 -100z"/>
</mask>
</defs>
<g>
<circle fill="none" stroke-width="25" stroke="#999" r="77" cx="100" cy="100"/>
</g>
<g transform="translate(220,0)">
<rect width="100%" height="100%" fill="white"/>
<path stroke="black" stroke-width="2" d="M100 100 l100 -100"/>
<path stroke="black" stroke-width="2" d="M100 100 l-100 -100"/>
<path fill="black" d="M100 100 l-115 100 l230 0z"/>
</g>
<g transform="translate(440,0)">
<circle mask="url(#m)"fill="none" stroke-width="25" stroke="#999" r="77" cx="100" cy="100"/>
</g>
<text text-anchor="middle" alignment-baseline="central" font-size=55 x=210 y=100>+</text>
<text text-anchor="middle" alignment-baseline="central" font-size=55 x=420 y=100>=</text>
</svg>
</body>
Результат:
let meter = document.querySelector('path.meter');
let text = document.querySelector('text');
let arrow = document.querySelector('path.arrow');
let length = meter.getTotalLength();
requestAnimationFrame(draw)
function draw(dt) {
progress(dt / 100 % 100);
requestAnimationFrame(draw)
}
function progress(value) {
meter.setAttribute('stroke-dasharray', `${length/100*value}, ${length}`);
arrow.setAttribute('transform', `rotate(${-135+value*270/100} 100,100)`);
text.innerHTML = Math.round(value);
}
<svg height="175" viewBox="0 0 200 200">
<defs>
<mask id="mask1">
<rect width="100%" height="100%" fill="white"/>
<path stroke="black" stroke-width="2" d="M100 100 l100 -100"/>
<path stroke="black" stroke-width="2" d="M100 100 l-100 -100"/>
<path fill="black" d="M100 100 l-115 100 l230 0z"/>
</mask>
<mask id="mask2">
<rect width="100%" height="100%" fill="white"/>
<path stroke="black" stroke-width="5" d="M100 100 l100 -100"/>
<path stroke="black" stroke-width="5" d="M100 100 l-100 -100"/>
</mask>
</defs>
<g fill="none">
<circle mask="url(#mask1)" stroke-width="25" stroke="#999" r="77" cx="100" cy="100"/>
<path mask="url(#mask2)" stroke-width="22" stroke="#ccc" d="M41 149.5a77 77 0 1 1 117.93 0"/>
<path mask="url(#mask2)" stroke-width="22" stroke="#d15f45" d="M41 149.5a77 77 0 1 1 117.93 0" class="meter"/>
<circle stroke-width="7" stroke="#ccc" r="33" cx="100" cy="100"/>
</g>
<text x="100" y="100" font-family="arial" font-size="22px" text-anchor="middle" alignment-baseline="central">0</text>
<path class="arrow" transform="rotate(-135 100,100)" fill="#ccc" d="M100,65 l5,0 l-5,-10 l-5,10"></path>
</svg>
UPD: сделал как в вопросе, с циферками и стрелочкой
У заданного пути максимальная длина равна 350px
Если нужно поделить на три равных сектора, то длина одного сектора будет равна 116.67px
Это сумма длин: черты - 110px
и пробела 6.67px
<svg xmlns="http://www.w3.org/2000/svg" height="200" width="200" viewBox="0 0 200 200" data-value="40">
<path class="bg" stroke="#ccc" stroke-width="20" stroke-dasharray="110 6.67"
d="M41 149.5a77 77 0 1 1 117.93 0" fill="none"/>
</svg>
Более подробно, как делить окружности на равные части с помощью stroke-dasharray
здесь и здесь
Анимация заполнения первого сектора основана на изменении значения длины черты от нуля до максимального значения 110px
<animate id="an1" attributeName="stroke-dasharray" begin="0s;an3.end" values="0 110 0 240;110 0 0 240" dur="2s" fill="freeze" />
Точно также заполняются по очереди остальные 2 сектора.
Я сделал сектора разного цвета, при необходимости можно присвоить один цвет.
<svg xmlns="http://www.w3.org/2000/svg" height="200" width="200" viewBox="0 0 200 200" data-value="40">
<path class="bg" stroke="#ccc" stroke-width="20" stroke-dasharray="110 6.67"
d="M41 149.5a77 77 0 1 1 117.93 0" fill="none"/>
<path class="meter" stroke="green" stroke-width="20"
d="M41 149.5a77 77 0 1 1 117.93 0" fill="none" stroke-dasharray="0 350" stroke-dashoffset="0" >
<! анимация заполнения зелёного сектора -->
<animate id="an1"
attributeName="stroke-dasharray"
begin="0s;an3.end"
values="0 110 0 240;110 0 0 240"
dur="2s"
fill="freeze" />
</path>
<! анимация заполнения жёлтого сектора -->
<path class="meter" stroke="gold" stroke-width="20"
d="M41 149.5a77 77 0 1 1 117.93 0" fill="none" stroke-dasharray="0 350" stroke-dashoffset="0" >
<animate id="an2"
attributeName="stroke-dasharray"
begin="an1.end"
values="0 116.67 0 110 0 116.67;0 116.67 110 0 0 116.67"
dur="2s"
fill="freeze" />
</path>
<! анимация заполнения красного сектора -->
<path class="meter" stroke="red" stroke-width="20"
d="M41 149.5a77 77 0 1 1 117.93 0" fill="none" stroke-dasharray="0 350" stroke-dashoffset="0" >
<animate id="an3"
attributeName="stroke-dasharray"
begin="an2.end"
values="0 116.67 0 116.67 0 116.67;0 116.67 0 116.67 110 0"
dur="2s"
fill="freeze" />
</path>
</svg>
<animateTransform id="an_arrow" attributeName="transform" type="rotate" values="-10 100 100;255 100 100" dur="6s" repeatCount="indefinite" fill="freeze" />
<svg xmlns="http://www.w3.org/2000/svg" height="200" width="200" viewBox="0 0 200 200" data-value="40">
<path class="bg" stroke="#ccc" stroke-width="20" stroke-dasharray="110 6.67"
d="M41 149.5a77 77 0 1 1 117.93 0" fill="none"/>
<path class="meter" stroke="green" stroke-width="20"
d="M41 149.5a77 77 0 1 1 117.93 0" fill="none" stroke-dasharray="0 350" stroke-dashoffset="0" >
<! анимация заполнения зелёного сектора -->
<animate id="an1"
attributeName="stroke-dasharray"
begin="0s;an3.end"
values="0 110 0 240;110 0 0 240"
dur="2s"
fill="freeze" />
</path>
<! анимация заполнения жёлтого сектора -->
<path class="meter" stroke="gold" stroke-width="20"
d="M41 149.5a77 77 0 1 1 117.93 0" fill="none" stroke-dasharray="0 350" stroke-dashoffset="0" >
<animate id="an2"
attributeName="stroke-dasharray"
begin="an1.end"
values="0 116.67 0 110 0 116.67;0 116.67 110 0 0 116.67" dur="2s"
fill="freeze" />
</path>
<! анимация заполнения красного сектора -->
<path class="meter" stroke="red" stroke-width="20"
d="M41 149.5a77 77 0 1 1 117.93 0" fill="none" stroke-dasharray="0 350" stroke-dashoffset="0" >
<animate id="an3"
attributeName="stroke-dasharray"
begin="an2.end"
values="0 116.67 0 116.67 0 116.67;0 116.67 0 116.67 110 0"
dur="2s"
fill="freeze" />
</path>
<circle cx="100" cy="100" r="50" fill="none" stroke-width="4" stroke="silver" />
<path d="m62.4 134.1c0 2.8 13.6 7.4-2.6 5-2.7-0.4-10.7-0.2-10.7-0.2 0 0 4-13.1 4.1-19.1 0.1-6 9.2 11.5 9.2 14.3z" fill="silver">
<animateTransform id="an_arrow"
attributeName="transform"
type="rotate"
values="-10 100 100;255 100 100"
dur="6s"
repeatCount="indefinite"
fill="freeze" />
</path>
<circle cx="100" cy="100" r="3" fill="#8E8E8E" />
</svg>
Ссылки на связанные топики c заполнением прогрессбара и выводом процентов:
Круговой прогресс бар
Круговой процентный прогресс бар
Круглый векторный индикатор прогресса
Практические примеры применения масок svg
Взяв за основу ответы Stranger in the Q
и Alexander_TT
, получил итог, который работает как необходимо в условиях моего проекта.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="radial">
<svg xmlns="http://www.w3.org/2000/svg" height="200" width="200" viewBox="0 0 200 200" data-value="40">
<defs>
<mask id="mask1">
<rect width="100%" height="100%" fill="white"/>
<path stroke="black" stroke-width="2" d="M100 100 l100 -100"/>
<path stroke="black" stroke-width="2" d="M100 100 l-100 -100"/>
<path fill="black" d="M100 100 l-115 100 l115 100 l115 -100z"/>
</mask>
<mask id="mask2">
<rect width="100%" height="100%" fill="white"/>
<path stroke="black" stroke-width="5" d="M100 100 l100 -100"/>
<path stroke="black" stroke-width="5" d="M100 100 l-100 -100"/>
</mask>
</defs>
<circle mask="url(#mask1)" fill="none" stroke-width="25" stroke="#bfb09d" r="77" cx="100" cy="100"/>
<path mask="url(#mask2)" fill="none" stroke-width="22" stroke="#FFF" d="M41 149.5a77 77 0 1 1 117.93 0"/>
<path mask="url(#mask2)" fill="none" stroke-width="22" stroke="#D15F45" d="M41 149.5a77 77 0 1 1 117.93 0" class="meter" pathLength="30" stroke-dasharray="22, 999">
<animate id="an1" attributeName="stroke-dasharray" from="0 0" to="22 999" dur="1s" repeatCount="0" fill="freeze" />
</path>
<circle cx="100" cy="100" r="50" fill="none" stroke-width="4" stroke="#bfb09d" class="arrow-circle"/>
<path d="m62.4 134.1c0 2.8 13.6 7.4-2.6 5-2.7-0.4-10.7-0.2-10.7-0.2 0 0 4-13.1 4.1-19.1 0.1-6 9.2 11.5 9.2 14.3z" fill="#bfb09d">
<animateTransform id="an_arrow" attributeName="transform" type="rotate" from="-10 100 100" to="186 100 100" dur="1s" repeatCount="0" fill="freeze" />
</path>
<text font-size="36px" x="100" y="100" fill="#D15F45" text-anchor="middle" alignment-baseline="central">22</text>
</svg>
</div>
Данные для атрибутов(в примере хардкодом заданы pathLength = 30
и currentVal = 22
).
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Хотел проверить с помощью js наличие куки на страничкепри правильном вводе данных в логине и пароле - куки создаются без проблем, но скрипт...
Решил поэкспериментировать с Vue, прочитал-узнал, что есть роутинг, решил попробовать, но, к сожалению, на select он не работаетЗадача была такая,...
хочу сделать так чтобы при нажатии на параграф вызывалась функция в которой прописано действиено почему то она не хочет работать