【问题标题】:SVG animations: sluggish/poor performance in ChromeSVG 动画:Chrome 中的迟缓/性能不佳
【发布时间】:2019-04-23 06:37:35
【问题描述】:

我们正在开发一个相当复杂的场景,其中包含很多移动部件,到目前为止还没有涉及任何 SVG 动画。

一切都很顺利并且表现良好,直到我们引入了一个带有几条虚线的 SVG,我们使用 stroke-dashoffset 属性对其进行动画处理。

在 Edge 或 Firefox 中完全没有区别,但在 Chrome 中,整个场景的动画变得不稳定且缓慢。

我们甚至尝试了这两种方法来达到相同的目的——CSS 关键帧和 SVG 元素中的 SMIL——但两者的表现都一样差。

我们是否缺少 Chrome 的性能技巧?

编辑:示例

标记:

.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>

【问题讨论】:

  • 你在使用 requestAnimationFrame 吗?
  • 有要重现的例子吗?
  • 我们使用 requestAnimationFrame 处理任何 JS 动画,是的。 SVG 动画使用 SMIL 或 CSS(两者都很迟钝),因此不适用于那里。
  • 无论如何,您都可以将您的 css 重构为 js 动画,这样您就可以从性能优化中受益,而 css 不能做很多事情,尤其是当您不显示示例时。
  • 你主要使用transition还是transform?

标签: javascript css performance animation svg


【解决方案1】:

您可以简单地使用animation-timing-function: steps(n) 来代替the JavaScript approach given by Mila Nautikus 来达到相同的效果。将n 设置为m * (how many stroke-dashoffset changed during an animation loop) 以获得更流畅的动画,例如:

.stream {
  animation: stream 0.5s steps(14) infinite;
}

@keyframes stream {
  100% {
    stroke-dashoffset: 7;
  }
}
<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>

【讨论】:

    【解决方案2】:

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

    这里真正的问题是糟糕的 svg 实现,请参阅 chrome bug

    一种解决方法确实可以通过 javascript 动画降低帧速率,请参阅代码示例

    这个特殊情况可以用虚线圆圈和 css transform: rotate3d() 来完成。而且“GPU 变换”翻译/旋转在当今的 svg 实现中表现不佳。解决方法:将 svg 代码包装在 &lt;div&gt; 中并为 div 设置动画,瞧! cpu 降为零。相关: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>

    【讨论】:

      【解决方案3】:

      您需要将动画上的 ease 设置为 linear。运行下面的 sn-p 以查看它在运行时不会出现那种大块的减速。

      .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>

      【讨论】:

      • 这并没有解决缓慢的问题(我做了另一个改变,虽然我不确定是什么!)但它确实让动画变得更好,所以谢谢你的提示!
      • @Geat 你有没有弄清楚是什么改变了延迟,你还记得它是什么吗?我在动画 stroke-dashoffset 时遇到了同样的问题......
      猜你喜欢
      • 2015-11-28
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-03
      • 1970-01-01
      • 1970-01-01
      • 2013-02-24
      相关资源
      最近更新 更多