我已经通过代码https://bl.ocks.org/mbostock/1705868进行了'point-along-path'd3可视化。我注意到,当该点沿其路径移动时,它会消耗7-11%的CPU使用率。
在当前情况下,我大约有100条路径,并且在每条路径上,我都必须将点(圆)从源移动到目标。因此,随着更多点同时移动,它消耗了90%以上的CPU内存。
我尝试过:
function translateAlong(path) {
var l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
var p = path.getPointAtLength(t * l);
return "translate(" + p.x + "," + p.y + ")";
};
};
}
// On each path(100 paths), we are moving circles from source to destination.
var movingCircle = mapNode.append('circle')
.attr('r', 2)
.attr('fill', 'white')
movingCircle.transition()
.duration(10000)
.ease("linear")
.attrTween("transform", translateAlong(path.node()))
.each("end", function() {
this.remove();
});
那么减少CPU使用率的更好方法应该是什么? 谢谢。
答案 0 :(得分:3)
发布修改:
我平均快5倍。
我认为这里的瓶颈是每17毫秒对getPointAtLength
方法的调用。如果需要的话,我也将避免冗长的字符串连接,但是在您的情况下,它的使用时间不长,所以我认为是最好的方法:
在默认情况下,有2个呼叫,在呼叫getPointAtLength
时有1个,而在设置translate(在后台)时有1个。
您可以将translateAlong
替换为以下内容:
function translateAlong(path){
var points = path.__points || collectPoints(path);
return function (d,i){
var transformObj = this.transform.baseVal[0];
return function(t){
var index = t * 1000 | 0,
point = points[index];
transformObj.setTranslate(point[0],point[1]);
}
}
}
function collectPoints(path) {
var l = path.getTotalLength(),
step = l*1e-3,
points = [];
for(var i = 0,p;i<=1000;++i){
p = path.getPointAtLength(i*step);
points.push([p.x,p.y]);
}
return path.__points = points;
}
对补间线进行了小的修改:
.tween("transform", translateAlong(path.node()))
不需要设置attr,调用它就足够了。结果如下:
http://jsfiddle.net/ibowankenobi/8kx04y29/
告诉我是否确实有所改善,因为我不确定100%。
答案 1 :(得分:1)
实现此目标的另一种方法可能是使用svg:animateMotion,您可以使用该docs沿给定路径移动元素。这是来自{{3}}的示例。本质上您想要:
<svg>
<path id="path1" d="...">
<circle cx="" cy="" r="10" fill="red">
<animateMotion dur="10s" repeatCount="0">
<mpath xlink:href="#path1" />
</animateMotion>
</circle>
</path>
</svg>
我没有介绍它,但是我认为您要比使用SVG本身内置的东西要难得多。
浏览器支持
请注意,在@ibrahimtanyalcin发表评论后,我开始检查浏览器的兼容性。事实证明,IE或Microsoft Edge不支持此功能。
答案 2 :(得分:-1)
在我的计算机上:
对于@mbostock和@ibrahimtanyalcin,这意味着transition
和transform
更新使用CPU。
如果我将100个这些动画放入1个SVG中,我会得到
所有动画看起来都很流畅。
一种可能性是使用https://stackoverflow.com/a/39914235/9938317在transform
更新功能中添加睡眠
修改
在不错的Andrew Reid answer中,我发现了一些优化方法。
我编写了一个Canvas + JS 100 000测试版本,该测试仅负责计算部分并计算在4000毫秒内可以执行的迭代次数。 order=false
是t
的一半时间。
我已经编写了自己的随机数生成器,以确保每次运行修改后的代码时都得到相同的随机数。
代码的块版本: 200次迭代
根据parseInt的文档
parseInt不应替代
Math.floor()
将数字转换为字符串,然后将字符串解析到.
听起来不是很有效。
用parseInt()
替换Math.floor()
:218次迭代
我还发现一行没有功能并且看起来并不重要
let p = new Int16Array(2);
它在内部while循环中。
用这行代替
let p;
给出 300次迭代。
使用这些修改,代码可以以60 Hz的帧频处理更多点。
我尝试了其他一些方法,但是结果却变慢了。
令我惊讶的是,如果我预先计算段的长度并将segment
的计算简化为单纯的数组查找,它比进行4个数组查找和几个Math.pow
的速度要慢以及添加项和Math.sqrt
。