实现的功能

  • 节点信息图片展示
  • 连线信息展示
  • 连线动画效果
  • 节点拖拽
  • 缩放
  • 移入节点展示更多信息
  • 动态修改数据展示(包括添加和删除),修改vuedevtools试试看吧
    在这里插入图片描述
  • 因为公司内网的原因,不能照搬所有代码,只能实现部分。还有折叠高亮视图聚焦移动等,可以看看D3的示例。

感谢

巨人的肩膀。我是根据大佬的实现,进行了一些封装优化,我用的是最新的D3版本。

代码仓库

d3-topo

预览地址

d3-topo

一些功能的实现,详细请看源码

  • render函数
  render() {
    this.container = this.svg.append("g").attr("class", "graph");
    this.init();

	// 每次迭代必须调用修改节点和边的位置
    this.force.on("tick", () => {
      this.initLinksPosition();
      this.initNodesPosition();
    });
  }

  init() {
    this.initForce(); //初始化力模型
    this.initMarker(); //初始化连线箭头
    this.initLinks(); //连线需要在节点之前,否则会盖住
    this.initNodes(); //初始化节点
    this.initDrag(); //初始化节点拖拽
    this.initZoom(); //初始化缩放
    this.initNodeHover(); //初始化hover节点信息展示
  }
  • 初始化force
  initForce() {
    this.force = d3
      .forceSimulation(this.nodes)
      .alpha(this.alpha) //力迭代次数[0,1],越大布局越好
      .force(
        "charge",
        d3.forceManyBody().strength(this.strength).distanceMax(this.distanceMax)
      ) //strength节点之间引力,负值越大分的越开。distanceMax连线距离
      .force("link", d3.forceLink(this.links))
      .force("center", d3.forceCenter(this.width / 2, this.height / 2)); //布局中心点
  }
  • 边箭头
  initMarker() {
    this.svg
      .append("marker")
      .attr("id", "resolved")
      .attr("markerUnits", "userSpaceOnUse")
      .attr("viewBox", "0 -5 10 10") //坐标系的区域
      .attr("refX", 12) //箭头坐标
      .attr("refY", 0)
      .attr("markerWidth", 12) //标识的大小
      .attr("markerHeight", 12)
      .attr("orient", "auto") //绘制方向,可设定为:auto(自动确认方向)和 角度值
      .attr("stroke-width", 2) //箭头宽度
      .append("path")
      .attr("d", "M0,-5L10,0L0,5") //箭头的路径
      .attr("fill", "#6cbfed"); //箭头颜色
  }
  • 拖拽
  initDrag() {
    let _this = this;
    this.graphNodes.call(
      d3.drag().on("start", dragStart).on("drag", dragging).on("end", dragEnd)
    );
    function dragStart(d) {
      if (!d.active) _this.force.alphaTarget(0.2).restart();
    }
    function dragging(d) {
      d.subject.x = d.x;
      d.subject.y = d.y;
    }
    function dragEnd(d) {
      if (!d.active) _this.force.alphaTarget(0);
    }
  }
  • 缩放
  initZoom() {
    // scaleExtent缩放范围
    let _this = this;
    this.svg.call(getZoom()).on("dblclick.zoom", null);//禁止双击放大
    function getZoom() {
      return (_this.zoom = d3
        .zoom()
        .scaleExtent([0.05, 8])//缩放大小限制
        .on("zoom", (d) => {
          d3.select("g.graph").attr("transform", function () {
            return `translate(${d.transform.x},${d.transform.y}) scale(${d.transform.k})`;
          });
        }));
    }
  }
  • 更新 reRender函数。更新千万不要append,要用select,否则更新一次,节点多一倍
  reRender() {
    this.reInitLink();
    this.reInitNode();

    this.force.nodes(this.nodes);
    this.force.force("links", d3.forceLink(this.links));
    this.force.alpha(this.alpha).alphaDecay(this.alphaDecay).restart();
  }

扩展

我最后没有用D3去实现拓扑图可视化的展示。因为我们需要minimap展示,但是我写不出来😂。所以后面用到了另外一个框架–ANTV-G6。他封装了大量的操作和动画效果,还有minimap插件,上手比D3快的多。所以就采用了G6,完全可以实现一模一样的效果,并且是canvas绘制的。

G6实现拓扑图可视化展示

g6-topo

Logo

永洪科技,致力于打造全球领先的数据技术厂商,具备从数据应用方案咨询、BI、AIGC智能分析、数字孪生、数据资产、数据治理、数据实施的端到端大数据价值服务能力。

更多推荐