Анимация прогресс-бара

104
22 июня 2021, 17:00

Я пытаюсь сделать анимацию прогресс-бара https://codepen.io/mihail-kamahin/pen/YzKZjWd
Я хочу сделать так, чтобы из одной точки круга анимация начиналась сразу с двух сторон, на картинке я показал схематично, как я хотел это сделать

Но у меня не получается, я пытался ещё один круг создавать, поверх уже созданного, но получается какая-то каша. Кто уже работал с кругами на svg, возможно, знаете, как это сделать?

function setProgress(percent, selector__circle) { 
  const circle = document.querySelector(`${selector__circle}`); 
  const radius = circle.r.baseVal.value; 
  const circumference = 2 * Math.PI * radius; 
 
  circle.style.strokeDasharray = `${circumference} ${circumference}`; 
  circle.style.strokeDashoffset = circumference; 
 
  const offset = circumference - percent / 100 * circumference; 
  circle.style.strokeDashoffset = offset; 
} 
 
var number = 125; 
 
setProgress(number, '.progressbar__thumb'); 
 
click__me = document.querySelector('.click__me'); 
 
click__me.addEventListener('click', function() { 
  setProgress(number += 25, '.progressbar__thumb'); 
});
.progress__container { 
  width: 140px; 
  height: 140px; 
} 
 
.progressbar__track { 
  fill: transparent; 
  stroke: #3E4153; 
  stroke-width: 3px; 
} 
 
.progressbar__thumb { 
  fill: transparent; 
  stroke: yellow; 
  stroke-width: 4px; 
  transform: rotate(270deg); 
  transform-origin: center; 
  transition: 0.5s linear; 
} 
 
.click__me { 
  margin-top: 30px; 
  margin-left: 30px; 
}
<div class="progress__container"> 
  <svg class="progressbar" viewbox="0 0 64 64"> 
    <circle class="progressbar__track" cx="50%" cy="50%" r="30">         </circle> 
    <circle class="progressbar__thumb" cx="50%" cy="50%" r="30">         </circle> 
  </svg> 
</div> 
 
<button class="click__me">Click me</button>

Answer 1

Все можно сделать за счет одного лишь stroke-dasharray, корректно посчитав длины:

function setProgress(percent, selector__circle) { 
  const circle = document.querySelector(selector__circle); 
  const total = Math.PI * circle.r.baseVal.value; 
  circle.style.strokeDasharray = `${total*percent} ${total*(1-percent)*2}`; 
  document.querySelector('svg text').innerHTML = (percent*100).toFixed(0) + '%'; 
} 
 
var number = 0; 
 
setProgress(number, '.progressbar__thumb'); 
 
document.querySelector('.click__me').addEventListener('click', function() { 
  setProgress(number = number+0.1 > 1 ? 0 : number+0.1, '.progressbar__thumb'); 
});
.progress__container { 
	width: 140px; 
	height: 140px; 
} 
 
.progressbar__track { 
	fill: transparent; 
	stroke: #3E4153; 
	stroke-width: 3px; 
} 
 
.progressbar__thumb { 
  transform: 
    translate(32px,32px) 
    rotate(180deg) 
    translate(-32px,-32px); 
	fill: transparent; 
	stroke: yellow; 
	stroke-width: 4px; 
	transition: 0.2s; 
} 
 
.click__me { 
  margin-top: 10px; 
  margin-left: 35px; 
}
<div class="progress__container"> 
  <svg class="progressbar" viewbox="0 0 64 64"> 
    <circle class="progressbar__track" cx="50%" cy="50%" r="30"></circle> 
    <circle class="progressbar__thumb" cx="50%" cy="50%" r="30"></circle> 
    <text x=32 y=32 text-anchor=middle dominant-baseline=middle></text> 
  </svg> 
</div> 
 
<button class="click__me">Click me</button>

Answer 2

Как я понял из рисунка, - анимация прогресс бара должна начинаться из одной точки синхронно двумя линиями и заканчиваться тоже в одной точке.

Расчет цифр в атрибуте stroke-dasharray

