Создание отображения таймера 30 с с помощью SVG и JS - PullRequest
1 голос
/ 21 марта 2019

Я пытаюсь создать дисплей таймера обратного отсчета 30 с, используя SVG и точку JS. Идея проста

  1. Нарисуйте лицо часов обратного отсчета в виде круга SVG
  2. Внутри него нарисуйте замкнутый путь SVG в виде сектора круга
  3. Используйте window.requestAnimationFrame, чтобы обновить этот сектор с интервалом в одну секунду

Мое усилие показано ниже. Хотя это работает, конечный результат далеко не гладкий и убедительный.

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

Что я здесь не так делаю и как это можно улучшить?

var _hold = {tickStart:0,stopTime:30,lastDelta:0};

String.prototype.format = function (args)
{
 var newStr = this,key;
 for (key in args) {newStr = newStr.replace('{' + key + '}',args[key]);}
 return newStr;
};

Boolean.prototype.intval = function(places)
{
 places = ('undefined' == typeof(places))?0:places; 
 return (~~this) << places;
};


function adjustSpent(timeStamp)
{
 if (0 === _hold.tickStart) _hold.tickStart = timeStamp;
 var delta = Math.trunc((timeStamp - _hold.tickStart)/1000);
 if (_hold.lastDelta < delta)
 {
  _hold.lastDelta = delta;
  var angle = 2*Math.PI*(delta/_hold.stopTime),
      dAngle = 57.2958*angle,
      cx = cy = 50,
      radius = 38,
      top = 12,
      x = cx + radius*Math.sin(angle),
      y = cy - radius*Math.cos(angle),
      large = (180 < dAngle).intval();
  
   var d = (360 <= dAngle)?"M50,50 L50,12 A38,38 1 0,1 51,12 z":"M50,50 L50,12 A38,38 1 {ll},1 {xx},{yy} z".format({ll:large,xx:x,yy:y});
   var spent = document.getElementById('spent');    
   if (spent) spent.setAttribute("d",d);
 }
 if (delta < _hold.stopTime) window.requestAnimationFrame(adjustSpent);
}

window.requestAnimationFrame(adjustSpent);
timer
{
 position:absolute;
 height:20vh;
 width:20vh;
 border-radius:100%;
 background-color:orange;
 left:calc(50vw - 5vh);
 top:15vh;
}

#clockface{fill:white;}
#spent{fill:#6683C2;}
<timer>
     <svg width="20vh" height="20vh" viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="38" id="clockface"></circle>
      <path d="M50,50 L50,12 A38,38 1 0,1 51,12 z" id="spent"></path>
     </svg>
    </timer>

1 Ответ

1 голос
/ 21 марта 2019

В качестве возможного решения можно использовать анимацию обводки, например:

Синий круг имеет радиус 38/2 = 19

stroke-width синего круга - 38, создающий иллюзиюкруга 38 единиц.

Пожалуйста, посмотрите на путь: это также круг радиуса = 19.

svg {
  border: 1px solid;
  height:90vh;
}
#clockface {
  fill: silver;
}
#spent {
  fill:none;
  stroke: #6683c2;
  stroke-width: 38px;
  stroke-dasharray: 119.397px;
  stroke-dashoffset: 119.397px;
  animation: dash 5s linear infinite;
}
  

@keyframes dash {
  to {
    stroke-dashoffset: 0;
  }
}
<svg  viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="38" id="clockface"></circle>
      <path d="M50,31 A19,19 1 0,1 50,69 A19,19 1 0,1 50,31" id="spent"></path>
     </svg>

В этом случае я использовал анимацию CSS, но вы можете контролировать значение для stroke-dashoffset с помощью JavaScript.

Значение для stroke-dasharray было получено с использованием spent.getTotalLength()

Если вы не знакомы с анимацией штрихов в SVG, прочитайте Как работает линейная анимация SVG

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...