Skip to content

G6-笔记

快速开始

安装

npm install --save @antv/g6

快速使用

  1. 创建Graph的HTML容器。
  2. 数据准备
  3. 创建Graph实例
  4. 数据配置和渲染
html
<!-- step1 -->
<div id="container"></div>
<script type="module">
import G6 from '@antv/g6';
// step2 数据
const datas = {
  nodes: [
    { id: 'node1', x: 100, y: 200, },
    { id: 'node2', x: 300, y: 200, }
  ],
  edges: [
    { source: 'node1', target: 'node2', }
  ]
}

// step3 创建实例
const graph = new G6.Graph({
  container: 'app',
  height: 400,
  width:600,
})

// step4 数据读取和渲染
graph.data(datas);
graph.render();
</script>

G6.Graph

js
const graph = new G6.Graph(Config)

生命周期

图的生命周期:初始化 -> 加载数据 -> 渲染 -> 更新 -> 销毁。

配置

js
{
    container: 'idRef', // 指定图挂载的容器 必要配置项
    height: 400, // 图的高度 必要配置项
    width: 500, // 图的宽度 必要配置项
    renderer: 'canvas', // 默认canvas,可选svg; 注意svg性能较差
    fitView: true, // 设置是否将图适配到画布中
    fitViewPadding: [20, 40, 50, 20], // 画布上四周的留白宽度,和CSS的padding一样,fitView为true生效
    fitCenter: false, // 默认false,是否平移图使其中心对齐画布中心
    animate: false// 是否启用全局动画。
    layout: { // 布局对象属性
        type: 'force'// 布局类型
    },
    modes: { // 定义各种模式
        default: ['drag-canvas', 'zoom-canvas', 'drag-node'],
        edit: []
    },
    nodeStateStyles: { // 配置节点不同状态的样式
        hover: { // 鼠标hover上节点,即hover状态为true时的样式
            fill: 'lightsteelblue'
        }
    },
    edgeStateStyles: { // 配置边不同状态的样式
        click: { // 鼠标点击边,即click的状态为true时的样式
            stroke: 'steelblue'
        }
    },
    groupByTypes: true, // 默认值为㹖
}

fitView

图上有些节点的坐标不在图的高宽范围内,会被截掉不显示,只能看到部分内容,设置fitView为true,可以将所有内容适配到图中。

Layout

当前数据中没有节点位置信息,或数据中的位置信息不满足需求时,需要借助一些布局算法对图进行布局。G6提供了9种一般图和4种树图的布局。

默认布局,当实例化图没有配置布局时:

  1. 若数据中节点有配置信息(x 和 y),则按钮归数据的位置信息进行绘制;
  2. 若数据中节点没有位置信息,则默认使用一般图中的一种Random Layout进行布局。

布局在调用graph.render()时执行计算

Modes

这是一个对象,可以定义各种模式,每种模式有不同的行为。 如默认模式default下,可以有drag-canvas, zoom-canvas, drag-node三种内置交互行为,而edit为空,没有可用的交互行为。 通过graph.setMode(modeValue)来切换模式。

groupByTypes

为true时,所有节点在一个名为nodeGroup的分组,所有边在另一个名为edgeGroup的分组,且nodeGroup在edgeGroup上层。 设置为false后将不存在 nodeGroup和edgeGroup,所有节点和边在同一个分组,它们的层级根据生成的顺序决定。

方法

graph.data

读取数据,参数是一个数组;要在render函数之前使用

graph.render

直接渲染图

graph.read(data)

接入数据,并进行渲染。功能相当于data和render方法的结合。

graph.setItemState

修改元素的状态

js
graph.on('node:mouseleave', (e) => {
  const nodeItem = e.item; // 获取鼠标进入节点的元素对象
  graph.setItemState(nodeItem, 'hover', false)
})

graph.setItemState(elementItem, stateName, false|true)

graph.clearItemStates

取消graph.setItemState设置的状态,支持一次取消单个或多个状态。

js
graph.clearItemStates(item, 'selected')
graph.clearItemStates(item, ['selected', 'active'])

graph.findAllByState

获取某元素下某种状态的所有元素,如graph.findAllByState('node', 'click')为获取当前图状态click为true的所有节点。

js
graph.findAllByState('combo|node|edge|vedge', 'stateName');

