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

200000个节点布局
300000个节点布局的示例如下:
300000个节点布局

示例代码

Worker计算的核心代码如下:

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

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

//  计算左上角的点与右下角的点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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

策略改进

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

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

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

其他策略

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

总结

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

           

猜你喜欢

转载自blog.csdn.net/qq_44884577/article/details/89232167