当前位置: 首页 > 工具软件 > G6 > 使用案例 >

Vue3使用G6基础

衡丰茂
2023-12-01

Vue3使用G6笔记(

需要用到思维导图,找到蚂蚁金服的G6可以满足需求,不得不说阿里巴巴yyds,这一套图标全家桶可太棒了

  • 熟悉了下基本用法,记录下来
  • 官网讲的就很好了,建议去认真读读手册就会用了
  • 这里总结的更精简和直观,需要的小伙伴可以看看
  • 目前还是一些比较基础的操作,后面用的深入了还会更新

一. 安装和引入

  • npm安装
npm install --save @antv/g6
  • 项目中引入
import G6 from '@antv/g6';

二. 第一个小demo

通过一个小demo了解基础的创建方式

步骤

  1. 首先需要一个标记了id的div
<template>
  <div>
    <div id="mountNode"></div>
  </div>
</template>
  1. 之后需要初始化G6的Graph实例,这一步需要放在onMounted生命周期中,不然加载不出来
 const graph = new G6.Graph({
        container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
        width: 800, // Number,必须,图的宽度
        height: 500, // Number,必须,图的高度
      });
  1. 之后需要定义一些节点数据
const data = {
      // 点集
      nodes: [
        {
          id: 'node1', // String,该节点存在则必须,节点的唯一标识
          x: 100, // Number,可选,节点位置的 x 值
          y: 200, // Number,可选,节点位置的 y 值
          label: 'start'
        },
        {
          id: 'node2', // String,该节点存在则必须,节点的唯一标识
          x: 300, // Number,可选,节点位置的 x 值
          y: 200, // Number,可选,节点位置的 y 值
          label: 'end'
        },
      ],
      // 边集
      edges: [
        {
          source: 'node1', // String,必须,起始点 id
          target: 'node2', // String,必须,目标点 id
          label: '我是连线'
        },
      ],
    };
  1. 还是在onMounted中加载数据,并且渲染
 graph.data(remoteData); // 加载远程数据
 graph.render(); // 渲染
  1. 完整代码
<template>
  <div>
    <div id="mountNode"></div>
  </div>
</template>


<script>
import G6 from '@antv/g6';
import {onMounted} from "vue";
export default {
  name: "Test02",
  setup(){
    const data = {
      // 点集
      nodes: [
        {
          id: 'node1', // String,该节点存在则必须,节点的唯一标识
          x: 100, // Number,可选,节点位置的 x 值
          y: 200, // Number,可选,节点位置的 y 值
          label: 'start'
        },
        {
          id: 'node2', // String,该节点存在则必须,节点的唯一标识
          x: 300, // Number,可选,节点位置的 x 值
          y: 200, // Number,可选,节点位置的 y 值
          label: 'end'
        },
      ],
      // 边集
      edges: [
        {
          source: 'node1', // String,必须,起始点 id
          target: 'node2', // String,必须,目标点 id
          label: '我是连线'
        },
      ],
    };
    onMounted(()=>{
    // 实例化graph对象
      const graph = new G6.Graph({
        container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
        width: 800, // Number,必须,图的宽度
        height: 500, // Number,必须,图的高度
      });
        graph.data(remoteData); // 加载远程数据
        graph.render(); // 渲染
      };
      main()
    })
  }
}
</script>

<style scoped>

</style>

之后就是详细各部分的教程

三. 点和边的参数设置

1. 基本配置

点和线的样式和设置都是包裹在nodes对象数组中的,在对象中填入下面的配置即可配置点和边的样式

{
	id: 'node0',          // 元素的 id
  type: 'circle',       // 元素的图形
  size: 40,             // 元素的大小
  label: 'node0'        // 标签文字
  visible: true,        // 控制初次渲染显示与隐藏,若为 false,代表隐藏。默认不隐藏
  labelCfg: {           // 标签配置属性
    positions: 'center',// 标签的属性,标签在元素中的位置
    style: {            // 包裹标签样式属性的字段 style 与标签其他属性在数据结构上并行
      fontSize: 12      // 标签的样式属性,文字字体大小
      // ...            // 标签的其他样式属性
    }
  }
  // ...,               // 其他属性
  style: {              // 包裹样式属性的字段 style 与其他属性在数据结构上并行
    fill: '#000',       // 样式属性,元素的填充色
    stroke: '#888',     // 样式属性,元素的描边色
    // ...              // 其他样式属性
  }
}

