• antv G6在vue项目中的实践总结


    在项目中使用

    Step 1: 使用命令行在项目目录下执行以下命令:

     npm install --save @antv/g6
    
    • 1

    Step 2: 在需要用的 G6 的 JS 文件中导入:

    import G6 from '@antv/g6';
    
    • 1

    Step 3你需要在template中写一个容器供g6进行绘制canvas

    • 1

    Step 4 准备数据 包含节点nodes和边edges

    Step 5 给你的容器宽高

    const graph = new G6.Graph({
      width: 800, // Number,必须,图的宽度
      height: 500, // Number,必须,图的高度
    });
    
    • 1
    • 2
    • 3
    • 4

    Step 6 开始绘制

    graph.data(data); // 读取数据源到图上
    graph.render(); // 渲染图
    
    • 1
    • 2

    开始自己的g6图绘制

    实际上深谙项目的我们是不会从零开始绘图的,我们直接在antvg6官网的案例中,找到合适的图例,然后开始魔改。

    根据需求 我们本次使用决策树进行魔改

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7RZP95zT-1662631940698)(C:\Users\guochangsha1\AppData\Roaming\Typora\typora-user-images\image-20220907195424873.png)]

    我们将官网上的代码 1部分加入style中,2部分的代码写入data()中,3部分的代码写入一个function里放在methods:中,例drawgraph(){} ;然后在mounted中调用;你以为这样的你会得到你的第一个图,然后并不是,在vue项目中,由于生命周期的关系,mounted阶段$el 尚未挂载dom 此时你的控制台会出现:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uH5HIts1-1662631940699)(E:\images\ME1662547347076.png)]

    此时我们可以写一个尾调用将方法包裹:然后在mounted中调用

      delaydrawgraph() {
          if (document.getElementById('container') == null) {
            this.delaydrawgraph()
          }
          this.drawgraph()
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    接下来我们就画好了这样一张图

    在这里插入图片描述

    修改图

    图的基本配置:
    const graph = new G6.Graph({
      container: '',
      width: 500, //画布宽
      height: 500,// 画布高
      modes: {
        default: ['drag-canvas'],
      },
      layout: {
        type: 'radial',
        unitRadius: 50,
        center: [500, 300],
      },
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    modes: 交互模式

    默认包含可拖拽,缩放,当需要选中节点时可配置 使用edit。当我们想要取消默认行为时,

      modes: {
        default: ['drag-canvas', 'zoom-canvas'],
        edit: ['click-select'],
      },
    
    • 1
    • 2
    • 3
    • 4

    当我们想要添加或取消默认行为时,我们可以在initGraph() 方法内 graph.render()之后进行如下操作:

    // 向 default 模式中添加名为 drag-canvas 的行为,并使用行为的默认配置
    graph.addBehaviors('drag-canvas', 'default');
    
    // 从 default 模式中移除名为 drag-canvas 的行为
    graph.removeBehaviors('drag-canvas', 'default');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    layout:布局配置项

    使用 type 字段指定使用的布局方式,type 可取以下值:random, radial, mds, circular, fruchterman, force, gForce, forceAtlas2, dagre, concentric, grid。

    另外树图(const treeGraph = new G6.TreeGraph({}))配置还包含:dendrogram生态树、compactBox紧凑树、mindmap脑图树 和 indented缩进树

    由于本次使用树图 以下属性基于树图的基础使用

            fitView: false,
            animate: true,
            defaultNode: {
              type: 'tree-node'
            },
            defaultEdge: {
              // type: 'arc',
              type: 'hvh',
              style: {
                stroke: '#987EFB',
                lineWidth: 1
              }
            },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    fitView:

    是否开启画布自适应。开启后图自动适配画布大小。

    defaultNode:节点通用属性

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tXw8j4o2-1662631940700)(C:\Users\guochangsha1\AppData\Roaming\Typora\typora-user-images\image-20220907202423495.png)]

    defaultEdge:边通用属性

    在这里插入图片描述

    节点
    内置节点类型:

    G6 的内置节点包括 circle,rect,ellipse,diamond,triangle,star,image,modelRect,donut(v4.2.5 起支持)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-loIiFyGG-1662631940700)(C:\Users\guochangsha1\AppData\Roaming\Typora\typora-user-images\image-20220908112612460.png)]

    自定义节点: G6.registerNode()

    以官网决策树部分代码为例进行分析

      G6.registerNode(
        'flow-rect',// 和defaultNode中的type需保持一致
        {
          shapeType: 'flow-rect',
          draw(cfg, group) {
            const {
              label,
            } = cfg;
    			// cfg拿到了整个实例,我们可以在上面找到数
                //据、样式、属性等
    // ##########################################
    
            const nodeOrigin = {
              x: -rectConfig.width / 2,
              y: -rectConfig.height / 2,
            };
    
            const textConfig = {
              textAlign: 'left',
              textBaseline: 'bottom',
            };
    
            const rect = group.addShape('rect', {
              attrs: {
                x: nodeOrigin.x,
                y: nodeOrigin.y,
                ...rectConfig,
              },
            });
              // 这一部分我们可以提取公共配置
    // ##########################################
    
            this.drawLinkPoints(cfg, group);
            return rect;
          },
          afterDraw(cfg, group) {},
        /**
         * 更新节点,包含文本
         * @override
         * @param  {Object} cfg 节点的配置项
         * @param  {Node} node 节点
         */
        update(cfg, node) {},
        /**
         * 更新节点后的操作,一般同 afterDraw 配合使用
         * @override
         * @param  {Object} cfg 节点的配置项
         * @param  {Node} node 节点
         */
        afterUpdate(cfg, node) {},
        /**
         * 响应节点的状态变化。
         * 在需要使用动画来响应状态变化时需要被复写,其他样式的响应参见下文提及的 [配置状态样式] 文档
         * @param  {String} name 状态名称
         * @param  {Object} value 状态值
         * @param  {Node} node 节点
         */
        setState(name, value, node) {},
           // 这里是绘制的起点
          getAnchorPoints() {
            return [
              [0, 0.5],
              [1, 0.5],
            ];
          },
        },
        'rect',
      );
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    给节点添加图片: group.addShape('image',{})

    图片源,G6 支持多种格式的图片:url,ImageData,Image,canvas

      group.addShape('image', {
                      attrs: {
                        x: nodeOrigin.x - 1,
                        y: -6,
                        img: require('../images/rootcard.png'),
                        size: 1,
                        width: width * 0.15,
                        height: width * 0.15 * 0.68
                      }
                    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    重写覆盖节点样式:

    当我们需要为不同场景下的节点定制化样式或覆盖原有样式时,我们可以const一个节点,然后利用.attr({})覆盖,此处可以用…运算符将通用config加入其中

    eg.

      const recticon = group.addShape('rect', {
                    attrs: {
                      x: 0,
                      y: -0
                    }
                  })
       recticon.attr({
                        ...iconconfig,
                        x: -width * 0.025 * 0.8,
                        y: width * 0.025 * 0.7,
                        fill: '#FFF0ED'
                      })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    根据层级为节点添加不同样式

    cfg.depth 为我们提供了层级的属性

    我们借此可以利用const去定义一个渲染的图形,然后利用rectname.attr({}) 覆盖重写节点的样式

    eg.

      if (cfg.depth === 4) {
                      group.addShape('rect', {
                        attrs: {
                          fill: '#987EFB'
                        },
                        name: 'left-border-shape'
                      })
                    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这里的name其实可以在一些方法中用来获取绘制的东西

    e.target.get('name')==='namexxx'

    如使用tooltip时获取需要显示tooltip的节点

    边:
    内置边

    G6 提供了 9 种内置边:

    • line:直线,不支持控制点;
    • polyline:折线,支持多个控制点;
    • arc:圆弧线;
    • quadratic:二阶贝塞尔曲线;
    • cubic:三阶贝塞尔曲线;
    • cubic-vertical:垂直方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点;
    • cubic-horizontal:水平方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点;
    • loop:自环。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MF0LNI0d-1662631940701)(C:\Users\guochangsha1\AppData\Roaming\Typora\typora-user-images\image-20220908113009888.png)]
    箭头

    具体形状通过style中控制:

    endArrow: {
        path: G6.Arrow.triangle(10, 20, 25), // 使用内置箭头路径函数,参数为箭头的 宽度、长度、偏移量(默认为 0,与 d 对应)
        d: 25
      },
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    自定义边: G6.registerEdge()
     G6.registerEdge(
        'flow-cubic',// 当你使用自定义边时与默认边type一致才能绘制
        {
          getControlPoints(cfg) {
            let controlPoints = cfg.controlPoints; 
              // 指定controlPoints
            if (!controlPoints || !controlPoints.length) {
              const { startPoint, endPoint, sourceNode, targetNode } = cfg;
              const { x: startX, y: startY, coefficientX, coefficientY } = sourceNode
                ? sourceNode.getModel()
                : startPoint;
              const { x: endX, y: endY } = targetNode ? targetNode.getModel() : endPoint;
              let curveStart = (endX - startX) * coefficientX;
              let curveEnd = (endY - startY) * coefficientY;
              curveStart = curveStart > 40 ? 40 : curveStart;
              curveEnd = curveEnd < -30 ? curveEnd : -30;
              controlPoints = [
                { x: startPoint.x + curveStart, y: startPoint.y },
                { x: endPoint.x + curveEnd, y: endPoint.y },
              ];
            }
            return controlPoints;
          },
          getPath(points) {
            const path = [];
            path.push(['M', points[0].x, points[0].y]);
            path.push([
              'C',
              points[1].x,
              points[1].y,
              points[2].x,
              points[2].y,
              points[3].x,
              points[3].y,
            ]);
            return path;
          },
        },
        'single-line',
      );
    
    • 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
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    根据不同节点绘制边:

    由于在绘制边时 我们拿到的cfg对象只包含数据中的id,而source、target、分别代表起始点的id,此时我们若想定制不同节点间边的样式,我们可以通过清洗数据,为数据id中拼接一个我们可以用来判断的字符串

    if (cfg.source.includes('mystring')) {
                  shape.attr({
                    stroke: '#987EFB'
                  })
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    边path指令:M、L、Q…

    源代码抛出的边指令如下:M代表起始点,L是直线,Q指令可以为自定义折线添加拐点以及弧度(因为此时radius是失效的)

    export declare type ElementFilterFn = (IElement: any) => boolean;
    declare type A = ['a' | 'A', number, number, number, number, number, number, number];
    declare type C = ['c' | 'C', number, number, number, number, number, number];
    declare type O = ['o' | 'O', number, number];
    declare type H = ['h' | 'H', number];
    declare type L = ['l' | 'L', number, number];
    declare type M = ['m' | 'M', number, number];
    declare type R = ['r' | 'R', number, number, number, number];
    declare type Q = ['q' | 'Q', number, number, number, number];
    declare type S = ['s' | 'S', number, number, number, number, number, number, number];
    declare type T = ['t' | 'T', number, number];
    declare type V = ['v' | 'V', number];
    declare type U = ['u' | 'U', number, number, number];
    declare type Z = ['z' | 'Z'];
    export declare type PathCommand = A | C | O | H | L | M | R | Q | S | T | V | U | Z;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    eg.

     path = [
                    ['M', startPoint.x, startPoint.y],
                    ['L', startPoint.x + 10, startPoint.y],
                    ['L', endPoint.x / 3 + (2 / 3) * startPoint.x - 15, startPoint.y],
                    ['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y, endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y],
                    ['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y],
                    ['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y, (endPoint.x / 3 + (2 / 3) * startPoint.x) + 13, endPoint.y],
                    ['L', endPoint.x + (-15), endPoint.y],
                    ['L', endPoint.x, endPoint.y]
                  ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    插件:
    插件tooltip:

    new G6.Graph时加载插件

    const graph = new G6.Graph({
      //... 其他配置项
      plugins: [tooltip], // 配置 Tooltip 插件
    });
    
    • 1
    • 2
    • 3
    • 4

    eg. DOM形式

    const tooltip = new G6.Tooltip({
      offsetX: 10,
      offsetY: 20,
      getContent(e) {
        const outDiv = document.createElement('div');
        outDiv.style.width = '180px';
        outDiv.innerHTML = `
          

    自定义tooltip

    • Label: ${e.item.getModel().label || e.item.getModel().id}
    `
    return outDiv }, // 允许出现 tooltip 的 item 类型 itemTypes: ['node', 'edge'], });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    String 形式

    const tooltip = new G6.Tooltip({
      getContent(e) {
        return `
    `
    ; }, });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    当我们需要自定义tooltip样式时:

    (注意:不要将此样式放在scoped中,此时会无法覆盖)

    .g6-component-tooltip {
      background: rgba(0,0,0,0.75) !important;
      padding: 10px;
      box-shadow: rgb(174, 174, 174) 0px 0px 10px;
      width: fit-content;
      border-radius: 4px;
      display:block;
      color:#fff;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    tooltip配置项:

    在这里插入图片描述

    插件总览:

    g6还提供了如下插件:

    在这里插入图片描述

    交互:

    绑定监听事件

     graph.on('collapse-text:click', (e) => {
     //collapse-text代表绘制的节点name。=,click为事件
       })
    
    • 1
    • 2
    • 3

    事件包含:Canvas 交互事件、node交互事件、edge交互事件等等

    常见如:click、mouseenter、mousemove、mouseover、drag、dragend、dragstart、keydown、keyup…

    时机事件如

    在这里插入图片描述

    复合交互事件:

    BehaviorOption.getEvents()

    BehaviorOption.onNodeClick(evt)

    BehaviorOption.getDefaultCfg()

    BehaviorOption.shouldBegin(evt)

    BehaviorOption.shouldUpdate(evt)

    BehaviorOption.shouldEnd(evt)

    数据更新渲染:
    api:

    graph.data(data):初始化图数据

    graph.save():获取图数据

    graph.read(data):接收数据,并进行渲染,read 方法的功能相当于 data 和 render 方法的结合

    graph.changeData(data, stack):更新数据源,根据新的数据重新渲染视图。

    graph.render():根据提供的数据渲染视图。

    graph.refresh():当源数据中现有节点/边/ Combo 的数据项发生配置的变更时,根据新数据刷新视图。

    graph.paint():仅重新绘制画布。当设置了元素样式或状态后,通过调用 paint() 方法,让修改生效。

    graph.setAutoPaint(auto):设置是否在更新/删除后自动重绘,一般搭配 paint() 方法使用。

    使用场景:

    1、当我获取后端数据时,应该重新绘制整张图,此时我可以先调用destroy()再重新绘制

    // data中存放我的图
    data() {
        return {
            mygraph:''
        }
    }
    // 初始化时赋给我的图
    graph = new G6.TreeGraph({
              container: 'container',
              ...config,
    })
    this.mygraph = graph
    // 数据更新时
    changedata(){
       this.mygraph.destroy()
       this.drawgrapg() 
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2、更新某些数据时

    graph.changeData(data, stack)

    在这里插入图片描述

    画布视口操作:

    graph.getZoom():获取当前视口的缩放比例。

    graph.zoom(ratio, center, animate, animateCfg):改变视口的缩放比例,在当前画布比例下缩放,是相对比例。

    graph.zoomTo(toRatio, center, animate, animateCfg):缩放视窗窗口到一个固定比例。

    graph.changeSize(width, height):改变画布大小。(canvas在当前画布大小中溢出)

    graph.translate(dx, dy, animate, animateCfg):采用相对位移来平移画布。

    graph.moveTo(x, y, animate, animateCfg):采用绝对位移将画布移动到指定坐标。(可相对于画布位置定位)

    graph.fitView(padding, rules, animate, animateCfg):让画布内容适应视口。(拓展了fitView属性,rules可以是 { onlyOutOfViewPort?: boolean; direction?: 'x' / 'y' / 'both'; ratioRule?: 'max' / 'min} 此方法将会另你的图在画布中缩放

    graph.fitCenter(animate, animateCfg):*v3.5.1 后支持。*平移图到中心将对齐到画布中心,但不缩放。优先级低于 fitView。

    graph.focusItem(item, animate, animateCfg):移动图,使得 item 对齐到视口中心,该方法可用于做搜索后的缓动动画。

  • 相关阅读:
    【STM32】驱动库的选择:CMSIS Driver、SPL、HAL、LL | 在ARM MDK、STM32Cube中如何选择?
    ArrayList常见面试题
    什么是pmp考试?
    2022- CSS 函数代码了
    一种基于 TrustZone 的内生可信执行环境构建方法
    冰蝎逆向初探
    Could not find cuda drivers on your machine
    Git、Github、Gitee、GitLab学习笔记
    NET:Spire.XLS 12.11.3 supports a variety of new formulas
    C++入门必会--删数问题
  • 原文地址:https://blog.csdn.net/weixin_44717486/article/details/126769657