Javascript d3:旋转和力导向布局
当我在d3应用程序中使用旋转勾选功能时,整个应用程序的速度会减慢为爬行 例如:如果取消注释行//var angle=0;在下面的例子中,它的运行速度提高了20倍 为什么会这样?旋转是非常昂贵还是我做错了什么Javascript d3:旋转和力导向布局,javascript,d3.js,rotation,force-layout,Javascript,D3.js,Rotation,Force Layout,当我在d3应用程序中使用旋转勾选功能时,整个应用程序的速度会减慢为爬行 例如:如果取消注释行//var angle=0;在下面的例子中,它的运行速度提高了20倍 为什么会这样?旋转是非常昂贵还是我做错了什么 function tick() { link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", fu
function tick() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
linktext.attr("transform", function(d) {
var xDiff = d.source.x - d.target.x;
var yDiff = d.source.y - d.target.y;
var angle = Math.atan2(yDiff, xDiff) * (180.0 / Math.PI);
//var angle = 0;
return "translate(" + (d.source.x + d.target.x) / 2 + ","
+ (d.source.y + d.target.y) / 2 + ")rotate(" + angle + ")";
});
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
注意:当您执行
//var angle=0时,我修改了找到的原始JSFIDLE代码>此代码的编译器可能会意识到结果是无意义的,并进行了优化,因为它从未更改。这就解释了为什么它在注释代码时运行速度要快20倍
我怀疑,即使保留了平移部分并删除了旋转,它也会变慢(尽管平移的计算成本明显低于旋转,因为与旋转相比,平移只需要3个加法)
虽然我对d3.js不太熟悉,但您现在似乎正在执行一个函数中的平移和旋转,该函数可能会在cpu上被多次调用。(通常你会希望通过一个着色器在gpu上实现这一点,但我不确定这是否适用于d3.js)。为了找出问题的根源,我尝试了使文本的各个方面相同/不同。看见请注意,每个文本元素的文本不同,角度也不同(因此不可能进行优化),但每个元素的角度是恒定的——不会在每个刻度上都改变
结果如何?刚开始有点迟钝(当图形中有很多重叠时),但它很快就会在30帧/秒以下平滑动画
即使文本内容在每一个滴答声中都会发生变化,情况也是如此(最终帧速率略高于30fps),如中所示
这与改变转换应该比改变内容更有效这一观点相矛盾
根据Chrome frame rate inspector,每次重新绘制(在我的计算机上时钟为4fps左右)所消耗的大部分时间都被“绘制设置”步骤占用,即计算图像的每个“层”
。引述:
以下步骤将DOM中的元素渲染为屏幕上的图像:
触发器-元素被加载到DOM中,或者以某种方式被修改
重新计算样式-样式应用于图元(或重新计算)
布局-元素根据其在屏幕上的位置进行几何布局
绘制设置-DOM被分割为渲染层,用于填充每个元素的像素
绘制-每一层都被绘制成位图,并通过软件光栅化器作为纹理上传到GPU
合成层-这些层由GPU合成在一起,并绘制成最终屏幕图像
通常,GPU可以在最后的“合成”步骤中高效地完成转换(现代操作系统上的现代浏览器会自动将工作转移到GPU)
有两个原因导致这种情况可能不会发生。首先,这种优化甚至可能不适用于SVG(尽管我很确定最新Chrome的默认设置是优化SVG转换)。但是,即使浏览器对SVG转换使用了一些GPU优化,您的GPU也只能处理有限数量的层,否则就会耗尽内存。有近200个单独转换的文本元素(以及上面和下面分层的未转换内容),这可能是一个瓶颈。请参阅或,其中给出了一些性能限制的示例,这些限制将抵消独立的层组成
不管引擎盖下发生了什么,最终的结果是你的CPU,而不是GPU,每次都在计算旋转并将文本分层,这是没有效率的
那么,你能做些什么呢?
我尝试通过使用矩阵变换来优化代码,而不是先计算角度,然后让浏览器计算旋转()…但这并没有产生明显的差异。更改为简单的倾斜变换而不是旋转有一点帮助(帧速率高达11fps),但这只是在滞后的动画上添加了难看的文本
不幸的是,看来你真的要以这种或那种方式妥协了。一些选择:
- 隐藏文本,直到强制布局停止,然后才计算旋转
关键代码(Javascript):
CSS:
- 显示文本,但不要旋转它(可选地,在强制布局停止时将其旋转到位,如上所述)
这里没有那么糟糕(Chrome),但有一个明显的区别。但是,你对此无能为力——文本的旋转非常昂贵,因为它不是一个简单的形状。但它似乎与单个文本旋转的处理更相关,因为如果你将角度设置为非零,它仍然非常快。
var vis = d3.select(".intgraph").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.on("click", function(){
if ( force.alpha() )
force.stop();
else
force.resume();
});
force.on("start", function(){
vis.classed("running", true);
})
.on("end", function () {
linktext.attr("transform", function (d) {
var xDiff = d.source.x - d.target.x,
xMid = d.source.x - xDiff / 2;
var yDiff = d.source.y - d.target.y,
yMid = d.source.y - yDiff / 2;
var hyp = Math.sqrt(xDiff * xDiff + yDiff * yDiff),
cos = xDiff / hyp,
sin = yDiff / hyp;
return "matrix(" +
[cos, sin, -sin, cos, xMid, yMid] + ")";
});
vis.classed("running", false);
});
.running text {
display:none;
}