При радиусе окружности r="100" длина окружности равна C= 2 * PI * R = 628,3

Половина окружности равна 314,15

Анимация линии достигается с помощью увеличения черты от нуля до максимума - 628,3

У атрибута stroke-dasharray первый параметр это длина черты, второй параметр это длина пробела, поэтому:

Чтобы получить в начале нулевую длину черты записываем:
stroke-dasharray="0 314.15 0 314.15"

Длина черты 0 длина пробела -314.15 длина черты 0 длина пробела -314.15, в итоге линию не будет видно.

Для максимального значения видимости линии нужно убрать пробелы :

stroke-dasharray=0 0 628.3 0

Для анимации линии записываем в values эти два значения stroke-dasharray

values="0 314.15 0 314.15;0 0 628.3 0"

var btn = document.getElementById('btn'); 
var anim = document.getElementById('an'); 
btn.onclick = function () { 
      anim.beginElement(); 
}
<button id="btn">Begin</button> 
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"  
    xmlns:xlink="http://www.w3.org/1999/xlink" 
	     width="250" height="250" viewBox="0 0 300 300" >   
	<!-- Серая окружность, показывающая трассировку анимации. При необходимости можно убрать -->	  
<circle cx="150" cy="150" r="100" stroke="#d3d3d3" stroke-width="6" fill="none" /> 
   <!-- Окружность, реализующая прогресс бар --> 
<circle cx="150" cy="150" r="100" stroke="purple" stroke-width="6" fill="none" stroke-dasharray="0 628.3" > 
  <animate id="an" 
        attributeName="stroke-dasharray" 
		values="0 314.15 0 314.15;0 0 628.3 0" 
		begin="indefinite" 
		dur="4s" 
		fill="freeze"/>  
 </circle> 
</svg>	 

Ещё пример основанный на этой технике

