D3 force(力导向图)研究之二:如何布局超过十万个节点的图谱

基于SVG利用力导向图对节点进行布局,容易导致布局失败的原因有两个:
1. 计算节点位置耗费大量的CPU,导致页面操作冻结;
2. 添加DOM节点到SVG元素时,渲染、重绘会耗费大量的GPU,导致页面直接崩溃;

针对以上的情况,可以采取如下策略:
1. 布局过程中,在页面只显示节点;
2. 布局过程中,在页面同时显示节点与连线;
3. 布局过程中不显示节点与连线,布局完成后显示;
4. 将布局算法放入Worker进行计算,同时显示节点与连线;

表一是各种策略的测试结果,每次布局都添加同样数量节点与连线,见下表。

表一:布局策略的完成时间(单位:毫秒)

节点数量\显示方式 只显示点 显示点与线 布局完成后显示 Worker
1000 11301 17854 6309 8313
2000 17854 20886 6243 -
3000 32831 51262 8249 -
4000 43536 69135 10307 11395
10000 116512 181092 36966 48890

从上表可以看出,达到10000个节点与连线后,计算时间最短也需要37秒,基本上处于不可用状态。

在此过程中,还有如下一条数据,布局一万个节点至少需要18278 X 18336的面积,也就是说,至少需要40块1920 X 1080的显示屏,才能将图片完全显示,平均每个节点占据的面积为33514平方像素,约为183*183的大小,当然,这主要是由节点之间的连接关系决定的。

继续加大数据量进行测试,主要以Worker的方式:

节点数量\显示方式 Worker布局完成后显示 布局时间 渲染时间 画布最小尺寸 SVG文件大小 单位面积平方像素
100000 771787 765841 5946 58118 * 58177 21.2m 33776=183*183
200000 1643614 1630699 12915 82185*82141 42.5m 33753=183*183
300000 36395188 36371453 23735 100708*100703 63.7m 33805=183*183


300000个节点布局的示例如下:
D3 force(力导向图)研究之二:如何布局超过十万个节点的图谱_第1张图片

示例代码

Worker计算的核心代码如下:

importScripts('d3.v4.min.js')
var sim = d3.forceSimulation();
//  每次数据发生变更时,通知布局进行DOM修正    
var tickHandler = function() {
    postMessage({
        nodes,
        links
    })
}
sim.on('tick.force', tickHandler)

计算画布尺寸的代码如下:

//  计算左上角的点与右下角的点
var max = {x : 0, y : 0},
    min = {x : 0, y : 0}
//  遍历所有的节点
nodes.forEach(function(item) {
    if(item.x > max.x) {
        max.x = item.x
    }
    if(item.y > max.y) {
        max.y = item.y
    }
    if(item.x < min.x) {
        min.x = item.x
    }
    if(item.y < min.y) {
        min.y = item.y
    }
})
//  改进SVG的视图区域
var width = max.x - min.x,
    height = max.y - min.y;
//  设置大小
svg.attr('width', width)
svg.attr('height', height)
//  设置可见区域
svg.attr('viewBox', min.x + ',' + min.y + ',' + width + ',' + height)

策略改进

通过上面的数据我们可以得出这样的结论:
1. 无论多大的显示屏都不可能把图谱显示完全;
2. 浏览器渲染节点容易导致浏览器崩溃;

于是我们也可以做出如下的改进策略:
1. 将布局结果保存到服务器;
2. 只显示可视区域之内的节点;
3. 通过可是区域的移动实现DOM节点的销毁;
4. 将SVG方式改为canvas方式,减少节点的消耗;

以Express为服务器,将布局方式放到服务器端,当节点数据生变化时,自动重排,并将结果保存到数据库,然后可视窗口滑动到哪里,就显示哪里的节点数据。

其他策略

  1. 按照连接关系对业务数据进行分片,例如分层、聚集等方法,然后依次布局;
  2. 采用多Worker方式;
  3. 采用静态布局方式,改用手动控制tick方法;
  4. 优化模拟器参数,尤其是alphaDecay、velocityDecay等核心参数。

总结

布局超大型的拓扑图或者图谱,需要多种策略的融合,无论是算法层面还是展现层面,都要经历长期的调试与优化,很难做到一蹴而就,没有最优的策略,但有最适合当前业务与环境的策略。

你可能感兴趣的:(d3应用专题,d3,力导向图,十万节点,超大布局)