AntV_G6实现UI树

发布于:2025-03-11 ⋅ 阅读:(20) ⋅ 点赞:(0)

UI 树的实现

背景

目前需要实现一个 UI 树,用于展示设备树,以及设备树中设备的属性。与树状列表不同,UI 树需要有特定的交互方式,支持边以及当前节点的点击事件。

实现效果【复制到.html文件夹就看见了】

总体效果

点击节点效果

点击边效果


代码示例

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>G6 Tree Example</title>
  <script src="https://gw.alipayobjects.com/os/lib/antv/g6/4.3.11/dist/g6.min.js"></script>
  <style>
    #container {
      width: 100%;
      height: 100vh;
      border: 1px solid #eee;
    }
  </style>
</head>
<body>
  <div id="container"></div>

  <script>
    // 树结构数据
    const treeData = {
      id: 'root',
      label: 'CEO',
      children: [
        {
          id: 'tech',
          label: 'CTO',
          type: 'modelRect',
          description: '技术负责人',
          children: [
            { id: 'frontend', label: 'Frontend' },
            { id: 'backend', label: 'Backend' }
          ]
        },
        {
          id: 'finance',
          label: 'CFO',
          children: [
            { id: 'accounting', label: 'Accounting' },
            { id: 'investment', label: 'Investment' }
          ]
        }
      ]
    };

    // 创建 TreeGraph 实例
    const tree = new G6.TreeGraph({
      container: 'container',
      fitView: true,
      modes: {
        default: ['drag-canvas', 'zoom-canvas'],
        edit: ['click-select-node', 'click-select-edge', 'drag-node', 'drag-canvas', 'zoom-canvas']
      },
      defaultNode: {
        type: 'modelRect',
        size: [200, 80],
        style: {
          fill: '#fff',
          stroke: '#1890ff',
          radius: 4
        },
        labelCfg: {
          style: {
            fill: '#333',
            fontSize: 14
          }
        }
      },
      defaultEdge: {
        type: 'cubic-horizontal',
        style: {
          stroke: '#999',
          lineWidth: 2,
          endArrow: false,
        }
      },
      layout: {
        type: 'compactBox',
        direction: 'TB', // 树方向:Top-Bottom
        getHeight: () => 40,
        getWidth: () => 120,
        getVGap: () => 40,
        getHGap: () => 100
      }
    });

    // 绑定交互事件
    tree.on('node:click', e => {
      const node = e.item;
      console.log('节点点击:', node.getModel().label);
      // 添加点击效果
      node.update({
        style: {
          fill: '#e6f7ff',
          stroke: '#1890ff'
        }
      });
    });

    tree.on('edge:click', e => {
      const edge = e.item;
      console.log('连线点击:', edge.getSource().getModel().label,
                '->', edge.getTarget().getModel().label);
      // 添加点击效果
      edge.update({
        style: {
          stroke: '#ff4d4f',
          lineWidth: 3
        }
      });
    });

    // 渲染树
    tree.data(treeData);
    tree.render();

    // 适配画布尺寸
    window.onresize = () => {
      if (!tree || tree.get('destroyed')) return;
      tree.changeSize(window.innerWidth, window.innerHeight);
      tree.fitView();
    };
  </script>
</body>
</html>

实现方式

在网上进行了一波搜索,一开始我打算使用原生的 canvas 或者 svg 实现此类效果,但是发现实现起来比较麻烦,而且效果也不够好。后来我找到了一个开源的库,AntV G6 这个库可以很方便的实现树状图,而且效果很好,于是我决定使用这个库来实现 UI 树。

一. 安装 G6 库

npm install --save @antv/g6
import G6 from '@antv/g6';

或者像我一样使用 CDN 导入

// version <= 3.2
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-{$version}/build/g6.js"></script>

// version >= 3.3
<script src="https://gw.alipayobjects.com/os/lib/antv/g6/{$version}/dist/g6.min.js"></script>

// version >= 4.0
<script src="https://gw.alipayobjects.com/os/lib/antv/g6/4.3.11/dist/g6.min.js"></script>

二. 创建树图实例

// 创建 TreeGraph 实例
const tree = new G6.TreeGraph({
  container: "container",
  fitView: true,
  modes: {
    default: ["drag-canvas", "zoom-canvas"],
    edit: [
      "click-select-node",
      "click-select-edge",
      "drag-node",
      "drag-canvas",
      "zoom-canvas",
    ],
  },
  defaultNode: {
    // 配置节点的相关内容
    type: "modelRect",
    // 配置节点的大小
    size: [200, 80],
    // 配置节点的样式
    style: {
      fill: "#fff",
      stroke: "#1890ff",
      radius: 4,
    },
    // 配置节点的文本样式
    labelCfg: {
      style: {
        fill: "#333",
        fontSize: 14,
      },
    },
  },
  defaultEdge: {
    // 配置边的相关内容

    // 线条样式
    type: "cubic-horizontal",
    style: {
      stroke: "#999",
      lineWidth: 2,
      // 设置箭头样式,我这里不设置结尾箭头
      endArrow: false,
    },
  },
  layout: {
    // 配置布局相关内容,部分配置项树形UI特有的,需要在此进行配置
    type: "compactBox",
    direction: "TB", // 树方向:Top-Bottom
    // 在特定的树下的API,为高、宽、水平距离、垂直距离
    getHeight: () => 40,
    getWidth: () => 120,
    getVGap: () => 40,
    getHGap: () => 100,
  },
});

三. 绑定交互事件

// 绑定交互事件

// 节点点击事件
tree.on("node:click", (e) => {
  const node = e.item;
  console.log("节点点击:", node.getModel().label);
  // 添加点击效果
  node.update({
    style: {
      fill: "#e6f7ff",
      stroke: "#1890ff",
    },
  });
});
// 边点击事件
tree.on("edge:click", (e) => {
  const edge = e.item;
  console.log(
    "连线点击:",
    edge.getSource().getModel().label,
    "->",
    edge.getTarget().getModel().label
  );
  // 添加点击效果
  edge.update({
    style: {
      stroke: "#ff4d4f",
      lineWidth: 3,
    },
  });
});

四. 加载数据并渲染
数据格式:

const treeData = {
  id: "root",
  label: "CEO",
  children: [
    {
      id: "tech",
      label: "CTO",
      type: "modelRect",
      description: "技术负责人",
      children: [
        { id: "frontend", label: "Frontend" },
        { id: "backend", label: "Backend" },
      ],
    },
    {
      id: "finance",
      label: "CFO",
      children: [
        { id: "accounting", label: "Accounting" },
        { id: "investment", label: "Investment" },
      ],
    },
  ],
};

注意:在节点里面也是可以进行配置对应的属性的,比如:label、type、description等,这样在渲染的时候就会显示出来。


渲染

// 加载数据
tree.data(treeData);
// 渲染树图
tree.render();

五. 总结
以上就是实现树形图的基本步骤,如果需要更详细的配置,可以开头所贴的对应的API。