具有大量元素的Snap.svg性能不佳

时间:2017-05-15 19:52:19

标签: snap.svg

我希望使用Snap.svg动画很多元素。

我正在创建一个由模型支持的可视化。出于这个原因,我并不打算使用Snap.animate,而只是在每个animationFrame上设置每个元素的位置。

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

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

两个示例小提琴显示了这一点:

  1. http://jsfiddle.net/zfw78n85/:取消注释行设置totalCircles = 500
  2. http://jsfiddle.net/9o0qswsb/:请注意,几秒钟之后,setInterval计时器开始占用一秒钟,最终需要10秒或更长时间。
  3. 我假设问题是因为它试图在每个requestAnimationFrame之间多次修改DOM。查看Chrome中的时间轴似乎可以确认这一点 - 我看到每个帧中都有render的大量来电。

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

1 个答案:

答案 0 :(得分:1)

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

首先,像Snap这样的库存在的原因是使SVG更容易,而不是更快。他们将考虑自上次requestAnimationFrame以来的时间长度,并根据该delta移动一个元素(否则它会减慢并加速,即使只是一点点,也许你会好的)。因此,如果你没有使用它并且你对性能感到困扰,感觉有点像你可能选择了错误的库。但是,你可能还有其他优点,所以我正在写下我可能会做的事情。

因此,如果我们看一下这个例子,其中一个会减慢速度的地方就是创建矩阵或检查现有的变换等。如果只有一个位,那就是重复调用,那么最好用它来生成

因此,您可以将movefunc更改为类似以下内容(使用data()存储数据以便在下一个周期重用),然后设置translate跳过任何额外的库方法。

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

jsfiddle

您可能会发现这会更好一些,但同样可能会减慢/加速,具体取决于系统正在做什么。如果由于某种原因总是想要精确增量,那么这可能是理想的。

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

如果我这么做的话,我可能会想要编写我自己的原生attr插件,比如,... ...

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