2. 通过遍历节点来设置样式

既可以在节点数据就写好样式,但更多的我们是拿到后端传来的很标准的json数据(只有数据),这个时候可以通过遍历节点来设置各个节点的样式

要注意的是动态配置的样式会覆盖掉在graph初始化时配置的默认样式

const nodes = remoteData.nodes; //这里是拿到的节点数据
nodes.forEach((node) => { //遍历节点数据
  if (!node.style) {
    node.style = {};
  }
  switch (
    node.class // 根据节点数据中的 class 属性配置图形
  ) {
    case 'c0': {
      node.type = 'circle'; // class = 'c0' 时节点图形为 circle
      break;
    }
    case 'c1': {
      node.type = 'rect'; // class = 'c1' 时节点图形为 rect
      node.size = [35, 20]; // class = 'c1' 时节点大小
      break;
    }
    case 'c2': {
      node.type = 'ellipse'; // class = 'c2' 时节点图形为 ellipse
      node.size = [35, 20]; // class = 'c2' 时节点大小
      break;
    }
  }
});

graph.data(remoteData);

四. 初始化实例时的参数设置

1. 让画布适应图像

由于点和变数据在设置的时候可以指定位置,而如果画布不够大的话是会超出画布大小,显示不完整的

  • 这一点可以在初始化的时候解决
 const graph = new G6.Graph({
        container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
        width: 800, // Number,必须,图的宽度
        height: 500, // Number,必须,图的高度
        fitView: true, // 让图片适应当前的画布大小
        fitViewPadding: [20,40,50,20] // 适应之后加入边框
      });

2. 给点和边指定默认样式

需要点和边有统一的样式的时候,可以在graph初始化的时候指定默认样式

const graph = new G6.Graph({
        container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
        width: 800, // Number,必须,图的宽度
        height: 500, // Number,必须,图的高度
        fitView: true, // 让图片适应当前的画布大小
        fitViewPadding: [20,40,50,20], // 适应之后加入边框
		// 从这开始指定默认节点样式
        defaultNode: {
          size: 30, // 节点大小
          // ...                 // 节点的其他配置
          // 节点样式配置
          style: {
            fill: 'steelblue', // 节点填充色
            stroke: '#666', // 节点描边色
            lineWidth: 1, // 节点描边粗细
          },
          // 节点上的标签文本配置
          labelCfg: {
            // 节点上的标签文本样式配置
            style: {
              fill: '#fff', // 节点标签文字颜色
            },
          },
        },
        // 边在默认状态下的样式配置(style)和其他配置
        defaultEdge: {
          // ...                 // 边的其他配置
          // 边样式配置
          style: {
            opacity: 0.6, // 边透明度
            stroke: 'grey', // 边描边颜色
          },
          // 边上的标签文本配置
          labelCfg: {
            autoRotate: true, // 边上的标签文本根据边的方向旋转
          },
        },
      });

3. 添加图布局Layout

const graph = new G6.Graph({
  // ...                      // 其他配置项
  layout: {
    // Object,可选,布局的方法及其配置项,默认为 random 布局。
    type: 'force',
    linkDistance: 100, // 指定边距离为100
    preventOverlap: true, // 防止节点重叠
    // nodeSize: 30        // 节点大小,用于算法中防止节点重叠时的碰撞检测。由于已经在上一节的元素配置中设置了每个节点的 size 属性,则不需要在此设置 nodeSize。
  },
});

4. 添加交互模式

下文会说

5. 添加提示框

下文会说

五. 图布局Layout

当数据中没有节点位置信息,或者数据中的位置信息不满足需求时,需要借助一些布局算法对图进行布局

一般图布局

  • Random Layout:随机布局;
  • Force Layout:经典力导向布局:

