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

在项目中使用

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

 npm install --save @antv/g6

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

import G6 from '@antv/g6';

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

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

Step 5 给你的容器宽高

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

Step 6 开始绘制

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

开始自己的g6图绘制

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

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

antv G6在vue项目中的实践总结_第1张图片

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

antv G6在vue项目中的实践总结_第2张图片

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

  delaydrawgraph() {
      if (document.getElementById('container') == null) {
        this.delaydrawgraph()
      }
      this.drawgraph()
    }

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

antv G6在vue项目中的实践总结_第3张图片

修改图

图的基本配置:
const graph = new G6.Graph({
  container: '',
  width: 500, //画布宽
  height: 500,// 画布高
  modes: {
    default: ['drag-canvas'],
  },
  layout: {
    type: 'radial',
    unitRadius: 50,
    center: [500, 300],
  },
});
modes: 交互模式

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

  modes: {
    default: ['drag-canvas', 'zoom-canvas'],
    edit: ['click-select'],
  },

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

// 向 default 模式中添加名为 drag-canvas 的行为,并使用行为的默认配置
graph.addBehaviors('drag-canvas', 'default');

// 从 default 模式中移除名为 drag-canvas 的行为
graph.removeBehaviors('drag-canvas', 'default');
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
          }
        },
fitView:

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

defaultNode:节点通用属性

antv G6在vue项目中的实践总结_第4张图片

defaultEdge:边通用属性

antv G6在vue项目中的实践总结_第5张图片

节点:
内置节点类型:

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',
  );
给节点添加图片: 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
                  }
                })
重写覆盖节点样式:

当我们需要为不同场景下的节点定制化样式或覆盖原有样式时,我们可以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'
                  })
根据层级为节点添加不同样式

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

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

eg.

  if (cfg.depth === 4) {
                  group.addShape('rect', {
                    attrs: {
                      fill: '#987EFB'
                    },
                    name: 'left-border-shape'
                  })
                }

这里的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
  },

antv G6在vue项目中的实践总结_第6张图片

自定义边: 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',
  );
根据不同节点绘制边:

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

if (cfg.source.includes('mystring')) {
              shape.attr({
                stroke: '#987EFB'
              })
 }
边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;

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]
              ]
插件:
插件tooltip:

new G6.Graph时加载插件

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

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'], });

String 形式

const tooltip = new G6.Tooltip({
  getContent(e) {
    return `
`
; }, });

当我们需要自定义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;
}

tooltip配置项:

antv G6在vue项目中的实践总结_第7张图片

插件总览:

g6还提供了如下插件:

antv G6在vue项目中的实践总结_第8张图片

交互:

绑定监听事件

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

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

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

时机事件如:

antv G6在vue项目中的实践总结_第9张图片

复合交互事件:

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() 
}

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 对齐到视口中心,该方法可用于做搜索后的缓动动画。

你可能感兴趣的:(vue,vue.js,javascript,前端)