graph.update/graph.updateItem

此方法用于动态更新节点或边的keyShape。

js
graph.updateItem(node, {
    style: {
        stroke: 'blue
    }
})

graph.updateLayout(string|object)

参数是字符串,或参数包含type字段的对象,且与之前的布局方法不同时会更换布局。 参数对象不含type或type字段值与之前的布局方法名称一样,布局方法不变,只修改参数。

graph.changeData()

更改数据源,根据新的数据重新渲染视图。

graph.setMode()

切换交互模式

元素及其配置

图的元素(Item)包含图上的节点node、边edge和Combo三大类。每个图元素由一个或多个图形(Shape)组成,且都会有自己唯一关键图形(keyShape)。除了G6内置的节点node、边edge和combo外,还可以自由搭配图形和组合图形达到自定义节点、边和combo的目的。不同内置元素的主要区别在于元素的图形Shape,例如:圆形,矩形,图片等

元素属性

不论元素的节点还边,它们的属性分为两种:

  1. 样式属性style: 对应Canvas中的种样式,在元素状态State发生变化时,可以被改变。
  2. 其他属性:如图形类型(type)、id一类元素状态State发生变化时不能被改变的属性。

如图的节点被click或hover时,造成节点状态的变化,只能自动改变节点对应状态的样式如fill, stroke等。 其他属性可以通graph.updateItem手动配置。 样式属性都在style对象中,和其他属性字段并行。

配置属性

可以根据不同场景需求使用不同方式配置

  1. 实例化图时配置元素的全局属性。在G6.Graph中配置,这是全局生效的,优先级最低,可以被其他方式覆盖如数据中的配置。defaultNode配置节点,defaultEdge配置边,其他数据结构和数据中配置的结构是一样的。这种方式适用于全局配置。
  2. 数据中配置,在graph.data的参数中配置,参数对象里的节点和边。这方式适用个性化配置。

图形Shape

G6中的每个节点、边和Combo都是由一个或多个图形Shape组件。节点、边、Combo、标签文本的配置都会被体现到对应的图形上。 图形Shape有很多,有图形(rect, circle,ellipse)、文本、锚点等。

关键图形KeyShape

虽然元素有若干个图形组成,但只有一个关键图形(keyShape)。 keyShape是在节点、边和Combo的draw()方法或drawShape()方法中返回的图形对象。 主要用交互检测、样式随状态自动更新。也就是说元素的style和stateSyles的配置只能体现在keyShape上,其他图形需要另行配置,如文本图形需要在labelCfg上配置。

包围盒确定

节点、Combo的包围盒决定了相关边的连入点(与相关边的交点)。keyShape不同,节点与边的交点计算结果不同。

Shape生命周期

大体分为:初始化渲染、更新、操作、销毁。 绘制:画图形。使用draw(cfg, group),提供了配置项和图形容器,必须返回图形作为keyShape。 更新:数据变更导致Shape及文本变化。使用,update(cfg, n)。 操作:给Shape添加状态,如selected等。使用setState(name, value, item)。

图形Shape及其属性

G6的元素(节点、边和Combo)是由一个或多个图形Shape组成,主要通过自定义节点或自定义边时在draw方法使用group.addShape添加。G6支持以下的图形Shape:

  • circle:圆;
  • rect:矩形;
  • ellipse:椭圆;
  • polygon:多边形;
  • fan:扇形;
  • image:图片;
  • marker:标记;
  • path:路径;
  • text:文本;
  • dom(svg):DOM(图渲染方式 renderer 为 'svg' 时可用)。

Shape通用方法

attr(name)

获取实例的属性值

js
const width = shape.attr('width');

attr(name, value)

更新实例的单个绘图属性

attr({...})

批量更新实例绘图属性

js
rect.attr({
    fill: '#999',
    stroke: '#666',
})

Shape用法

这里以图片图形Image为主,其它的可以查看官网内容

js
group.addShape('image', {
    attrs: {
        x: 0,
        y: 0,
        img: 'https://g.alicdn.com/cm-design/arms-trace/1.0.155/styles/armsTrace/images/TAIR.png'
    },
    // 在 G6 3.3 及之后的版本中,必须指定 name,可以是任意字符串,但需要在同一个自定义元素类型中保持唯一性
    name: 'image-shape'
})