力导向布局:一个布局网络中,粒子与粒子之间具有引力和斥力,从初始的随机无序的布局不断演变,逐渐趋于平衡稳定的布局方式称之为力导向布局。适用于描述事物间关系,比如人物关系、计算机网络关系等。

  • Circular Layout:环形布局;
  • Radial Layout:辐射状布局;
  • MDS Layout:高维数据降维算法布局;
  • Fruchterman Layout:Fruchterman 布局,一种力导布局;
  • Dagre Layout:层次布局;
  • Concentric Layout:同心圆布局,将重要(默认以度数为度量)的节点放置在布局中心;
  • Grid Layout:格子布局,将节点有序(默认是数据顺序)排列在格子上

树图布局

  • Dendrogram Layout:树状布局(叶子节点布局对齐到同一层);
  • CompactBox Layout:紧凑树布局;
  • Mindmap Layout:脑图布局;
  • Indented Layout:缩进布局。

默认情况

  • 默认情况下,如果节点数据中有坐标信息,就用坐标信息
  • 没有坐标信息,就用 Random Layout 布局
const graph = new G6.Graph({
// 。。。。。其他配置省略
  // 图布局Layout
        layout: {
          // Object,可选,布局的方法及其配置项,默认为 random 布局。
          type: 'force',
          linkDistance: 100, // 指定边距离为100
          preventOverlap: true, // 防止节点重叠
          // nodeSize: 30        // 节点大小,用于算法中防止节点重叠时的碰撞检测。由于已经在上一节的元素配置中设置了每个节点的 size 属性,则不需要在此设置 nodeSize。
        },
 )}

六. 图的交互

给图添加简单的交互,比如:hover 节点、点击节点、点击边、放缩画布、拖拽画布

1. 拖拽,放大,缩小

直接在graph初始化的时候写上mode就行,

const graph = new G6.graph({
// 交互模式
	modes: {
    default: ['drag-canvas', 'zoom-canvas', 'drag-node'], // 允许拖拽画布、放缩画布、拖拽节点
    },
})

2. 提示框

  • hover的时候出现提示框,在mode的数组中加入tooltip类型或edge-tooltip类型
  • 实际上就是将这个节点上的一些数据输出出来,需要手动写一个html的字符串
