Animate-duration is not accurate

I created loading spinner in SVG, but animation-duration is not accurate. For example:

  • 30s animation-duration ~ 26s in real
  • 45s animation-duration ~ 38s in real
  • 60s animation-duration ~ 51s in real

I'm desperate and I don't know where there may be a mistake. Can you help me?

Screen of spinner #1

Screen of spinner #2 - later

<svg class="circle">
  <circle cx="23" cy="23" r="20"/>
</svg>

Less:

@spinnerSize: 46;

svg.spinner {
  display: block;
  width: (@spinnerSize + 0px);
  height: (@spinnerSize + 0px);
  x: 0px;
  y: 0px;
  background: url("../images/ico_timer_small.png") center center no-repeat;

  circle {
    fill: transparent;
    stroke: #027eff;
    stroke-width: 3;
    stroke-dasharray: (3.14 * @spinnerSize);
    transform-origin: (0.5px * @spinnerSize) (0.5px * @spinnerSize) 0;
    transform: rotate(-90deg);
    animation-name: spinner;
    animation-timing-function: linear;
    animation-duration: 30s;
    stroke-linecap: butt;
  }
}

@keyframes spinner {
  from {
    stroke-dashoffset: (3.14 * @spinnerSize);
  }
  to {
    stroke-dashoffset: 0;
  }
}

Answers


The stroke-dasharray value should be equal to the circumference of the circle for this animation to work properly. The circle's radius is only 20 and so the circumference (2 * PI * radius) is equal to 125.66 but in the Less code you have set the diameter (@spinnerSize) as 46 and because of this, the stroke-dasharray has a computed value of 144.44 (greater than circumference of circle).

For a value to go from 0 to 144.44 in 30s, it must be incremented (approximately) by 4.81 per second and so by the time it reaches the 26s mark, the value becomes (26 * 4.81) = 125.81 (approximately). Since this value is greater than the circumference, it looks like the animation has completed ahead of time whereas in reality it is still animating the value until it reaches 144.44.

In the below snippet, I've set 125 as the final value and it runs as expected for 30 seconds. In Less code, you need to calculate stroke-dasharray based on two times the radius of the circle. Do not directly modify the value of @spinnerSize variable because that would modify a few other properties and end up affecting the display of the SVG circle.

svg.spinner {
  display: block;
  width: 46px;
  height: 46px;
  /*x: 0px;
  y: 0px;*/
  background: url("../images/ico_timer_small.png") center center no-repeat;
}
svg.spinner circle {
  fill: transparent;
  stroke: #027eff;
  stroke-width: 3;
  stroke-dasharray: 125;
  transform-origin: 23px 23px 0;
  transform: rotate(-90deg);
  animation-name: spinner;
  animation-timing-function: linear;
  animation-duration: 30s;
  stroke-linecap: butt;
}
@keyframes spinner {
  from {
    stroke-dashoffset: 125;
  }
  to {
    stroke-dashoffset: 0;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<svg class="spinner">
  <circle cx="23" cy="23" r="20" />
</svg>

Need Your Help

How to create a downloadable public link for files on server

linux http ftp

I am afraid my question could be very stupid, and also be duplicate. But I didn't manage to find what I want after looking for some similar questions on this site.

Android InterstitalAd gray small bar bevor the ad

android ads interstitial

Im trying to get a InterstitialAd into my application.