vue + d3 实现纵向拓扑图,子节点超过N个时换行展示
最近接手一个功能,画设备拓扑级联图,最开始使用echart.js完成,但有如下问题:
- 当节点过多时,节点描述文本会重叠(网上有解决方案,但效果不是很满意);
- 无法控制子节点超过n个时换行展示;
在尝试了很多方法效果都不好时,转向了d3.js,完成了该功能,效果图如下:
实现思路如下:
- 数据建模
数据建模很重要,它直接决定后续代码的复杂度,以下是我的数据建模,仅做参考:// 这里位置信息我是分开定义,方便后续筛选数据,其实可以使用一个index中间用 分隔符间隔 来定义的 { "name": "xx", "secondIndex": 0, // 父节点所属父节点索引 "thirdIndex": 0, // 节点所属父节点索引 "index": 1, // 节点在本层的横向位置 "deep": 1, //节点位于第几层 "totalWidth": 0, //节点总宽度 "image": '../firstLevel.png', "children": [], };
- 实现子节点超过n个时换行展示
// 这里实现方式有两种,可以直接重置x, y坐标,也可以渲染完成后对节点进行偏移 // 以下是对节点进行偏移的方式实现 var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("transform", function(d) { let x = source.x; let y = source.y0; if (d.deep === 4) { // 重新计算节点坐标 let selfOffset = that.getFourSelfOffset(d); x = selfOffset.x; y = selfOffset.y; } return "translate(" + x + "," + y + ")"; }) .on("click", d => that.click(d));
- 子节点换行展示后,父节点之间的间距应该缩小,重置所属父节点位置,同理也重置父节点所属父节点的位置
// update方法中修改代码重置节点x坐标 let isResetPosition = false; nodes.forEach(function(d) { d.x = d.x; if (d.deep === 3 && !isResetPosition) { // 重置父节点位置 that.resetPosition(d.parent.parent); isResetPosition = true; } })
- 节点描述水平居中
nodeEnter.append("text") .attr("x", "0") .attr("y", "25") // 水平居中 .attr("text-anchor", "middle") .attr("font-size", "12px") .text(function(d) { return d.name; }) .style("fill-opacity", 1e-6);