Snap.svg 中包含大量元素时性能不佳

Poor performance in Snap.svg with lots of elements

我希望使用 Snap.svg.

为很多元素制作动画

我正在创建一个由模型支持的可视化。出于这个原因,我懒得使用 Snap.animate,而是只是在每个 animationFrame.

上设置每个元素的位置

为了移动每个元素,我遍历元素列表并调用 el.transform

当我开始需要转换超过几百个元素时,这个过程开始需要很长时间。

两个示例 Fiddles 展示了这一点:

  1. http://jsfiddle.net/zfw78n85/:取消注释行设置totalCircles = 500
  2. http://jsfiddle.net/9o0qswsb/:请注意,几秒钟后,setInterval 计时器如何开始占用一秒,最终需要 10 秒或更长时间。

我假设问题是因为它试图在每个 requestAnimationFrame 之间多次修改 DOM。查看 Chrome 中的时间线似乎证实了这一点——我看到在每一帧中有很多对 render 的调用。

有没有办法提高效率?也许要批量处理所有转换,以便我们只更新 DOM 一次?

确实有几个问题。感觉这个方法首先有点不对,但最终我不知道更大的项目或图片。

首先,像 Snap 这样的库存在的原因是为了让 SVG 更容易,而不是更快。他们将考虑诸如自上次 requestAnimationFrame 以来的时间之类的事情,并根据该增量移动元素(否则它会减慢速度并加快速度,即使只是一点点,也许你会接受的)。因此,如果您不使用它并且担心性能,感觉有点像是您选择了错误的库。但是,您可能还需要其他好处,所以我正在写我可能会做的事情。

所以如果我们看一下这个例子,会减慢速度的地方之一是创建矩阵或检查现有的转换等。如果只有一位,重复调用,最好是本地化

因此您可以将 movefunc 更改为如下所示(使用 data() 存储数据以供下一个循环重用),然后设置翻译跳过任何额外的库方法。

function moveCircle(circ) {
  circ.data('x', circ.data('x')+1 || 1);
  circ.node.setAttribute('transform', 'translate('+circ.data('x')+')')
}

jsfiddle

您可能会发现它的性能会好一些,但同样,可能会 slow/speed 提高,具体取决于系统正在执行的操作。如果您出于某种原因总是想要精确的增量,这可能是需要的。

编辑:转换变慢的主要原因是它在幕后执行额外的辅助函数。例如,我认为它会计算一个边界框,以防您想围绕中心旋转(例如 'r90' 会这样做,因为 Snap 默认情况下会这样做来帮助您,因为大多数人都想围绕中心旋转) .我认为如果你传递适当的 svg 转换,例如 'translate(20,20)',肯定有一个避免额外帮助的东西的争论,但可能仍然有额外的处理来打破这一切,即使不是那么多。

如果我经常这样做,我可能会想编写自己的原生 attr 插件,比如,w...

Snap.plugin( function( Snap, Element, Paper, global ) {
    Element.prototype.nativeAttrs = function( attrs ) {
        for (var p in attrs)
            this.node.setAttributeNS(null, p, attrs[p]);
        return this;
    }
});   

circ.nativeAttrs({ 'transform': 'translate('+circ.data('x')+')'}); 

jsfiddle