Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG animations: sluggish/poor performance in Chrome

We're developing a fairly complex scene with a lot of moving parts, which up until now didn't involve any SVG animation.

Everything has been smooth and performing well, until we introduced an SVG with a few dashed lines that we animated using the stroke-dashoffset property.

It makes absolutely no difference in Edge or Firefox, but in Chrome the animation of the entire scene becomes choppy and sluggish.

We've even tried both means to the same end - CSS keyframes and SMIL inside the SVG element - but both perform equally poorly.

Is there a performance trick for Chrome that we're missing?

Edit: Example

Markup:

.stream {
  animation: stream 10s infinite;
}

@keyframes stream {
  100% {
    stroke-dashoffset: 100;
  }
}
<svg version="1.0" id="streams" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 225.32 66.19" enable-background="new 0 0 225.32 66.19" xml:space="preserve">
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M107.38,50.54c0,0-6.78-84.52-106.51-22.2" />
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M110.49,45.31c-0.63-13.01-4.56-44.87-27.83-43.8c-27.6,1.27-37.33,39.66-38.49,60.34"/>
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M180.63,59.88c-0.69-9.65-3.6-30.18-15.76-45.51C148.44-6.34,131.85,2.22,128.87,5c-2.89,2.7-12.81,7.14-14.28,42"/>
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M118.59,45.41c2.4-10.18,9.9-31.97,30.87-37.59c26.03-6.98,55.13,9.32,72.02,19.37"/>
</svg>
like image 530
Geat Avatar asked Nov 20 '18 18:11

Geat


2 Answers

duplicate of How can I animate infinite marker movement down an SVG path without very high CPU usage?

the real problem here are poor svg-implementations, see chrome bug

one workaround does reduce the frame-rate with a javascript animation, see the code sample

this particular case can be done with a dashed circle and css transform: rotate3d(). but also the "GPU transforms" translate/rotate have poor performance in today's svg implementations. workaround: wrap svg code inside a <div> and animate the div, and voila! cpu goes down to zero. related: crmarsh.com/svg-performance

const svg_elem = document.getElementById('streams')

const animateDashTime = 200 // milliseconds
let anim_dash_offset = 0
let animateDashTimer = null

function animateDashStep(){

  anim_dash_offset += 1

  svg_elem.setAttribute('style',
    '--stroke-dashoffset: '+anim_dash_offset);

  // repeat
  animateDashTimer = setTimeout(
    animateDashStep,
    animateDashTime
  )
}

// start
animateDashStep()

// stop
//clearTimeout(animateDashTimer)
<svg version="1.0" id="streams" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 225.32 66.19" enable-background="new 0 0 225.32 66.19" xml:space="preserve" 

  style="--stroke-dashoffset: 0"
>
  <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" 
  
    stroke-dasharray="3,4" 
    stroke-dashoffset="var(--stroke-dashoffset)" 

    d="M107.38,50.54c0,0-6.78-84.52-106.51-22.2"
  />
  <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" stroke-dashoffset="var(--stroke-dashoffset)" d="M110.49,45.31c-0.63-13.01-4.56-44.87-27.83-43.8c-27.6,1.27-37.33,39.66-38.49,60.34"
  />
  <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" stroke-dashoffset="var(--stroke-dashoffset)" d="M180.63,59.88c-0.69-9.65-3.6-30.18-15.76-45.51C148.44-6.34,131.85,2.22,128.87,5c-2.89,2.7-12.81,7.14-14.28,42"/>
  <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" stroke-dashoffset="var(--stroke-dashoffset)" d="M118.59,45.41c2.4-10.18,9.9-31.97,30.87-37.59c26.03-6.98,55.13,9.32,72.02,19.37"/>
</svg>
like image 66
Mila Nautikus Avatar answered Sep 27 '22 21:09

Mila Nautikus


You need to set the ease on your animation to linear. Run the snippet below to see it run without that chunky slow-down.

.stream {
  animation: stream 10s linear infinite;
}

@keyframes stream {
  100% {
    stroke-dashoffset: 100;
  }
}
<svg version="1.0" id="streams" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 225.32 66.19" enable-background="new 0 0 225.32 66.19" xml:space="preserve">
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M107.38,50.54c0,0-6.78-84.52-106.51-22.2" />
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M110.49,45.31c-0.63-13.01-4.56-44.87-27.83-43.8c-27.6,1.27-37.33,39.66-38.49,60.34"/>
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M180.63,59.88c-0.69-9.65-3.6-30.18-15.76-45.51C148.44-6.34,131.85,2.22,128.87,5c-2.89,2.7-12.81,7.14-14.28,42"/>
      <path class="stream" fill="none" stroke="#000" stroke-width="1.75" stroke-linecap="round" stroke-miterlimit="10" stroke-dasharray="3,4" d="M118.59,45.41c2.4-10.18,9.9-31.97,30.87-37.59c26.03-6.98,55.13,9.32,72.02,19.37"/>
</svg>
like image 35
Ted Avatar answered Sep 27 '22 22:09

Ted