图形分组Group

和Combo区别

图形分组Group与节点分组Combo属于不同层次的概念。

  1. 图形分组针对图形Shape层次的分组
  2. 节点分组Combo是针对节点的分组,与数据结构中的层次、分组对应。

概念

图形分组相当于一个容器,包含了多个图形,在分组上添加变换(剪裁、旋转、平移)会应用到其所有的子元素上,添加属性(颜色、位置)会被所有子元素继承,且分组可以多层嵌套。 G6中一个实例所有节点同属于一个变量名为nodeGroup的分组,所有边同属于一个变量名为edgeGroup的分组,且节点的分组层级(zindex)在高于边的分组。

用法

获取元素Group

js
// 获取元素(节点、边、Combo)的图形对象的容器
const group = item.getContainer();

// 等价于
const group = item.get('group')

addGroup(cfgs)

向分组中添加新的分组。

js
const subGroup = group.addGroup({
    id: 'rect'
})

addShape(type, cfgs)

向分组中添加新的图形

js
const keyShape = group.addShape('rect', {
    attrs: {
        stroke: 'red',
    },
    name: 'rect-shape'
})

获取图形group.get('children')

这个方法返回的是一个数组,里面的元素是图形,排序是按照addShape方法添加的顺序

js
const group = node.getContainer(); // 获取容器
const shape = group.get('children')[0]; //获取第一个添加的图形

在分组上添加clip、transform等会影响到该分组中的所有元素(子分组或图形)

图的交互Behavior

图的交互是指对元素的hover,click、画布的放缩、拖拽后产生的状态变化而对元素相对就的状态样式进行自动修改。

交互行为Behavior

定义图上的交互事件机制,与交互模式Mode搭配使用。G6内置了一系列交互行为,用户可以直接使用。如:

  1. drag-canvas: 拖拽画布
  2. zoom-canvas: 缩放画布

交互管理Mode

Mode是G6交互行为的管理机制,一个Mode是多种行为Behavior的组件,用户通过切换不同模式(Mode)进行交互行为管理。

交互状态State

状态State是G6中的状态机制。用户可以为元素(节点、边)设置不同状态对应不同的样式,在状态发生变化时,G6自动更新元素对应状态设置的样式。

如对节点设置状态click为true或false,并为节点设置click的样式为加粗节点边框。当click状态切换为true时,节点的边框会被加粗,click状态切换为false时,节点样式恢复到默认。

实际上,任何操作如,clikk, hover,都可以称为一种状态,当前也可以自定义状态名称,用户可以自由设置不同状态下的元素样式。 要达到交互更改元素样式,需要两步:

  1. 设置各种状态下的元素样式;
  2. 监听事件并切换元素状态。

设置元素状态的样式

实例化图时,通过nodeStateStyles和edgeStateStyles两个配置项可以配置在不同状态下的样式。

监听事件切换元素状态

G6所有元素监听都挂载在图实例上,通过graph.on()函数监听某元素类型(node/edge)的某种事件(click, mouseenter, mouseleave)。并在监听函数里使用graph.setItemState()改变元素的状态。

js
// graph.on('元素类型[node|edge]:事件名', (e) =>{})
graph.on('node:mouseenter', (e) => {
  const nodeItem = e.item; // 获取鼠标进入节点的元素对象
  graph.setItemState(nodeItem, 'hover', true)
})

事件

G6上所有的事件都需要在graph上监听。

全局事件

只要在画布上范围内发生均会被触发,如:mousedown, mouseup, click, mouseenter, mouseleave等

canvas事件

只在canvas空白片被触发,如canvas:mousedown, canvas:click等,以canvas:eventName为事件名称

节点/边/combo上的事件

例如node:mousedown, edge:click, combo:click等, 以type:eventName为事件名称。

图形上的事件

指定图形上的事件,如circle-shape:mousedown, circle-shape:click等,以shapeName:eventName为事件名称。可以用于绑定节点/边/combo中对局部图形做出响应的场景。

时机事件

时机事件指渲染、视口变换、元素增删改、数据变换等时机。如beforeadditem, afteradditem等。

自定义事件

可以任意位置通过graph.emit(customEventName: string, event: IG6GraphEvent)触发一个事件,第一个参数为自定义事件名称。在触发前,通过graph.on(customEventName: string, callback: Function)进行监听。

内置Behavior

  • drag-combo

拖动combo

  • Collapse-expand-combo 收起和展开combo。若图配置有布局,则该behavior被触发后会触发图的重新布局,可以通过配置去掉这种默认行为。

  • Drag-canvas 拖拽画布

  • Scroll-canvas 滚动画布

  • zoom-canvas 滚动画布

  • drag-node 拖拽节点,或拖动combo中的节点

  • Click-select 点击选中节点,再次点击或点击canvas取消选中状态。

  • Tooltip 节点文本提示

  • Edge-tooltip 边文本提示

  • Activate-relations 当鼠标移到某节点时,突出显示该节点以及其直接关联的节点和连线

  • Brush-select 拖动框选节点

  • Lasso-select 自由圈选

  • Collapse-expand 只适用于树图,展开或收起子树。

  • Create-edge 通过交互创建边

  • Shortcuts-call 允许终端用户使用键盘组合键调用graph的函数。

自定义交互behavior

生命周期如下:

  • 绑定事件
  • 触发事件
  • 持续事件
  • 结束事件
  • 移除事件
js
import G6 from "@antv/g6";

G6.registerBehavior('activate-node', {
    getDefaultCfg() {
        return {
            multiple: true
        }
    },
    getEvents() {
        // 定义事件,和事件的回调函数
        return {
            'node:click': 'onNodeClick',
            'canvas:click': 'onCanvasClick'
        }
    },
    onNodeClick(e) {
        const graph = this.graph;
        const item = e.item;
        if (item.hasState('active')) {
            graph.setItemStete(item, 'active', false);
            return;
        }
        if (!this.multiple) {
            this.removeNodesState();
        }
        graph.setItemStete(item, 'active', true)
    },
    onCanvasClick(e) {
    },
    removeNodesState()
})

插件与工具

G6提供了一些辅助工具,一部分是插件工具,一部分是交互工具。

插件工具

插件工具在实例化的配置plugins的字段里添加。如缩略图插件和背景网格插件引入如下:

js
// 缩略图
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 ],
  // ... 其他配置
 })
  1. 缩略图 (Minimap) 是一种常见的用于快速预览和探索图的工具,可作为导航辅助用户探索大规模图。
  2. 网格可用于辅助用户在拖拽节点时对齐到网格。

交互工具

交互工具实际是一种交互行为,也就是说在实例化的配置modes可用行为模式里配置即可。 如节点悬浮提示框tooltip,边悬浮提示框edge-tooltip。在modes里配置使用即可。根据官网提示,这两种提示框返回的都是一个div标签,可以使用g6-tooltip为节点和边的悬浮提示框设置一样的样式。如果需求自定义边和节点的可以在返回内容里包含一个带不同class的标签容器。

js
const graph = new G6.Graph({
      modes: {
        default: [
        'drag-canvas', 'zoom-canvas', 'drag-node',
          {
            type: 'tooltip',
            formatText(model) {
              console.log(model)
              return 'label: ' + model.label + '<br /> class: '+ model.class;
            }
          },
          {
            type: 'edge-tooltip',
            formatText(model) {
              // 边提示框文本内容
              return 'source: ' + model.source + '<br/> target: ' + model.target + '<br/> weight: ' + model.weight;
            },
          }
        ],
        edit: []
      },
  })

内置工具

  • Legend 图例插件。用于说明图中不同类型的节点和边所代表的含义,并可以通过与图例的交互做简单的高亮和过滤。

  • SnapLine 对齐线插件。

  • Grid Grid插件在画布上绘制了网格。

  • Minimap 用于快速预览和探索图的工具

  • Image Minimap 对于Minimap插件的优化版

  • Edge Bundling 在关系复杂、繁多的大规模图上,通过边绑定可以降低视觉复杂度。

  • Menu 用于配置节点上的右键菜单

  • Toolbar 集成了以下常见的操作:

  • 重做

  • 撤销

  • 放大

  • 缩小

  • 适应屏幕

  • 实际大小

  • ToolTip 主要用于在节点和边上展示一些辅助信息,G6 4.0以后,Tooltiop插件将会替换Behavior中的tooltip。

  • Fisheye Fisheye鱼眼放大镜为focus+context的探索场景设计的,它能够保证在放大关注区域的同时,保证上下文以及上下文与关注中心的关系不丢失。

  • Edge Filter Lens 边过滤镜可以将关注的边保留在过滤镜范围内,其他边将在该范围内不显示。

  • TimeBar 内置了三种形态的TimeBar组件:带有趋势图的、简易版的、刻度的。

节点

内置节点

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

配置方法

支持三种配置方式:实例化图时全局配置,优先级最低、在数据中动态配置、使用graph.node(nodeFn)函数配置,优先级最高。id、label只能配置在每个节点的数据,其他属性三种配置都支持。

实例化图时全局配置

实例化图时通过defaultNode属性配置节点,这里是全局配置,在所有节点上都会生效

在数据中动态配置

既是传给graph.data函数参数的数据对象的属性nodes中的数据。

使用graph.node

该方法可以为不同节点进行不同的配置。

提示

  • 必须在render之前调用,否则不起作用。
  • 该方法优先级最高,可能会覆盖其他节点的配置,这会造成一些其他配置不生效的疑惑。
  • 该方法在增加元素、更新元素时会被调用,如果数据里大,每个节点需要更新的内容多时,可能会有性能问题。
js
graph.node((node) => {
    return {
        id: node.id,
        type: 'rect',
        style: {
            fill: 'blue'
        }
    }
})

方法

nodeItem.toFront()

将节点实例nodeItem提前到其父级group的最前面

nodeItem.toBack()

将节点实例nodeItem放置到其父级group的最后面

nodeItem.show()

显示节点,调用后设置visible为true

nodeItem.hide()

隐藏节点,调用后设置visible为false

lock()

锁住节点。锁住后,拖动节点没有任何反应。但是拖动画布时,还是会有影响的。如果要不影响要自定义behavior的方法来实现。 https://g6.antv.antgroup.com/manual/middle/elements/methods/lock-node

unlock()

解锁节点

hasLocked()

判断当前节点是否上锁

配置

配置内容如下

js
{
    id: 'node1', // 节点的唯一标识 必填
    type: 'circle', // 元素的图形,默认为circle
    size: 40, // 元素的大小
    x: 200, // 节点的横坐标
    y: 300, // 节点的纵坐标
    label: 'text'// 节点显示的本文
    visible: true, // 控制初次渲染显示隐藏,false为隐藏
    labelCfg: { // 标签配置属性
        position: 'center' // 标签在元素中的位置
        style: {    // 标签样式属性对象,和标签其他属性并行
            fontSize: 12, // 标签的样式属性,文字字体大小
            // ...
        }
    },
    style: { // 样式属性对象,和元素其他属性并行
        fill: '#000', // 样式属性,元素的填充色
        stroke: '#888', // 元素的描边色
        // ... 其他样式属性
    },
    anchorPoints: [0, 0], //指定边连入节点的位置(相对于该节点而言),可以为空
    linkPoints:{ // 指定节点周围【上下左右】四个方向上的四个小圆点。
    }
}

linkPoints:

anchorPoints是真正用于指定该节点相关边的连入位置的数组,而linkPoints仅是指定是否绘制出四个圆点,不直实际的连接相关边的作用。

自定义节点

通过G6.registerNode(typeName: string, nodeDefinition: object, extendedNodeType?: string)进行自定义节点。 typeName: 新节点类型名称。

extendedNodeType: 被继承的节点类型,可以内置的也可以自定义的,不指定则不继承其他类型节点。 注意:若指定继承节点类型,且在nodeDefinition中没有复写draw, update, setState等必要函数时,将会继承extendedNodeType中的相关定义。这可能会导致一些意外的问题。

  • Q:节点/边更新时,没有按照在 nodeDefinition 中自定义实现的 draw 或 drawShape 逻辑更新。例如,有些图形没有被更新,增加了没有在 draw 或 drawShape 方法中定义的图形等。

  • A:由于继承了 extendedNodeType,且在 nodeDefinition 中没有复写 update 方法,导致节点/边更新时执行了 extendedNodeType 中的 update 方法,从而与自定义的 draw 或 drawShape 有出入。可以通过复写 update 方法为 undefined 解决。当 update 方法为 undefined 时,节点/边的更新将会执行 draw 或 drawShape 进行重绘。

js
import G6 from "@antv/g6";

G6.registerNode(
  'nodeName', {
    options: {
      style: {},
      stateStyles: {
        hover: {},
        selected: {},
      }
    },

    /**
     * 绘制节点,包含本文
     * @param {Object} cfg 节点的配置项
     * @param {G.Group} group 图形分组,节点中图形对象的容器
     * @return {G.Shape} 返回一个绘制的图形作为keyShape,通过node.get('keyShape') 可以获取。
     */
    draw(cfg, group) {},

    /**
     * 绘制后的附加操作,默认没有任何操作
     * @param {Object} cfg 节点的配置项
     * @param {G.Group} group 图形分组,节点中图形对象的容器
     */
    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) {},

    /**
     * 获取锚点(相关边的连入点)
     * @param {Object} cfg 节点的配置项
     * @return {Array|null} 锚点(相关边的连入点)的数组,如果为null则没有控制点
     */
    getAnchorPoints(cfg) {},
  },
  // 继承内置节点类型的名字,例如基类 'single-node',或'circle', 'rect'
  // 不指定则不继承任何类型节点
  'extendNodetype'
)

注意:

  1. extendedNodeType不写,draw方法是必须的。
  2. 节点内部所有图形的坐标系是相对于节点本身的坐标,即(0,0)是该节点的中心。而节点的坐标是相对于画布的,由该节点group上的矩阵控制。
  3. update方法未定义时:若指定了extendedNodeType,则节点更新时执行继承节点类型的update方法逻辑;若未指定extendedNodeType时,则节点更新时会执行draw方法,所有图形清除重绘。
  4. 指定update方法,不论是否指定extendedNodetype,节点更新时都会执行复写的update函数逻辑。
  5. afterDraw,afterUpdate方法一般用于扩展已有节点,例如,在矩形节点上附加图片,圆节点增加动画等;
  6. setState只有在需要使用动画的方式响应状态变化时需要复写,一般的样式响应状态变化可以通过配置状态样式实现
  7. getAnchorPoints方法仅在需要限制与边的连接点时才需要复写,也可以数据中直接指定。

优化性能

根据上面注意事项3和4,如果存在性能问题,可以通过重写update方法,找到需要更新的shape进行更新,从而优化性能。

节点的连接点

节点的连接点anchorPoint指的是边连入节点的相对位置,即是节点和边的交点位置。 anchorPoint是一个二维数组,每一项都是一个连接点,只有定义了才会有连接点,不定义的是不存在的,在一个图形Shape中,连接点的位置如下,x和y方向上范围都是[0, 1]:

图片

节点定义了anchorPoint之后,边通过sourceAnchor指定anchorPoint数组中的索引作为连接交点的起点,通过targetAnchor指定anchorPoint数组中的索引作为连接交点的终点。

内置边:

  • line:直线,不支持控制点;
  • polyline:折线,支持多个控制点;
  • arc:圆弧线;
  • quadratic:二阶贝塞尔曲线;
  • cubic:三阶贝塞尔曲线;
  • cubic-vertical:垂直方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点;
  • cubic-horizontal:水平方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点;
  • loop:自环。

配置方法

和节点一样,有全局配置,数据中配置和使用graph.edge(edgeFn)三种配置方法

配置

配置内容如下

json
{
    source: 'node1', // 起始节点的ID 必填
    target: 'node2', // 结束节点的ID 必填
    label: 'label', // 边上显示的文本
    type: 'line', // 默认为line,内置边
    sourceAnchor: 0, // 边的起始节点上的锚点的索引值
    targetAnchor:0, // 边的终止节点上的锚点的索引值
    style: { // 边的样式
        lineAppendWidth: 1, // 边响应鼠标事件检测的宽度,
        endArrow: false|Object, // true边的终点绘制默认箭头, 也可以对象自定义
        startArrow:  false|Object, // true边的起点绘制默认箭头, 也可以对象自定义
        // ... 其他一样
    },
    label: '', //文本文字,没有不显示
    labelCfg:{// 文本配置项
        refX: 0, // 标签在x方向的偏移量
        refY: 0, // 标签在y方向的偏移量
        position: 'middle', //文本相对于边的位置,目前支持的位置有:'start','middle','end'。默认为'middle'。
        autoRotate: false, // 标签文本是否跟随边旋转, 默认false
        style:{}, // 标签样式
    }, 
}

方法

  • edgeItem.toFront() 将边edgeItem提前到其父级group的最前面

  • edgeItem.toBack() 将边edgeItem放置到其父级group的最后面

  • edgeItem.show() 显示边,调用后设置visible为true

  • edgeItem.hide() 隐藏边,调用后设置visible为false

内置类型

  • polyline
js
// 独有的配置
{
    routeCfg: {// 用以配置路由计算的参数,不存在controlPoints时生效
        gridSize: 10, // 计算拆线的网格大小,值越小性能消耗越高
        maxAllowedDirectionChange: Math.PI / 2, // 允许的最大转角角度, 弧度制
        obstacles: [], // 需要躲避的障碍节点对象
    },
    style: {
        radius: 1, // 拐弯处的圆角弧度
        offset: 5, // 拐弯处距离节点最小距离
    },
    controlPoints: [{x: 10, y: 10}, ...], // 其他边也有这个,不指定时根据
    
}

obstacles

不支持自动躲避所有节点,只能通过例如graph.updateItem(edge, { routeCfg: { obstacles: [graph.findById('node1')]}})的方式手动增加

controlPoints

其他边也有这个,不指定时根据算法自动生成,若指定时,根据指定的坐标进行弯折,坐标是根据画布定位的,一个坐标对应一个折点。

  • 自定义边
  • 自定义箭头

Combo

Combo是对节点进行分组。内置的combo有两种,circle和rect 两种。 使用combo时,必须在实例化图时配置groupByTypes设置为false,图中元素的视觉层级才能合理。

配置

使用combo时,在数据中,和nodes、edges同一层级加上combos,是一个数组,每个数组元素是combo的配置,如下:

js
{
    id: '', // 唯一标识,也是其他节点归类combo引用的字段,comboId
    type: '', // combo的类型,默认为circle.
    parentId: '', // 该combo的父combo的ID
    padding: number|number[], // 内边距
    size: number|number[], // combo的最小尺寸(非固定尺寸),circle为20,rect为[20, 5]
    fixSize: number|number[], // 固定尺寸
    fixCollapseSize: number|number[], // 折叠时的尺寸
    collapsed: false, // 该combo是否收起,如果渲染前配置true,初次渲染时将默认收起
    label: '', // combo的文本标签
    style:{ // 样式配置项
    },
    labelCfg: { // 文本标签的样式配置项
    },
    collapsedSubstituteIcon: {// v4.6.8起支持,combo收起状态下展示的图片
    },
}

fixSize

不指定时combo大小由内部元素的分布和大小来决定。若指定了fixSize,而没有指定fixCollapseSize时,combo即时是收起折叠状态仍然保持fixSize的尺寸。

fixCollapseSize

固定该combo折叠收起时的尺寸。不指定时,若未指定fixSize则由size决定收起时的尺寸,否则统一为fixSize尺寸

配置方法

和节点一样,有全局配置,数据中配置和使用graph.combo(edgeFn)三种配置方法

Combo交互

和其他交互一样的配置,内置的combo交互有三种:drag-combo, collapse-expand-combo, drag-node

自定义combo

和节点一样,通过G6.registerCombo('comboName', options, expendedComboName)进行自定义扩展内置的Combo。 自定义时需要以下两点

  • 控制combo的生命周期
  • 解析用户输入的数据,在图形上展示
js
import G6 from "@antv/g6";
G6.registerCombo(
    'comboName',
    {
        /**
         * 绘制Combo中的图形,不需要为默认的label增加图形,父类方法会自动增加label
         * @param {Object} cfg Combo的配置项
         * @param {G.group} group 图形分组, Combo中的图形对象的容器
         * @return {G.shape} 返回一个绘制的图形作为keyShape, 通过combo.get('keyShape'),可以获取
         */
        drawShape(cfg, group){},
        /**
         * 绘制后的附加操作,默认没有任何操作
         * @param  {Object} cfg Combo 的配置项
         * @param  {G.Group} group 图形分组,Combo 中的图形对象的容器
         */
        afterDraw(cfg, group) {},
        /**
         * 更新节点后的操作,新增的图形需要在这里控制其更新逻辑
         * @override
         * @param  {Object} cfg 节点的配置项
         * @param  {Combo} combo 节点
         */
        afterUpdate(cfg, combo) {},
        /**
         * 响应 Combo 的状态变化。
         * 在需要使用动画来响应状态变化时需要被复写,其他样式的响应参见下文提及的 [配置状态样式] 文档
         * @param  {String} name 状态名称
         * @param  {Object} value 状态值
         * @param  {Combo} combo 节点
         */
        setState(name, value, combo) {},
    },
    // 被继承的 Combo 类型名,可选:'circle' 或 'rect'
    'circle',
)

注意事项https://g6.antv.antgroup.com/manual/middle/elements/combos/custom-combo#注意事项必读

  1. 在drawShape中不需要添加label图形,父类方法自动添加label,可以通过配置方式指定label的位置和样式。
  2. 与自定义节点边不同,不建议复写,update和draw方法,否则会使用combo根据子元素更新的逻辑异常。
  3. 复写drawShpae方法的返回值推荐与继承内置的circle/rect的keyShape一致。即继承circle时返回 一个cirele图形,继承rect时,返回 一个rect图形。
  4. 除keyShape外,自定义新增的图形需要在afterUpdate中定义其位置更新逻辑。

内置 Rect Combo 位置逻辑详解

https://g6.antv.antgroup.com/manual/middle/elements/combos/custom-combo#内置-rect-combo-位置逻辑详解

  1. 下图灰色虚线框是子元素分布范围,高宽分别为innerHeight, innerWidth。
  2. 虚线框外面还有padding,该combo的keyShape的width和height分别是innerWidth + padding,innerHeight+padding。
  3. combo的内部图形是以自身坐标为参考系,虚线框的正中心为原点。
  4. 由于padding上下左右不对称,(X, Y)的坐标,不是简单的(-width/2, -height/2)。
  5. rect的combo的label是左上角,上边距为refX,左边距为refY。
js
drawShape: function drawShape(cfg, group) {
    const self = this;
    const style = self.getShapeStyle(cfg);
    // style.width 对应的是combo的宽,即是keyShape的width,innerWidth + padding[1] + padding[3]
    // style.height 对应的是combo的高,即是keyShape的height ,innerHeight+ padding[0] + padding[2]
    
    // cfg.style.width 子元素分布的宽度innerWidth,这个不包含padding
    // cfg.style.height 子元素分布的宽度innerHeight,这个不包含padding
}

图片

路径PATH函数命令

大写是使用绝对定位,也就是说是坐标轴定位。小写是相对定位,从上一个位置开始。如m 10 10, 是从当前位置向上移动10个单位,向右移10个单位

  • M 移动画笔,不作画,如:M 10 10,将画笔移到坐标为(10,10)的位置

  • L 画线,如L 10 10,从当前位置到坐标为(10,10)的位置两点间画一条线段。

  • H 绘制水平线, H 10,从当前位置到X轴位置 10 间水平画一条线段。

  • V 绘制垂直线, V 10,从当前位置到Y轴位置 10 间垂直平画一条线段。

  • Z 从当前位置画一条线到路径的起始位置完成闭合。

  • C 三次贝塞尔曲线,需要三个坐标,第一个控制点,第二控制点,曲线点,如 C x1 y1, x2 y2, x y;

  • Q 二次贝塞尔曲线,需要二个坐标,第一个控制点,曲线点,如 C x1 y1, x y;

  • A 画弧线

问题

手动调用布局时在graph.read()后面监听afterrender事件不生效

https://github.com/antvis/G6/issues/2598

js
// 引入dagre布局
import { DagreLayout } from '@antv/layout/es/layout/dagre';

export function calcPositionDagre(options, data) {
  const dagreLayout = new DagreLayout(options);
  // 计算出坐标
  dagreLayout.layout(data);
}

// 不生效 
graph.read(data)
graph.on('afterrender', fn) // 不生效

// 改成这样才生效
graph.data(data)
graph.on('afterrender', fn) // 生效
graph.render()

修改坐标不生效

修改坐标后不生效,实际要调用graph.refreshPositions()才生效

修改边的sourceAnchor和targetAnchor时会影响边startPoint 和 endPoint 的位置

当计算坐标需要startPoint 和 endPoint 的位置,且需要更新sourceAnchor和targetAnchor时,只能先更新sourceAnchor和targetAnchor的位置。