.container 
{ 
width:50%; 
height:50%;   
 background:black; 
}
<div class="container"> 
<svg xmlns="http://www.w3.org/2000/svg"  viewBox="0 0 100 100"> 
   
  <path fill="none" d="M24.3 30C11.4 30 5 43.3 5 50s6.4 20 19.3 20c19.3 0 32.1-40 51.4-40C88.6 30 95 43.3 95 50s-6.4 20-19.3 20C56.4 70 43.6 30 24.3 30z" stroke="#d3d3d3" stroke-width="10"  />   
       <!-- Средняя точка начала анимации в центре слева stroke-dashoffset="31.1" --> 
	<path id="center" fill="none" d="M24.3 30C11.4 30 5 43.3 5 50s6.4 20 19.3 20c19.3 0 32.1-40 51.4-40C88.6 30 95 43.3 95 50s-6.4 20-19.3 20C56.4 70 43.6 30 24.3 30z" stroke="crimson" stroke-width="10" stroke-dashoffset="31.1" stroke-dasharray="0 128.5" >   
      <animate  attributeName="stroke-dasharray" values="0 128.5 0 128.5;0 0 257 0" begin="btn_C.click" dur="4s" restart="whenNotActive" />  
	</path>  
	  <!-- Средняя точка слева stroke-dashoffset="-159.5" --> 
	    <path id="Left" fill="none" d="M24.3 30C11.4 30 5 43.3 5 50s6.4 20 19.3 20c19.3 0 32.1-40 51.4-40C88.6 30 95 43.3 95 50s-6.4 20-19.3 20C56.4 70 43.6 30 24.3 30z" stroke="yellowgreen" stroke-width="10" stroke-dashoffset="-159.5" stroke-dasharray="0 128.5" >   
      <animate attributeName="stroke-dasharray" values="0 128.5 0 128.5;0 0 257 0" begin="btn_L.click" dur="4s"  restart="whenNotActive" />  
	</path>   
	 
	   <!-- Средняя точка слева сверху stroke-dashoffset="128.5" --> 
	    <path id="Top" fill="none" d="M24.3 30C11.4 30 5 43.3 5 50s6.4 20 19.3 20c19.3 0 32.1-40 51.4-40C88.6 30 95 43.3 95 50s-6.4 20-19.3 20C56.4 70 43.6 30 24.3 30z" stroke="gold" stroke-width="10" stroke-dashoffset="128.5" stroke-dasharray="0 128.5" >   
      <animate attributeName="stroke-dasharray" values="0 128.5 0 128.5;0 0 257 0" begin="btn_T.click" dur="4s"  restart="whenNotActive" />  
	</path>  
	    <!-- Средняя точка справа внизу  stroke-dashoffset="192.7" --> 
	 <path id="Bottom" fill="none" d="M24.3 30C11.4 30 5 43.3 5 50s6.4 20 19.3 20c19.3 0 32.1-40 51.4-40C88.6 30 95 43.3 95 50s-6.4 20-19.3 20C56.4 70 43.6 30 24.3 30z" stroke="dodgerblue" stroke-width="10" stroke-dashoffset="192.7" stroke-dasharray="0 128.5" >   
      <animate attributeName="stroke-dasharray" values="0 128.5 0 128.5;0 0 257 0" begin="btn_B.click" dur="4s"  restart="whenNotActive" />  
	</path>    
	 
	       <!-- Средняя точка справа   stroke-dashoffset="223.9" --> 
	 <path id="Bottom" fill="none" d="M24.3 30C11.4 30 5 43.3 5 50s6.4 20 19.3 20c19.3 0 32.1-40 51.4-40C88.6 30 95 43.3 95 50s-6.4 20-19.3 20C56.4 70 43.6 30 24.3 30z" stroke="purple" stroke-width="10" stroke-dashoffset="223.9" stroke-dasharray="0 128.5" >   
      <animate attributeName="stroke-dasharray" values="0 128.5 0 128.5;0 0 257 0" begin="btn_R.click" dur="4s"  restart="whenNotActive" />  
	</path>  
	 
	 
	 
 <g id="btn_L" transform="translate(-17 0)" > 
      <rect x="20" y="84" width="15" height="15" rx="7.5" fill="none" stroke="#B2B2B2"/> 
	     <text x="25" y="95" font-size="10" fill="green" >L</text> 
    </g> 	 
	<g id="btn_C" transform="translate(3 0)"> 
      <rect x="20" y="84" width="15" height="15" rx="7.5" fill="none" stroke="#B2B2B2"/> 
	     <text x="24" y="95" font-size="10" fill="crimson" >C</text> 
    </g>  
	    
	    <g id="btn_T" transform="translate(23 0)" > 
      <rect x="20" y="84" width="15" height="15" rx="7.5" fill="none" stroke="dodgerblue"/> 
	     <text x="24" y="95" font-size="10" fill="orange" >T</text> 
        </g>   
  <g id="btn_B" transform="translate(43 0)"> 
	<rect x="20" y="84" width="15" height="15" rx="7.5" fill="none" stroke="#B2B2B2"/> 
	 <text x="25" y="95" font-size="10" fill="dodgerblue" >B</text> 
  </g>	   
      <g id="btn_R" transform="translate(63 0)"> 
	    <rect x="20" y="84" width="15" height="15" rx="7.5" fill="none" stroke="#B2B2B2"/> 
	      <text x="25" y="95" font-size="10" fill="purple" >R</text> 
    </g>	 
</svg> 
</div>

READ ALSO
Последовательное выполнение задач

Последовательное выполнение задач

Есть две Gulp задачиКогда я пытаюсь ввести предвыполнение pug:data перед pug, выполняется только pug:data

77
Как это называется в JS?

Как это называется в JS?

с JS знаком очень мало, в основном пытался что нибудь делать на JQКак это реализовать

116
Как при выборе темы оформления сохранять выбор через cookie?

Как при выборе темы оформления сохранять выбор через cookie?

У меня есть простой сайт и на нём я хочу предоставить юзерам возможность менять темы оформления, к примеру есть три файла:

86
Убрать повторяющийся тег

Убрать повторяющийся тег

Как можно скриптом убрать тег <br>, если подряд идут два?

111