const graph = new G6.Graph({
	modes: {
          default: ['drag-canvas', 'zoom-canvas', 'drag-node', // 允许拖拽画布、放缩画布、拖拽节点
            {
              type: 'tooltip', // 提示框
              formatText(model) {
                // 提示框文本内容,实际上就是放了个div进去
                const text = 'label: ' + model.label + '<br/> class: ' + model.class;
                return text;
              }
            },
            {
              type: 'edge-tooltip', // 边提示框
              formatText(model) {
                // 边提示框文本内容
                const text =
                    'source: ' +
                    model.source +
                    '<br/> target: ' +
                    model.target +
                    '<br/> weight: ' +
                    model.weight;
                return text;
                }
              },
          ],
)}

3. 状态式交互

比如点击,hover触发的事件和样式的改变等等

(a) 交互状态

  • 交互状态就是这个节点是否处于被hover,或者是否被点击等等事件触发的状态
  • 比如这个节点被点击了,那这个节点的click状态就是true
  • 而节点处于激活状态时候的样式,是需要在初始化的时候就进行配置的
  • nodeStateStyles和edgeStateStyles下可以进行配置,注意这是激活后才生效的,这里还没绑定事件,因此是不生效的
const graph = new G6.Graph({
  // ...                           // 其他配置项
  // 节点不同状态下的样式集合
  nodeStateStyles: {
    // 鼠标 hover 上节点,即 hover 状态为 true 时的样式
    hover: {
      fill: 'lightsteelblue',
    },
    // 鼠标点击节点,即 click 状态为 true 时的样式
    click: {
      stroke: '#000',
      lineWidth: 3,
    },
  },
  // 边不同状态下的样式集合
  edgeStateStyles: {
    // 鼠标点击边,即 click 状态为 true 时的样式
    click: {
      stroke: 'steelblue',
    },
  },
});

(2) 绑定事件

  • 绑定事件和交互状态需要联合起来用,经过绑定的事件并触发后,才会显示初始化中定义的处于true状态时候的样式
  • 思路就是:拿到点击的节点/边,然后设置这个节点的状态
//graph事件监听
      // 鼠标进入节点
      graph.on('node:mouseenter', (e) => {
        const nodeItem = e.item; // 获取鼠标进入的节点元素对象
        graph.setItemState(nodeItem, 'hover', true); // 设置当前节点的 hover 状态为 true
      });

      // 鼠标离开节点
      graph.on('node:mouseleave', (e) => {
        const nodeItem = e.item; // 获取鼠标离开的节点元素对象
        graph.setItemState(nodeItem, 'hover', false); // 设置当前节点的 hover 状态为 false
      });

      // 点击节点
      graph.on('node:click', (e) => {
        // 先将所有当前是 click 状态的节点置为非 click 状态
        const clickNodes = graph.findAllByState('node', 'click');
        clickNodes.forEach((cn) => {
          graph.setItemState(cn, 'click', false);
        });
        const nodeItem = e.item; // 获取被点击的节点元素对象
        graph.setItemState(nodeItem, 'click', true); // 设置当前节点的 click 状态为 true
      });

      // 点击边
      graph.on('edge:click', (e) => {
        // 先将所有当前是 click 状态的边置为非 click 状态
        const clickEdges = graph.findAllByState('edge', 'click');
        clickEdges.forEach((ce) => {
          graph.setItemState(ce, 'click', false);
        });
        const edgeItem = e.item; // 获取被点击的边元素对象
        graph.setItemState(edgeItem, 'click', true); // 设置当前边的 click 状态为 true
      });

七. 插件的使用

步骤:

  1. 实例化插件
  2. 在初始化graph的时候在plugins中加入
  • 实例化两个插件,一个是缩略图,一个是网格
// 实例化minimap插件对象
    const minimap = new G6.Minimap({
      size: [100, 100],
      className: 'minimap',
      type: 'delegate',
    })
    // 实例化网格插件对象
    const grid = new G6.Grid()
  • 之后在实例化中加入
const graph = new G6.Graph({
		// ......其余配置
        plugins:[minimap, grid],
   	)}

整个案例

整个组件的案例代码在这,里面包含了上面说的所有部分

<template>
  <div>
    <div id="mountNode"></div>
  </div>
</template>


<script>
import request from "../utils/request";
import G6 from '@antv/g6';
import {onMounted} from "vue";
export default {
  name: "Test02",
  setup(){
    // 实例化minimap插件对象
    const minimap = new G6.Minimap({
      size: [100, 100],
      className: 'minimap',
      type: 'delegate',
    })
    // 实例化网格插件对象
    const grid = new G6.Grid()

    const data = {
      // 点集
      nodes: [
        {
          id: 'node1', // String,该节点存在则必须,节点的唯一标识
          x: 100, // Number,可选,节点位置的 x 值
          y: 200, // Number,可选,节点位置的 y 值
          label: 'start'
        },
        {
          id: 'node2', // String,该节点存在则必须,节点的唯一标识
          x: 300, // Number,可选,节点位置的 x 值
          y: 200, // Number,可选,节点位置的 y 值
          label: 'end'
        },
      ],
      // 边集
      edges: [
        {
          source: 'node1', // String,必须,起始点 id
          target: 'node2', // String,必须,目标点 id
          label: '我是连线'
        },
      ],
    };



    onMounted(()=>{
      const graph = new G6.Graph({
        container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
        width: 800, // Number,必须,图的宽度
        height: 500, // Number,必须,图的高度
        fitView: true, // 让图片适应当前的画布大小
        fitViewPadding: [20,40,50,20], // 适应之后加入边框
        plugins:[minimap, grid],

        // 图布局Layout
        layout: {
          // Object,可选,布局的方法及其配置项,默认为 random 布局。
          type: 'force',
          linkDistance: 100, // 指定边距离为100
          preventOverlap: true, // 防止节点重叠
          // nodeSize: 30        // 节点大小,用于算法中防止节点重叠时的碰撞检测。由于已经在上一节的元素配置中设置了每个节点的 size 属性,则不需要在此设置 nodeSize。
        },

        // 交互模式
        modes: {
          default: ['drag-canvas', 'zoom-canvas', 'drag-node', // 允许拖拽画布、放缩画布、拖拽节点
            {
              type: 'tooltip', // 提示框
              formatText(model) {
                // 提示框文本内容,实际上就是放了个div进去
                const text = 'label: ' + model.label + '<br/> class: ' + model.class;
                return text;
              }
            },
            {
              type: 'edge-tooltip', // 边提示框
              formatText(model) {
                // 边提示框文本内容
                const text =
                    'source: ' +
                    model.source +
                    '<br/> target: ' +
                    model.target +
                    '<br/> weight: ' +
                    model.weight;
                return text;
                }
              },
          ],
        },


        // 交互式状态,hover和click时候的样式改变
        nodeStateStyles: {
          // 鼠标 hover 上节点,即 hover 状态为 true 时的样式
          hover: {
            fill: 'lightsteelblue',
          },
          // 鼠标点击节点,即 click 状态为 true 时的样式
          click: {
            stroke: '#000',
            lineWidth: 3,
          },
        },
        // 边不同状态下的样式集合
        edgeStateStyles: {
          // 鼠标点击边,即 click 状态为 true 时的样式
          click: {
            stroke: 'steelblue',
          },
        },

        // 节点的默认样式
        defaultNode: {
          size: 30, // 节点大小
          // ...                 // 节点的其他配置
          // 节点样式配置
          style: {
            fill: 'steelblue', // 节点填充色
            stroke: '#666', // 节点描边色
            lineWidth: 1, // 节点描边粗细
          },
          // 节点上的标签文本配置
          labelCfg: {
            // 节点上的标签文本样式配置
            style: {
              fill: '#fff', // 节点标签文字颜色
            },
          },
        },
        // 边在默认状态下的样式配置(style)和其他配置
        defaultEdge: {
          // ...                 // 边的其他配置
          // 边样式配置
          style: {
            opacity: 0.6, // 边透明度
            stroke: 'grey', // 边描边颜色
          },
          // 边上的标签文本配置
          labelCfg: {
            autoRotate: true, // 边上的标签文本根据边的方向旋转
          },
        },


      });

      //graph事件监听
      // 鼠标进入节点
      graph.on('node:mouseenter', (e) => {
        const nodeItem = e.item; // 获取鼠标进入的节点元素对象
        graph.setItemState(nodeItem, 'hover', true); // 设置当前节点的 hover 状态为 true
      });

      // 鼠标离开节点
      graph.on('node:mouseleave', (e) => {
        const nodeItem = e.item; // 获取鼠标离开的节点元素对象
        graph.setItemState(nodeItem, 'hover', false); // 设置当前节点的 hover 状态为 false
      });

      // 点击节点
      graph.on('node:click', (e) => {
        // 先将所有当前是 click 状态的节点置为非 click 状态
        const clickNodes = graph.findAllByState('node', 'click');
        clickNodes.forEach((cn) => {
          graph.setItemState(cn, 'click', false);
        });
        const nodeItem = e.item; // 获取被点击的节点元素对象
        graph.setItemState(nodeItem, 'click', true); // 设置当前节点的 click 状态为 true
      });

      // 点击边
      graph.on('edge:click', (e) => {
        // 先将所有当前是 click 状态的边置为非 click 状态
        const clickEdges = graph.findAllByState('edge', 'click');
        clickEdges.forEach((ce) => {
          graph.setItemState(ce, 'click', false);
        });
        const edgeItem = e.item; // 获取被点击的边元素对象
        graph.setItemState(edgeItem, 'click', true); // 设置当前边的 click 状态为 true
      });


      //案例中的真实数据
      const main = async () => {
        const response = await fetch(
            'https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json',
        );
        const remoteData = await response.json();

        // ...
        graph.data(remoteData); // 加载远程数据
        graph.render(); // 渲染
      };
      main()
    })
  }
}
</script>

<style scoped>
.g6-tooltip {
  border: 1px solid #e2e2e2;
  border-radius: 4px;
  font-size: 12px;
  color: #545454;
  background-color: rgba(117, 77, 77, 0.9);
  padding: 10px 8px;
  box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
</style>

 类似资料: