diff --git a/docs/manual/introduction.zh.md b/docs/manual/introduction.zh.md index ce439428e4..dc9ea05073 100644 --- a/docs/manual/introduction.zh.md +++ b/docs/manual/introduction.zh.md @@ -5,7 +5,7 @@ redirect_from: - /zh/docs/manual --- -![](https://user-images.githubusercontent.com/6113694/45008751-ea465300-b036-11e8-8e2a-166cbb338ce2.png) + [![](https://img.shields.io/travis/antvis/g6.svg)](https://travis-ci.org/antvis/g6) ![](https://img.shields.io/badge/language-javascript-red.svg) diff --git a/docs/manual/middle/bindEvent.md b/docs/manual/middle/bindEvent.md new file mode 100644 index 0000000000..2439f49d8c --- /dev/null +++ b/docs/manual/middle/bindEvent.md @@ -0,0 +1,31 @@ +--- +title: 监听和绑定事件 +order: 1 +--- + +除了 [内置交互行为 Behavior](./defaultBehavior) 和 [交互模式 Mode](./mode) 搭配的事件管理方式外,G6 提供了直接的单个事件、时机的监听方法,可以监听画布、节点、边、以及各函数被调用的时机等。这些事件可以分为以下四个层次: + +- 画布、图形层次的事件,`mousedown`, `mouseup`,`click`,`mouseenter`,`mouseleave` 等; +- 节点/边 上的事件,`node:mousedown`, `edge:click` 等,以 `type:eventName` 为事件名称; +- 时机事件: + - 节点/边增删改时的事件, 例如:`beforeadditem` , `afteradditem` 等; + - 节点/边状态改变时的事件,例如:`beforerefreshitem`,`afterrefreshitem`。 + - 布局时机,例如:`beforelayout`,`afterlayout`。 + +如果要了解G6支持的所有事件,请参考[Event文档](https://www.yuque.com/antv/g6/event-api)。 + +G6 上所有的事件都需要在graph上监听。 +```javascript +graph.on('click', ev => { + const shape = ev.target; + const item = ev.item; + if (item) { + const type = item.getType(); + } +}); + +graph.on('node:click', ev => { + const shape = ev.target; + const node = ev.item; +}); +``` diff --git a/docs/manual/middle/defaultBehavior.md b/docs/manual/middle/defaultBehavior.md new file mode 100644 index 0000000000..ea146f3ccb --- /dev/null +++ b/docs/manual/middle/defaultBehavior.md @@ -0,0 +1,389 @@ +--- +title: 内置的 Behavior +order: 4 +--- + + +## 什么是 Behavior +Behavior 是 G6 提供的定义图上交互事件的机制。它与[交互模式 Mode](https://www.yuque.com/antv/g6/g6-mode) 搭配使用,如何将下文所述各种 Behavior 配置到图上,见 [交互模式](https://www.yuque.com/antv/g6/g6-mode)。 + + +## 内置 Behavior +理论上说 G6 上的所有基础图形、Item(节点/边)都能通过事件来进行操作,考虑到通用性, G6目前共提供了以下9个内置的 Behavior。 + + +### drag-canvas + +- 含义:拖拽画布; +- `type: 'drag-canvas'`; +- `direction`: 允许拖拽方向,支持`'x'`, `'y'`,`'both'`,默认方向为 `'both'`。 + +**默认配置** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ 'drag-canvas' ] + } +}) +``` + +默认配置下,可以在 x 和 y 两个方向上拖动画布。 + +**配置参数** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ + { + type: 'drag-canvas', + direction: 'x' + } + ] + } +}) +``` + +此时只能在 x 方向上面拖动,y 方向上不允许拖动。
![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570778658995-88e2bf4e-e201-43a0-9ffd-15ceadc8334e.gif#align=left&display=inline&height=333&name=3.gif&originHeight=517&originWidth=783&search=&size=669012&status=done&width=504) + + +### zoom-canvas + +- 含义:缩放画布; +- `type: 'zoom-canvas'`; +- `sensitivity`: 缩放灵敏度,支持 1-10 的数值,默认灵敏度为 5。 + +**提示:若要限定缩放尺寸,请在 graph 上设置 **`**minZoom**`** 和 **`**maxZoom**`**。** + + +### drag-node + +- 含义:拖拽节点; +- `type: 'drag-node'`; +- `delegateStyle`: 节点拖拽时的绘图属性,默认为 `{ strokeOpacity: 0.6, fillOpacity: 0.6 }`; +- `updateEdge`: 是否在拖拽节点时更新所有与之相连的边,默认为 `true` 。 +- 3.1.2 `enableDelegate`:拖动节点过程中是否启用 `delegate`,即在拖动过程中是否使用方框代替元素的直接移动,效果区别见下面两个动图。默认值为 `false`。 + +**默认配置** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ 'drag-node' ] + } +}) +``` +![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570777651736-e68e2d92-eabe-4b58-bc39-66a6cfbd6cf5.gif#align=left&display=inline&height=374&name=3.gif&originHeight=517&originWidth=783&search=&size=149678&status=done&width=567) + +**启用** `delegate` +```javascript +const graph = new G6.Graph({ + modes: { + default: [ + { + type: 'drag-node', + enableDelegate: true + } + ] + } +}) +``` +![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570778113574-f65eeb6b-4df4-4db4-a4d3-5cf2141607f3.gif#align=left&display=inline&height=279&name=3.gif&originHeight=517&originWidth=783&search=&size=219983&status=done&width=422) + + +### click-select + +- 含义:点击选中节点,再次点击节点或点击 Canvas 取消选中状态; +- `type: 'click-select'`; +- `multiple`: 是否允许多选,默认为 `true`,当设置为 `false`,表示不允许多选,此时 `trigger` 参数无效。 +- 3.1.2 `trigger`: 指定按住哪个键进行多选,默认为 shift,按住 Shift 键多选,用户可配置 shift、ctrl、alt; + +**默认配置**
** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ 'click-select' ] + } +}) +``` + +按住 **`Shift`** 键可多选。
![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570778352084-ca8b1694-0e10-4dfa-b69e-2fc35130b9a9.gif#align=left&display=inline&height=517&name=3.gif&originHeight=517&originWidth=783&search=&size=48383&status=done&width=783) + +**配置参数** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ + { + type: 'click-select', + trigger: 'ctrl' + } + ] + } +}) +``` + +以上配置中,用户可按住 **Ctrl** 键进行多选,也可以配置 **Alt** 键。当配置了 `multiple` 参数为 `false`,则表示不允许多谢,此时 `trigger` 参数无效。 + + +### tooltip + +- 含义:节点文本提示; +- `type: 'tooltip'`; +- `formatText(model)` 格式化函数,可以返回文本或者 HTML; +```javascript +const graph = new G6.Graph({ + container: 'mountNode', + width: 500, + height: 500, + modes: { + default: [{ + type: 'tooltip', + formatText(model) { + return model.xxx; + } + }], + } +}); +``` + +**提示:由于 G6 没有内置任何 tooltip 的样式,用户需要自己定义样式,例如:** +```css +.g6-tooltip { + padding: 10px 6px; + color: #444; + background-color: rgba(255,255,255,0.9); + border: 1px solid #e2e2e2; + border-radius: 4px; +} +``` + + +### edge-tooltip +使用方式基本与 tooltip 相同,但是移到边时触发。主要是为了将两个交互区分开,以满足用户边与节点的提示样式或 HTML 结构不同,以及不需要在事件中去区分是节点事件还是边事件等。 + +- 含义:边文本提示; +- `type: 'edge-tooltip'`; +- `formatText(model)` 格式化函数,可以返回文本或者 HTML。 + + +### activate-relations + +- 含义:当鼠标移到某节点时,突出显示该节点以及与其直接关联的节点和连线; +- `type: 'activate-relations'`; +- 参数: + - `trigger: 'mouseenter'`, 可以是 `mousenter` , 鼠标移入时触发;也可以是 `click` ,鼠标点击时触发; + - `activeState: 'active'`, 活跃节点状态;当行为被触发,需要被突出显示的节点和边都会附带此状态,默认值为 `active`;可以与 graph 实例的 `nodeStyle` 和 `edgeStyle` 结合实现丰富的视觉效果。 + - `inactiveState: 'inactive'`,非活跃节点状态,不需要被突出显示的节点和边都会附带此状态,默认值为 `inactive`;可以与 graph 实例的 `nodeStyle` 和 `edgeStyle` 结合实现丰富的视觉效果; + - 3.1.2 `resetSelected`:高亮相连节点时是否重置已经选中的节点,默认为false,即选中的节点状态不会被 `activate-relations` 覆盖。 + + +
**默认配置**
+ +```javascript +const graph = new G6.Graph({ + modes: { + default: [ 'activate-relations' ] + } +}) +``` +默认情况下,选中的节点状态,在操作完以后仍然会保持选中状态。
![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570783971145-6588e49f-79d7-40b4-aa66-3308f060f2b4.gif#align=left&display=inline&height=542&name=3.gif&originHeight=542&originWidth=610&search=&size=358920&status=done&width=610) + +**配置参数** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ + { + type: 'activate-relations', + resetSelected: true + } + ] + } +}) +``` + +配置 `resetSelected` 参数为 `true` 后,交互后会重置节点的选择状态。 + +![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570784093933-beb50a11-eef7-4076-a05c-5723be7e7e1d.gif#align=left&display=inline&height=542&name=3.gif&originHeight=542&originWidth=610&search=&size=142174&status=done&width=610) + + + +### brush-select + +- 含义:拖动框选节点; +- `type: 'brush-select'`; +- 参数: + - `brushStyle`:拖动框选框的样式; + - `onSelect(nodes)`:选中节点时的回调,参数 `nodes` 表示选中的节点; + - `onDeselect(nodes)`:取消选中节点时的回调,参数 `nodes` 表示取消选中的节点; + - `brushStyle`:框选时样式的配置项,包括 `fill`、`fillOpacity`、`stroke` 和 `lineWidth` 四个属性; + - `selectedState`:选中的状态,默认值为 `'selected'`; + - `includeEdges`:框选过程中是否选中边,默认为 `true`,用户配置为 `false` 时,则不选中边; + - 3.1.2 `trigger`:触发框选的动作,默认为 `'shift'`,即用户按住 Shift 键拖动就可以进行框选操作,可配置的的选项为: `'shift'`、`'ctrl' / 'control'`、`'alt'` 和 `'drag'` ,不区分大小写: + - `'shift'`:按住 Shift 键进行拖动框选; + - `'ctrl' / 'control'`:按住 Ctrl 键进行拖动框选; + - `'alt'`:按住 Alt 键进行拖动框选; + - 风险 `'drag'`:不需要按任何键,进行拖动框选,如果同时配置了 `drag-canvas`,则会与该选项冲突。 + +**默认配置** + +```javascript +const graph = new G6.Graph({ + modes: { + default: [ 'brush-select' ] + } +}) +``` +默认情况下,按住 Shift 键进行框选,选中节点的同时,也会选中边。
![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570779252901-1efaccf6-a268-47a6-8db9-f63c82d355fe.gif#align=left&display=inline&height=542&name=3.gif&originHeight=542&originWidth=610&search=&size=188323&status=done&width=610) + +**配置参数** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ + { + type: 'brush-select', + trigger: 'ctrl', + includeEdges: false + } + ] + } +}) +``` + +上面的配置,按住 Ctrl 键,进行框选,框选过程中不会选中边。
![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570779434063-6bf4fe39-88c8-44c2-a25d-6b8980db4a39.gif#align=left&display=inline&height=370&name=3.gif&originHeight=542&originWidth=610&search=&size=115882&status=done&width=416) + +**配置冲突** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ 'drag-canvas', + { + type: 'brush-select', + trigger: 'drag' + } + ] + } +}) +``` + +当用户配置 `brush-select` 的 `trigger` 为 `drag`,同时又配置了 `drag-canvas` 时,在交互上面会出现冲突的情况。
![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570779665370-63bb8a65-f4e3-4a05-8c42-21b2e79b6b76.gif#align=left&display=inline&height=412&name=3.gif&originHeight=542&originWidth=610&search=&size=559913&status=done&width=464) + +可以看到,在拖动过程中也出现了框选的情况,这种情况很显然不是我们期望的效果,除过使用 `brush-select `的 `trigger` 参数避免这种冲突外,我们还可以通过下面的方式来实现: + +```javascript +const graph = new G6.Graph({ + modes: { + default: [ 'drag-canvas' ], + brush: [ + { + type: 'brush-select', + trigger: 'drag' + } + ] + } +}) +``` + +上面这种方式是使用不同的 mode 来区分,mode 可以达到使用相同交互动作而产生不同的效果,更多关于 mode 的内容请参数 [G6 中的 Mode 文档](https://www.yuque.com/antv/g6/g6-mode)。 + +使用 mode 区分,默认情况下使用的是 `drag-canvas`,但用户需要切换到框选时,通过 `graph.setModel('brush')` 即可实现,此时同样的交互产生的就是框选的效果。 + + +### collapse-expand + +- 含义:只适用于树图,展开或收起节点; +- `type: 'collapse-expand'`; +- 参数: + - `trigger`:收起和展开树图的方式,支持`click`和`dblclick`两种方式,默认为`click`; + - `onChange`:收起或展开的回调函数,警告 `3.1.2 `版本中将移除。 + + + +**用法** + +```javascript +const graph = new G6.TreeGraph({ + modes: { + default: [{ + type: 'collapse-expand', + trigger: 'click', + onChange(item, collapsed) { + const data = item.get('model').data; + data.collapsed = collapsed; + return true; + } + }, 'drag-canvas', 'zoom-canvas'] + } +}); +``` + + +### collapse-expand-group + +- 含义:收起和展开群组; +- `type:'collapse-expand-group'` +- 参数: + - 3.1.2 trigger:收起和展开节点分组的方式,支持`click`和`dblclick`两种方式,默认为`dblclick` + +**默认配置** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ 'collapse-expand-group' ] + } +}) +``` + +**配置参数**
配置 `trigger` 参数为 **`click`** 后,单击节点分组即可收起或展开分组。 + +```javascript +const graph = new G6.Graph({ + modes: { + default: [ + { + type: 'collapse-expand-group', + trigger: 'click' + } + ] + } +}) +``` + +![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570785874686-a7333f95-e8d3-45a7-873e-8ee56c3b4b21.gif#align=left&display=inline&height=542&name=3.gif&originHeight=542&originWidth=610&search=&size=57719&status=done&width=610) + +### drag-group +3.1.0 + +- 含义:拖动节点分组; +- `type: 'drag-group'`; +- 参数: + - `delegateStyle`:拖动节点分组时 `delegate` 的样式。 + +**默认配置** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ 'drag-group' ] + } +}) +``` + + +### drag-node-with-group +3.1.0 + +- 含义:拖动节点分组中的节点; +- `type:'drag-node-with-group'`; +- 参数: + - `delegateStyle`:拖动节点分组时 `delegate` 的样式; + - `maxMultiple`: + - `minMultiple`。 + +**默认配置** +```javascript +const graph = new G6.Graph({ + modes: { + default: [ 'drag-node-with-group' ] + } +}) +``` diff --git a/docs/manual/middle/defaultEdge.md b/docs/manual/middle/defaultEdge.md new file mode 100644 index 0000000000..be60cf9fc6 --- /dev/null +++ b/docs/manual/middle/defaultEdge.md @@ -0,0 +1,296 @@ +--- +title: 内置的边 +order: 3 +--- + +G6 提供了 9 种内置边: + +- line:直线,不支持控制点; +- polyline:折线,支持多个控制点; +- arc:圆弧线; +- quadratic:二阶贝塞尔曲线; +- cubic:三阶贝塞尔曲线; +- cubic-vertical:垂直方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点; +- cubic-horizontal;水平方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点; +- loop:自环。 + +这些内置边的默认样式分别如下图所示。
+ + + +# 内置边类型说明 +下面表格中显示了内置的各类边,同时对一些特殊的字段进行了说明: + +| 名称 | 描述 | | +| --- | --- | --- | +| line | 连接两个节点的直线:
- controlPoints 不生效
- 更多配置详见 line 边的配置
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570858805015-2171552a-56fc-44f9-a8d0-608de6aeb3f8.png#align=left&display=inline&height=36&name=image.png&originHeight=72&originWidth=210&search=&size=6061&status=done&width=105) | +| polyline | 多段线段构成的折线,连接两个端点:
- controlPoints 表示所有线段的拐点,不指定时根据 [A* 算法](https://yuque.alibaba-inc.com/antv/blog/polyline-edges-with-border-radius)自动生成折线
- 更多配置详见 polyline 边的配置
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570858897304-9b5e3045-4b8c-4e84-8373-7fda9ca2193a.png#align=left&display=inline&height=105&name=image.png&originHeight=210&originWidth=222&search=&size=12334&status=done&width=111) | +| arc | 连接两个节点的一段圆弧:
- controlPoints 不生效
- 使用 curveOffset 指定弧的弯曲程度,其正负影响弧弯曲的方向
- 更多配置详见 arc 边的配置
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570858921616-3dc5034d-ede0-425f-874b-620af6fe2dc9.png#align=left&display=inline&height=49&name=image.png&originHeight=98&originWidth=218&search=&size=8131&status=done&width=109) | +| quadratic | 只有一个控制点的曲线:
- controlPoints 不指定时,会默认线的一半处弯曲
- 更多配置详见 quadratic 边的配置
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570858940562-cea717dc-c0be-4bd1-af07-0f71e22f9243.png#align=left&display=inline&height=48&name=image.png&originHeight=96&originWidth=214&search=&size=8780&status=done&width=107) | +| cubic | 有两个控制点的曲线:
- controlPoints 不指定时,会默认线的 1/3, 2/3 处弯曲
- 更多配置详见 cubic 边的配置
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570858972322-2ba56d44-bd65-4fbb-9de2-a0c4bbbc8e8d.png#align=left&display=inline&height=36&name=image.png&originHeight=72&originWidth=216&search=&size=8066&status=done&width=108) | +| cubic-vertical | 垂直方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点 | ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570858985655-b18e4465-0534-4dbf-a097-460a967d1100.png#align=left&display=inline&height=109&name=image.png&originHeight=218&originWidth=222&search=&size=15336&status=done&width=111) | +| cubic-horizontal | 水平方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点 | ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570858999282-e9e4d9c1-f2da-4804-975f-d4abed62933f.png#align=left&display=inline&height=114&name=image.png&originHeight=228&originWidth=206&search=&size=16769&status=done&width=103) | +| loop | 自环。更多配置详见 arc 边的配置 | ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570859007824-5b9c3023-9851-4bda-917b-3216811d2e45.png#align=left&display=inline&height=56&name=image.png&originHeight=112&originWidth=76&search=&size=6558&status=done&width=38) | + + + +# 边的通用属性 +所有内置的边支持的通用属性: + +| 名称 | 是否必须 | 类型 | 备注 | +| --- | --- | --- | --- | +| id | false | String | 边编号 | +| source | true | String | Number | 起始点 id | +| target | true | String | 结束点 id | +| shape | false | String | 边图形,默认为 'line' | +| sourceAnchor | false | Number | 边的起始节点上的锚点的索引值 | +| targetAnchor | false | Number | 边的终止节点上的锚点的索引值 | +| style | false | Object | 边的样式属性 | +| label | false | String | 文本文字,如果没有则不会显示 | +| labelCfg | false | Object | 文本配置项 | + + + +### 样式属性 style +Object 类型。通过 `style` 配置来修改边的颜色、线宽等属性。下表是 `style` 对象中常用的配置项: + +| 名称 | 是否必须 | 类型 | 备注 | +| --- | --- | --- | --- | +| stroke | false | String | 边的颜色 | +| lineWidth | false | Number | 边宽度 | +| lineAppendWidth | false | Number | 边响应鼠标事件时的检测宽度,当 `lineWidth` 太小而不易选中时,可以通过该参数提升击中范围 | +| endArrow | false | Boolean | 边的结束端是否有箭头 | +| strokeOpacity | false | Number | 边透明度 | +| shadowColor | false | String | 阴影颜色 | +| shadowBlur | false | Number | 阴影范围 | +| shadowOffsetX | false | Number | 阴影 x 方向偏移量 | +| shadowOffsetX | false | Number | 阴影 y 方向偏移量 | +| ... | | | | + + +下面代码演示在实例化图时全局配置方法中配置 `style`: +```javascript +const graph = new G6.Graph({ + container: 'mountNode', + width: 800, + height: 600, + defaultEdge: { + // ... 其他属性 + style: { + stroke: '#eaff8f', + lineWidth: 5, + // ... 其他属性 + } + } +}) +``` + + +### 标签文本 label 及其配置 labelCfg +`label` String 类型。标签文本的文字内容。
`labelCfg` Object 类型。配置标签文本。下面是 `labelCfg` 对象中的常用配置项: + +| 名称 | 是否必须 | 类型 | 备注 | +| --- | --- | --- | --- | +| refX | false | Number | 标签在 x 方向的偏移量 | +| refY | false | Number | 标签在 y 方向的偏移量 | +| position | false | String | 文本相对于边的位置,目前支持的位置有: `start`,`middle`, `end`。默认为`middle`。 | +| autoRotate | false | Boolean | 标签文字是否跟随边旋转,默认 `false` | +| style | false | Object | 标签的样式属性 | + + +上表中的标签的样式属性 `style` 的常用配置项如下:  + +| 名称 | 是否必须 | 类型 | 备注 | +| --- | --- | --- | --- | +| fill | false | String | 文本颜色 | +| stroke | false | String | 文本描边颜色 | +| lineWidth | false | Number | 文本描边粗细 | +| opacity | false | Number | 文本透明度 | +| font | false | String | 文本内容的当前字体属性 | +| fontSize | false | Number | 文本字体大小 | +| ... | | | | + + +下面代码演示在实例化图时全局配置方法中配置 `label` 和 `labelCfg`。 +```javascript +const graph = new G6.Graph({ + container: 'mountNode', + width: 800, + height: 600, + defaultEdge: { + // ... 其他属性 + label: 'edge-label', + labelCfg: { + refY: -10, + refX: 60 + } + } +}) +``` + + +# 边的配置方法 +配置边的方式有三种:实例化图时全局配置,在数据中动态配置,使用 `graph.edge(edgeFn)` 函数配置。这几种配置方法可以同时使用,优先级: + +使用 graph.edge(edgeFn) 配置 > 数据中动态配置 > 实例化图时全局配置 + +即有相同的配置项时,优先级高的方式将会覆盖优先级低的。 + + +## 实例化图时全局配置 +用户在实例化 Graph 时候可以通过 `defaultEdge` 配置边,这里的配置是全局的配置,将会在所有边上生效。 +```javascript +const graph = new G6.Graph({ + container: 'mountNode', + width: 800, + height: 600, + defaultEdge: { + shape: 'line', + // 其他配置 + } +}) +``` + + +## 在数据中动态配置 +如果需要使不同边有不同的配置,可以将配置写入到边数据中。这种配置方式可以通过下面代码的形式直接写入数据,也可以通过遍历数据的方式写入。 +```javascript +const data = { + nodes: [ + ... // 节点 + ], + edges: [{ + source: 'node0', + target: 'node1' + shape: 'polyline', + ... // 其他配置 + style: { + ... // 样式属性,每种边的详细样式属性参见各边文档 + } + },{ + source: 'node1', + target: 'node2' + shape: 'cubic', + ... // 其他配置 + style: { + ... // 样式属性,每种边的详细样式属性参见各边文档 + } + }, + ... // 其他边 + ] +} +``` + + +## 使用 graph.edge(edgeFn) 配置 +该方法可以为不同边进行不同的配置。
提示: + +- 该方法必须**在 render 之前调用**,否则不起作用; +- 由于该方法优先级最高,将覆盖其他地方对边的配置,这可能将造成一些其他配置不生效的疑惑; +- 该方法在增加元素、更新元素时会被调用,如果数据量大、每条边上需要更新的内容多时,可能会有性能问题。 +```javascript +// const data = ... +// const graph = ... +graph.edge((edge) => { + return { + id: edge.id, + shape: 'polyline', + style: { + fill: 'steelblue' + } + } +}); + +graph.data(data); +graph.render(); +``` + + +# 实例演示 +```javascript +const data = { + nodes: [ + {id: '1', x: 50, y: 50, size: 20}, + {id: '2', x: 150, y: 50, size: 20}, + {id: '3', x: 200, y: 50, size: 20}, + {id: '4', x: 300, y: 130, size: 20}, + {id: '5', x: 350, y: 50, size: 20}, + {id: '6', x: 450, y: 50, size: 20}, + {id: '7', x: 500, y: 50, size: 20}, + {id: '8', x: 600, y: 50, size: 20}, + {id: '9', x: 650, y: 50, size: 20}, + {id: '10', x: 750, y: 50, size: 20}, + {id: '11', x: 800, y: 50, size: 20}, + {id: '12', x: 900, y: 150, size: 20}, + {id: '13', x: 950, y: 50, size: 20}, + {id: '14', x: 1050, y: 150, size: 20}, + {id: '15', x: 1100, y: 50, size: 20}, + ], + edges: [ + {source: '1', target: '2', shape: 'line', label: 'line'}, + {source: '3', target: '4', shape: 'polyline', label: 'polyline'}, + {source: '5', target: '6', shape: 'arc', label: 'arc'}, + {source: '7', target: '8', shape: 'quadratic', label: 'quadratic'}, + {source: '9', target: '10', shape: 'cubic', label: 'cubic'}, + {source: '11', target: '12', shape: 'cubic-vertical', label: 'cubic-vertical'}, + {source: '13', target: '14', shape: 'cubic-horizontal', label: 'cubic-horizontal'}, + {source: '15', target: '15', shape: 'loop', label: 'loop'} + ] +} + +const graph = new G6.Graph({ + container: 'mountNode', + width: 1500, + height: 300, + linkCenter: true // 使边连入节点的中心 +}); +graph.data(data); +graph.render(); +``` + +显示结果:
+ + + +## 调整边的样式 +可以在边上添加文本,修改边的样式。下面演示将配置写入数据的方式配置边。使用下面代码替换上面代码中的 9-10、11-12 两条边数据,修改这两条边的样式和其文本。 +```javascript +// 使 9-10 的 cubic 边文本下移 15 像素 +{ + source: '9', + target: '10', + shape: 'cubic', + label: 'cubic', + labelCfg: { + refY: -15 // refY 默认是顺时针方向向下,所以需要设置负值 + } +}, +// 设置 11-12 的 cubic-vertical 边的颜色、虚线、粗细,并设置文本样式、随边旋转 +{ + source: '11', + target: '12', + shape: 'cubic-vertical', + color: '#722ed1', // 边颜色 + size: 5, // 边粗细 + style: { + lineDash: [2, 2] // 虚线边 + }, + label: 'cubic-vertical', + labelCfg: { + position: 'center', // 其实默认就是 center,这里写出来便于理解 + autoRotate: true, // 使文本随边旋转 + style: { + stroke: 'white', // 给文本添加白边和白色背景 + lineWidth: 5, // 文本白边粗细 + fill: '#722ed1', // 文本颜色 + } + } +} +``` + + + + +# 相关阅读 + +- [边的状态样式](https://www.yuque.com/antv/g6/fqnn9w) —— 交互过程中的样式变化。 diff --git a/docs/manual/middle/defaultNode.md b/docs/manual/middle/defaultNode.md new file mode 100644 index 0000000000..6ca5fa49ca --- /dev/null +++ b/docs/manual/middle/defaultNode.md @@ -0,0 +1,314 @@ +--- +title: 内置的节点 +order: 2 +--- + +G6 默认提供的节点是一个基础图形加一个文本图形的实现。可选的内置节点包括 circle,rect,ellipse,diamond,triangle,star,image,modelRect,这些内置节点的默认样式分别如下图所示。
+ + + +## 内置节点类型说明 +下面表格中显示了内置的各类节点,同时对一些特殊的字段进行了说明: + +| 名称 | 描述 | 默认示例 | +| --- | --- | --- | +| circle | 圆形:
- `size` 是单个数字,表示直径
- 圆心位置对应节点的位置
- `color` 字段默认在描边上生效
- 标签文本默认在节点中央
- 更多字段见 [circle 节点的配置]()
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570852503218-902e8221-e7e7-49c5-911f-ec3cabe7e04f.png#align=left&display=inline&height=56&name=image.png&originHeight=112&originWidth=110&search=&size=13270&status=done&width=55) | +| rect | 矩形:
- `size` 是数组,例如:[100, 50]
- 矩形的中心位置是节点的位置,而不是左上角
- `color` 字段默认在描边上生效
- 标签文本默认在节点中央
- 更多字段见 [rect 节点的配置](https://www.yuque.com/antv/g6/vdqpdt#qWf35)
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570852565858-345455f4-2ddb-4c40-9c8a-67e337a9e746.png#align=left&display=inline&height=38&name=image.png&originHeight=76&originWidth=178&search=&size=5514&status=done&width=89) | +| ellipse | 椭圆:
- `size` 是数组,表示椭圆的长和宽
- 椭圆的圆心是节点的位置
- `color` 字段默认在描边上生效
- 标签文本默认在节点中央
- 更多字段见 [ellipse 节点的配置](https://www.yuque.com/antv/g6/pxt157#qWf35)
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570852588313-3dcaee5b-b2aa-45d6-99be-6f4c56d494f1.png#align=left&display=inline&height=63&name=image.png&originHeight=126&originWidth=216&search=&size=19099&status=done&width=108) | +| diamond | 菱形:
- `size` 是数组,表示菱形的长和宽
- 菱形的中心位置是节点的位置
- `color` 字段默认在描边上生效
- 标签文本默认在节点中央
- 更多字段见 [diamond 节点的配置](https://www.yuque.com/antv/g6/ilnhgt#qWf35)
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570852597814-e4e4585a-fbe0-41a4-af92-a2de2f837220.png#align=left&display=inline&height=92&name=image.png&originHeight=184&originWidth=178&search=&size=20859&status=done&width=89) | +| triangle | 三角形:
- `size` 是数组,表示三角形的长和高
- 三角形的中心位置是节点的位置
- `color` 字段默认在描边上生效
- 标签文本默认在节点下方
- 更多字段见 [triangle 节点的配置](https://www.yuque.com/antv/g6/sfcm38#qWf35)
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570852606815-2f8526a8-1349-452e-a9f7-dccb37be57f9.png#align=left&display=inline&height=78&name=image.png&originHeight=156&originWidth=126&search=&size=11213&status=done&width=63) | +| star | 星形:
- `size` 是单个数字,表示星形的大小
- 星星的中心位置是节点的位置
- `color` 字段默认在描边上生效
- 标签文本默认在节点中央
- 更多字段见 [star 节点的配置](https://www.yuque.com/antv/g6/gwn2mq#qWf35)
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570852618082-bfe59c69-08ce-4538-be49-ee72984c4830.png#align=left&display=inline&height=99&name=image.png&originHeight=198&originWidth=194&search=&size=24192&status=done&width=97) | +| image | 图片:
- `size` 是数组,表示图片的长和宽
- 图片的中心位置是节点位置
- `img` 图片的路径,也可以在 `style` 里面设置
- `color` 字段不生效
- 标签文本默认在节点下方
- 更多字段见 [image 节点的配置](https://www.yuque.com/antv/g6/ng8a0q#qWf35)
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570852649476-7c6c4aeb-8172-4a69-a6a3-b6cd24d7ea46.png#align=left&display=inline&height=67&name=image.png&originHeight=134&originWidth=112&search=&size=16354&status=done&width=56) | +| modelRect | 菱形:
- `size` 是数组,表示菱形的长和宽
- 菱形的中心位置是节点的位置
- `color` 字段默认在描边上生效
- 标签文本默认在节点中央
- 若有 `description` 字段则显示在标签文本下方显示 `description` 内容
- 更多字段见 [modelRect 节点的配置](https://www.yuque.com/antv/g6/sdfcpq#qWf35)
| ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570852629046-62c03494-82ac-4e76-b3b4-9ca242d9459a.png#align=left&display=inline&height=74&name=image.png&originHeight=148&originWidth=324&search=&size=15378&status=done&width=162)
 ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570852931313-42f193db-c9f0-4098-af7f-6c5eaf32923a.png#align=left&display=inline&height=69&name=image.png&originHeight=138&originWidth=316&search=&size=17261&status=done&width=158) | + + + +## 节点的通用属性 +所有内置的节点支持的通用属性: + +| 名称 | 是否必须 | 类型 | 备注 | +| --- | --- | --- | --- | +| id | true | String | 节点编号 | +| x | false | Number | x 坐标 | +| y | false | Number | y 坐标 | +| shape | false | String | 节点图形,默认为 `'circle'` | +| size | false | Number | Array | 节点的大小 | +| anchorPoints | false | Array | 指定边连如节点的连接点的位置(相对于该节点而言),可以为空。例如: `[0, 0]`,代表节点左上角的锚点,`[1, 1]`,代表节点右下角的锚点。 | +| style | false | Object | 节点的样式属性 | +| label | false | String | 文本文字 | +| labelCfg | false | Object | 文本配置项 | + + + +#### 样式属性 style +Object 类型。通过 `style` 配置来修改节点的填充色、边框颜色、阴影等属性。下表是 `style` 对象中常用的配置项: + +| 名称 | 是否必须 | 类型 | 备注 | +| --- | --- | --- | --- | +| fill | false | String | 节点填充色 | +| stroke | false | String | 节点的描边颜色 | +| lineWidth | false | Number | 描边宽度 | +| shadowColor | false | String | 阴影颜色 | +| shadowBlur | false | Number | 阴影范围 | +| shadowOffsetX | false | Number | 阴影 x 方向偏移量 | +| shadowOffsetX | false | Number | 阴影 y 方向偏移量 | +| ... | | | | + + +下面代码演示在实例化图时全局配置方法中配置 `style`: +```javascript +const graph = new G6.Graph({ + container: 'mountNode', + width: 800, + height: 600, + defaultNode: { + // ... 其他属性 + style: { + fill: '#steelblue', + stroke: '#eaff8f', + lineWidth: 5, + // ... 其他属性 + } + } +}) +``` + + +#### 标签文本 label 及其配置 labelCfg +`label` String 类型。标签文本的文字内容。
`labelCfg` Object 类型。配置标签文本。下面是 `labelCfg` 对象中的常用配置项: + +| 名称 | 是否必须 | 类型 | 备注 | +| --- | --- | --- | --- | +| position | false | String | 文本相对于节点的位置,目前支持的位置有:  `'center'`,`'top'`,`'left'`,`'right'`,`'bottom'`。默认为 `'center'`。 | +| offset | false | Number | Array | 文本的偏移,在 `'top'`,`'left'`,`'right'`,`'bottom'` 位置上的偏移量 | +| style | false | Object | 标签的样式属性 | + + +上表中的标签的样式属性 `style` 的常用配置项如下:  + +| 名称 | 是否必须 | 类型 | 备注 | +| --- | --- | --- | --- | +| fill | false | String | 文本颜色 | +| stroke | false | String | 文本描边颜色 | +| lineWidth | false | Number | 文本描边粗细 | +| opacity | false | Number | 文本透明度 | +| font | false | String | 文本内容的当前字体属性 | +| fontSize | false | Number | 文本字体大小 | +| ... | | | | + + +下面代码演示在实例化图时全局配置方法中配置 `label` 和 `labelCfg`。 +```javascript +const graph = new G6.Graph({ + container: 'mountNode', + width: 800, + height: 600, + defaultNode: { + // ... 其他属性 + label: 'node-label', + labelCfg: { + position: 'bottom', + offset: [10, 10, 10, 10], + style: { + fill: '#666' + } + } + } +}) +``` + + +## 节点的配置方法 +配置节点的方式有三种:实例化图时全局配置,在数据中动态配置,使用 `graph.node(nodeFn)` 函数配置。这几种配置方法可以同时使用,优先级: + +使用 graph.node(nodeFn) 配置 > 数据中动态配置 > 实例化图时全局配置 + +即有相同的配置项时,优先级高的方式将会覆盖优先级低的。 + + +### 实例化图时全局配置 +用户在实例化 Graph 时候可以通过 `defaultNode` 配置节点,这里的配置是全局的配置,将会在所有节点上生效。 +```javascript +const graph = new G6.Graph({ + container: 'mountNode', + width: 800, + height: 600, + defaultNode: { + shape: 'circle', + // 其他配置 + } +}) +``` + + +### 在数据中动态配置 +如果需要为不同节点进行不同的配置,可以将配置写入到节点数据中。这种配置方式可以通过下面代码的形式直接写入数据,也可以通过遍历数据的方式写入。 +``` +const data = { + nodes: [{ + id: 'node0', + size: 100, + shape: 'rect', + ... // 其他属性 + style: { + ... // 样式属性,每种节点的详细样式属性参见各节点文档 + } + },{ + id: 'node1', + size: [50, 100], + shape: 'ellipse', + ... // 其他属性 + style: { + ... // 样式属性,每种节点的详细样式属性参见各节点文档 + } + }, + ... // 其他节点 + ], + edges: [ + ... // 边 + ] +} +``` + + +### 使用 graph.node(nodeFn) 配置 +该方法可以为不同节点进行不同的配置。
提示: + +- 该方法必须**在 render 之前调用**,否则不起作用; +- 由于该方法优先级最高,将覆盖其他地方对节点的配置,这可能将造成一些其他配置不生效的疑惑; +- 该方法在增加元素、更新元素时会被调用,如果数据量大、每个节点上需要更新的内容多时,可能会有性能问题。 + +``` +// const data = ... +// const graph = ... +graph.node((node) => { + return { + id: node.id, + shape: 'rect', + style: { + fill: 'blue' + } + } +}); + +graph.data(data); +graph.render(); +``` + +## 实例演练 + +``` +const data = { + nodes: [{ + x: 100, + y: 100, + shape: 'circle', + label: 'circle', + },{ + x: 200, + y: 100, + shape: 'rect', + label: 'rect', + },{ + id: 'node-ellipse', + x: 330, + y: 100, + shape: 'ellipse', + label: 'ellipse' + },{ + id: 'node-diamond', + x: 460, + y: 100, + shape: 'diamond', + label: 'diamond' + },{ + id: 'node-triangle', + x: 560, + y: 100, + //size: 80, + shape: 'triangle', + label: 'triangle' + },{ + id: 'node-star', + x: 660, + y: 100, + //size: [60, 30], + shape: 'star', + label: 'star' + },{ + x: 760, + y: 100, + size: 50, + shape: 'image', + img: 'https://gw.alipayobjects.com/zos/rmsportal/XuVpGqBFxXplzvLjJBZB.svg', + label: 'image', + },{ + id: 'node-modelRect', + x: 900, + y: 100, + shape: 'modelRect', + label: 'modelRect' + }] +}; + +const graph = new G6.Graph({ + container: 'mountNode', + width: 1500, + height: 300 +}); +graph.data(data); +graph.render(); +``` + + +显示结果: +
+ + +- triangle 节点和 image 节点的标签文本默认位置为:`position:'bottom'` ,其他节点文本的默认位置都为:`position: 'center'`; + + +### 调整节点配置 + +下面演示通过将配置写入数据的方式,调整 `id` 为 `'node-ellipse'` 的椭圆节点的文本位置,颜色和样式。将下面代码替换上面代码中 `id` 为 `'node-ellipse'` 的节点数据即可生效。 + +``` +{ + id: 'node-ellipse', + x: 330, + y: 100, + shape: 'ellipse', + size: [60, 30], + label: 'ellipse', + labelCfg: { + position: 'bottom', + offset: 5 + }, + style: { + fill: '#fa8c16', + stroke: '#000', + lineWidth: 2 + } +} +``` + + + +再为 `id` 为 `'node-modelRect'` 的 modelRect 节点添加描述文字,使用下面代码替换 `id` 为 `'node-modelRect'` 的节点数据即可得到带有内容为 '描述文本xxxxxxxxxxx' 的 modelRect 节点。 +``` +{ + id: 'node-modelRect', + x: 900, + y: 100, + description: '描述文本xxxxxxxxxxx', + shape: 'modelRect', + label: 'modelRect' +} +``` + + + + +## 相关阅读 + +- [节点的状态样式](https://www.yuque.com/antv/g6/fqnn9w) —— 交互过程中的样式变化。 diff --git a/docs/manual/middle/g6InReact.md b/docs/manual/middle/g6InReact.md new file mode 100644 index 0000000000..713edcdb45 --- /dev/null +++ b/docs/manual/middle/g6InReact.md @@ -0,0 +1,115 @@ +--- +title: React 中使用 G6 +order: 9 +--- + + +### 概述 +G6是一个纯JS库,不与任何框架耦合,也就是可以在任何前端框架中使用,如 React、Vue、Angular 等。由于我们内部绝大多数都是基于 React 技术栈的,所以我们也仅提供一个 G6 在 React 中使用的 Demo。 + +在 React 中使用 G6,和在 HTML 中使用基本相同,唯一比较关键的区分就是在实例化 Graph 时,要**保证 DOM 容器渲染完成,并能获取到 DOM 元素**。 + +在 Demo 中,我们以一个简单的流程图为例,实现如下的效果。![demo.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570264721327-6afda2c1-2edf-4bb4-84dc-14f91f820d0c.gif#align=left&display=inline&height=545&name=demo.gif&originHeight=545&originWidth=1207&search=&size=166134&status=done&width=1207) + + +### 功能及实现 +Demo 包括以下功能点: + +- 自定义节点; +- 自定义边; +- 节点的 tooltip; +- 边的 tooltip; +- 节点上面弹出右键菜单; +- tooltip 及 ContextMenu 如何渲染自定义的 React 组件。 + +在 React 中,通过 `**ReactDOM.findDOMNode(ref.current)**`** **获取到真实的 DOM 元素。 + +```javascript +import React, { useEffect, useState } from 'react'; +import ReactDOM from 'react-dom'; +import { data } from './data'; +import G6 from '@antv/g6'; + +export default function() { + const ref = React.useRef(null) + let graph = null + + useEffect(() => { + if(!graph) { + graph = new G6.Graph({ + container: ReactDOM.findDOMNode(ref.current), + width: 1200, + height: 800, + modes: { + default: ['drag-canvas'] + }, + layout: { + type: 'dagre', + direction: 'LR' + }, + defaultNode: { + shape: 'node', + labelCfg: { + style: { + fill: '#000000A6', + fontSize: 10 + } + }, + style: { + stroke: '#72CC4A', + width: 150 + } + }, + defaultEdge: { + shape: 'polyline' + } + }) + } + graph.data(data) + graph.render() + }, []) + + return ( +
+ ); +} + +``` + + +### G6中渲染React组件 +节点和边的 tooltip、节点上的右键菜单,G6 中内置的很难满足样式上的需求,这个时候我们就可以通过渲染自定义的 React 组件来实现。Tooltip 和 ContextMenu 都是普通的 React 组件,样式完全由用户控制。交互过程中,在G6 中需要做的事情就是确定何时渲染组件,以及渲染到何处。在 G6 中获取到是否渲染组件的标识值和渲染位置后,这些值就可以使用 React state 进行管理,后续的所有工作就全部由 React 负责了。 + +```javascript +// 边tooltip坐标 +const [showNodeTooltip, setShowNodeTooltip] = useState(false) +const [nodeTooltipX, setNodeToolTipX] = useState(0) +const [nodeTooltipY, setNodeToolTipY] = useState(0) + +// 监听node上面mouse事件 +graph.on('node:mouseenter', evt => { + const { item } = evt + const model = item.getModel() + const { x, y } = model + const point = graph.getCanvasByPoint(x, y) + + setNodeToolTipX(point.x - 75) + setNodeToolTipY(point.y + 15) + setShowNodeTooltip(true) +}) + +// 节点上面触发mouseleave事件后隐藏tooltip和ContextMenu +graph.on('node:mouseleave', () => { + setShowNodeTooltip(false) +}) + +return ( +
+ { showNodeTooltip && } +
+); +``` + +完整的 Demo 源码请👉戳[这里](https://github.com/baizn/g6-in-react)。 + +关于 G6 如何在 Vue 及 Angular 中使用,还望社区中有相关实践的同学能提供一些,供其他同学学习和参考,非常感谢! diff --git a/docs/manual/middle/graph.md b/docs/manual/middle/graph.md index e3adb2369c..44bbc4eb3e 100644 --- a/docs/manual/middle/graph.md +++ b/docs/manual/middle/graph.md @@ -15,7 +15,7 @@ order: 1 ## 前提代码 本文的讲解将会基于下面这份内嵌 JavaScript 的 HTML 代码。该代码通过定义数据、实例化图、读取数据、渲染图等操作中完成了下图中简单的图:
-[image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571034737611-563c61e5-d3c0-407b-89fc-ca8c6fb97f66.png#align=left&display=inline&height=29&name=image.png&originHeight=148&originWidth=736&search=&size=20441&status=done&width=146) + ```html diff --git a/docs/manual/middle/keyConcept.md b/docs/manual/middle/keyConcept.md new file mode 100644 index 0000000000..cf3dfef159 --- /dev/null +++ b/docs/manual/middle/keyConcept.md @@ -0,0 +1,117 @@ +--- +title: G6 中的关键概念 +order: 0 +--- + + +## 图形 Shape +Shape 指 G6 中的图形、形状,它可以是圆形、矩形、路径等。它一般与 G6 中的节点、边相关。G6 中的每一种节点或边由一个或多个 Shape 组成。 + +例如下图(左)的节点包含了一个圆形图形;下图(中)的节点含有有一个圆形和一个文本图形;下图(右)的节点中含有 5 个圆形(蓝绿色的圆和上下左右四个锚点)、一个文本图形。但每种节点和边都会有自己的唯一关键图形 keyShape,下图中三个节点的 keyShape 都是蓝绿色的圆,keyShape 主要用于交互检测、样式随[状态](https://www.yuque.com/antv/g6/fqnn9w)自动更新等,见 [keyShape](#UNCAz)。
![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570860282365-a580467a-9843-4aa5-a016-d73dff38fc0a.png#align=left&display=inline&height=68&name=image.png&originHeight=136&originWidth=138&search=&size=14236&status=done&width=69)      ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570860291602-5729dfa6-4c25-4547-82f8-2d388422df67.png#align=left&display=inline&height=85&name=image.png&originHeight=170&originWidth=150&search=&size=16796&status=done&width=75)      ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1570859851766-0358416c-65d1-4637-93d1-e5cf12017bc8.png#align=left&display=inline&height=94&name=image.png&originHeight=188&originWidth=196&search=&size=24941&status=done&width=98) +> (左)只含有一个圆形图形的节点,keyShape 是该圆形。(中)含有圆形和文本图形的节点,keyShape 是圆形。(右)含有主要圆形、文本、上下左右四个小圆形的节点,keyShape 是圆形。 + + +G6 使用不同的 shape 及组合,设计了多种内置的节点和边。G6 内置节点的有 'circle', 'rect','ellipse',...(详见 [内置节点](https://www.yuque.com/antv/g6/internal-node));内置边的有 'line','polyline','cubic',...(详见 [内置边](https://www.yuque.com/antv/g6/internal-edge))。 + +除了使用内置的节点和边外,G6 还允许用户通过自己搭配和组合 Shape 进行节点和边的自定义,详见 [自定义节点](https://www.yuque.com/antv/g6/self-node) 和 [自定义边](https://www.yuque.com/antv/g6/self-edge)。 + + +## KeyShape +如上所述,每一种节点和边都有一个唯一的关键图形 keyShape。keyShape 是在节点的 draw 方法中返回的图形对象,用于**确定节点的包围盒(Bounding Box) —— bbox(x, y, width, height)** ,从而计算相关边的连入点(与相关边的交点)。若 keyShape 不同,节点与边的交点计算结果不同。  + + +### 示例  +本例中的一个节点由一个 rect 图形和一个带灰色描边、填充透明的 circle 图形构成。 + +- 当节点的 keyShape 为 circle 时: + +![2019-06-13.07.png](https://cdn.nlark.com/yuque/0/2019/png/244306/1561033286841-e52f2489-4c31-4235-9d3c-0dfcc95ff4c6.png#align=left&display=inline&height=145&name=%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-06-13%20%E4%B8%8A%E5%8D%8811.31.07.png&originHeight=166&originWidth=392&search=&size=8734&status=done&width=342) + +- 当节点的 keyShape 为 rect 时: + +![2019-06-13.png](https://cdn.nlark.com/yuque/0/2019/png/244306/1561033286856-823a0f11-a768-456f-b510-d823799d1bfe.png#align=left&display=inline&height=150&name=%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7%202019-06-13%20%E4%B8%8A%E5%8D%8811.31.56.png&originHeight=180&originWidth=432&search=&size=8968&status=done&width=359) + + + +## Shape 的生命周期 +> 当用户需要[自定义节点](https://www.yuque.com/antv/g6/self-node)和[自定义边](https://www.yuque.com/antv/g6/self-edge)时,需要了解 Shape 的生命周期。使用内置节点和边则可以跳过这一部分内容。 + +从整体来看,Shape 的生命周期分为: + +- 初始化渲染; +- 更新; +- 操作; +- 销毁。 + +Shape 作为 Graph 上的核心元素,这几个阶段都需要考虑,但是销毁可以交给 Graph 来处理,所以在定义 Shape 时不需要考虑,仅需要考虑三个阶段即可: + +- 绘制:从无到有的绘制 Shape 及文本; +- 更新:数据发生改变导致 Shape 及文本发生变化; +- 操作:给 Shape 添加状态,如:selected,active 等。 + +所以我们在设计自定义节点和边时,定义了三个方法,若需要自定义节点和边,需要有选择性地复写它们: + +- `draw(cfg, group)`: 绘制,提供了绘制的配置项(数据定义时透传过来)和图形容器; +- `update(cfg, n)`: 更新,更新时的配置项(更新的字段和原始字段的合并)和节点对象; +- `setState(name, value, item)`: 设置节点状态。 + +关于自定义Shape更多的方法请[参考 Shape API 文档](https://www.yuque.com/antv/g6/shape-api)。 + +## anchorPoint + +节点的连接点 anchorPoint 指的是边连入节点的相对位置,即节点与其相关边的交点位置。anchorPoints 是一个二维数组,每一项表示一个连接点的位置,在一个[图形 shape](https://www.yuque.com/antv/g6/shape-crycle) 中,连接点的位置如下图所示,x 和 y 方向上范围都是 [0, 1]:
+ + +节点中有了 anchorPoints 之后,相关边可以分别选择连入起始点、结束点的哪一个 anchorPoint。当需要在节点之间连多条线时,这种机制能够使边的连入更美观。 + +边可以通过指定 `sourceAnchor` 和 `targetAnchor` 分别选择起始点、结束点的 anchorPoint。`sourceAnchor` 和 `targetAnchor` 取的值是相对应节点上 anchorPoints 数组的索引值。 + +下面数据演示了如何在节点上配置连接点、在边上指定连接点: +```javascript +const data = { + nodes: [ + { + id: 'node1', + label: 'node1', + x: 100, + y: 200, + // 该节点可选的连接点集合,该点有两个可选的连接点 + anchorPoints: [[0, 1], [0.5, 1]], + shape: 'rect' + }, + { + id: 'node2', + label: 'node2', + x: 300, + y: 400, + // 该节点可选的连接点集合,该点有两个可选的连接点 + anchorPoints: [[0.5, 0], [1, 0.5]], + shape: 'rect' + } + ], + edges: [ + { + source: 'node1', + target: 'node2', + // 该边连入 source 点的第 0 个 anchorPoint, + sourceAnchor: 0, + // 该边连入 target 点的第 0 个 anchorPoint, + targetAnchor: 0, + style: { + endArrow: true + } + }, + { + source: 'node2', + target: 'node1', + // 该边连入 source 点的第 1 个 anchorPoint, + sourceAnchor: 1, + // 该边连入 source 点的第 1 个 anchorPoint, + targetAnchor: 1, + style: { + endArrow: true + } + } + ] + } +``` diff --git a/docs/manual/middle/layout.md b/docs/manual/middle/layout.md new file mode 100644 index 0000000000..935880987d --- /dev/null +++ b/docs/manual/middle/layout.md @@ -0,0 +1,478 @@ +--- +title: 使用布局 Layout +order: 7 +--- + + +## 简介 +图布局是指图中节点的排布方式,根据图的数据结构不同,布局可以分为两类:一般图布局、树图布局。G6 为这两类图都内置了一些常用的图布局算法。使用内置的图布局可以完成[布局的参数、方法、数据的切换](#FCFKL)等。 + +除了内置布局方法外,一般图布局还支持 [自定义布局](https://www.yuque.com/antv/g6/zpg5ty) 机制。 + +事实上,G6 的布局是自由的,内置布局算法仅仅是操作了数据中节点的 `x` 和 `y` 值。因此,除了使用内置布局以及自定义的一般图布局外,用户还可以使用外部图布局算法,计算节点位置后赋值到数据中节点的 `x` 和 `y` 字段上,G6 便可以根据该位置信息进行绘制。 + +本文将逐一介绍内置的布局算法,及其使用方式。 + + +## G6 布局方法总览 + +### 一般图 Graph + +- [Random Layout](#AIkrd):随机布局; +- [Force Layout](#B6ZYA):经典力导向布局; +- [Fruchterman Layout](#TirhH):Fruchterman 布局,一种力导布局; +- [Circular Layout](#0lVZj):环形布局; +- [Radial Layout](#lALX0):辐射状布局; +- [MDS Layout](#RBhhk):高维数据降维算法布局; +- [Dagre Layout](#RUeWF):层次布局; +- [Concentric Layout](#4JMfP):同心圆布局; +- [Grid Layout](#XG0RD):网格布局。 + + +### 树图 TreeGraph + +- [CompactBox Layout](#AyYPj):紧凑树布局; +- [Dendrogram Layout](#sH1z0):树状布局(叶子节点布局对齐到同一层); +- [Intended Layout](#04ZZ5):缩进布局; +- [Mindmap Layout](#AOAs2):脑图布局。 + + +## 一般图 Graph + +### 配置一般图布局 +用户可以通过在实例化图时使用图的配置项 `layout` 指定布局方法。下面代码在实例化图时设置了布局方法为 `type: 'force'`,即经典力导向图布局。并设置了参数 `preventOverlap: true` 和 `nodeSize: 30`,表示希望节点不重叠。节点大小 `nodeSize` 用于算法中判断节点是否重叠,更多配置项见 [Graph 各布局的配置项](https://www.yuque.com/antv/g6/qopkkg#a73ba)。 +```javascript +const graph = new G6.Graph({ + ... // 其他配置项 + layout: { // Object,可选,布局的方法及其配置项,默认为 random 布局。 + type: 'force', + preventOverlap: true, + nodeSize: 30, + ... // 其他配置 + } +}); +``` + +当实例化图时没有配置布局时: + +- 若数据中节点有位置信息(`x` 和 `y`),则按照数据的位置信息进行绘制; +- 若数据中节点没有位置信息,则默认使用 Random Layout 进行布局。 + + +### 一般图布局方法 +图布局通用 API:[Layout API](https://www.yuque.com/antv/g6/agbmu2)。 + +#### Random + + +
**描述**:随机布局。 +
**API**:[Random API](https://www.yuque.com/antv/g6/nrxlhg) +
**参数**: + +| 参数名 | 类型 | 示例 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| center | Array | [ 0, 0 ] | 图的中心 | 随机布局的中心 | +| width | Number | 300 | 图的宽 | | +| height | Number | 300 | 图的高 | | + + + +#### Force + + + +
**描述**:经典力导向布局。 +
**API**:[Force API](https://www.yuque.com/antv/g6/rllgdl) +
**参数**:与 d3 的力导布局参数相对应。 + +| 参数名 | 类型 | 示例 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| center | Array | [ 0, 0 ] | 图的中心 | 随机布局的中心 | +| linkDistance | Number | Function | 示例1: 50 
示例2:
d => {
  // d 是一条边
  if (d.id === 'edge1') {
    return 100;
  }
  return 50;
} | 50 | 边长。可以使用回调函数的形式对不同对边定义不同边长(如示例2) | +| nodeStrength | Number | Function | 示例1: -30 
示例2:
d => {
  // d 是一个节点
  if (d.id === 'node1') {
    return -100;
  }
  return -30;
} | null | 节点作用力,正数代表节点之间的引力作用,负数代表节点之间的斥力作用。可以使用回调函数的形式对不同对节点定义不同节点作用力(如示例2) | +| edgeStrength | Number | 示例1: 1 
示例2:
d => {
  // d 是一个节点
  if (d.id === 'node1') {
    return 10;
  }
  return 1;
} | null | 边的作用力,默认根据节点的出入度自适应。可以使用回调函数的形式对不同对节点定义不同边作用力(如示例2) | +| preventOverlap | Boolean | false | false | 是否防止重叠,必须配合属性 `nodeSize` ,只有设置了与当前图节点大小相同的 `nodeSize` 值,才能够进行节点重叠的碰撞检测。若未设置 `nodeSize` ,则根据节点数据中的 `size` 进行碰撞检测。若二者都未设置,则默认以 10 为节点大小进行碰撞检测 | +| nodeSize | Array | Number | 20 | undefined | 节点大小(直径)。用于碰撞检测。
若不指定,则根据传入的数据节点中的 `size` 字段计算。若即不指定,节点中也没有 `size`,则默认大小为 10 | +| nodeSpacing

3.1.6 后支持 | Number | Function | 示例 1 : 10
示例 2 : 
d => {
  // d 是一个节点
  if (d.id === 'node1') {
    return 100;
  }
  return 10;
} | 0 | ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1572589493571-733b149d-2887-4b75-bd22-a2808233d0d5.png#align=left&display=inline&height=115&name=image.png&originHeight=200&originWidth=378&search=&size=46987&status=done&width=217)
`preventOverlap` 为 `true` 时生效,防止重叠时节点边缘间距的最小值。可以是回调函数,为不同节点设置不同的最小间距,如示例 2 所示
| +| alphaDecay | Number | 0.03 | 0.028 | 迭代阈值的衰减率。[0, 1],0.028 对应迭代书为 300 | +| alphaMin | Number | 0.03 | 0.001 | 停止迭代的阈值 | +| alpha | Number | 0.1 | 0.3 | 当前阈值 | +| collideStrength | Number | 0.8 | 1 | 防止重叠的力强度,[0, 1]。 | +| forceSimulation | Object | | null | 自定义 force 方法,若不指定,则使用 d3 的方法。 | +| onTick | Function | | {} | 每一次迭代的回调函数 | +| onLayoutEnd | Function | | {} | 布局完成后的回调函数 | + + + +#### Fruchterman + + + +
**描述**:Fruchterman 布局,一种力导布局。 +
**API**:[Fruchterman API](https://www.yuque.com/antv/g6/vzqn07) +
**参数**: + +| 参数名 | 类型 | 示例 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| center | Array | [ 0, 0 ] | 图的中心 | 随机布局的中心 | +| maxIteration | Number | 1000 | 1000 | 最大迭代次数 | +| gravity | Number | 10 | 10 | 重力大小,影响布局的紧凑程度 | +| speed | Number | 1 | 1 | 每次迭代节点移动的速度。速度太快可能会导致强烈震荡 | +| clustering | Boolean | false | false | 是否按照聚类布局 | +| clusterGravity | Number | 30 | 10 | 聚类内部的重力大小,影响聚类的紧凑程度 | + + + +#### Circular + + + + + +
**描述**:环形布局。 +
**API**:[Circular API](https://www.yuque.com/antv/g6/ml1qe3) +
**参数**: + +| 参数名 | 类型 | 示例/可选值 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| center | Array | [ 0, 0 ] | 图的中心 | 随机布局的中心 | +| radius | Number | 50 | null | 圆的半径。若设置了 radius,则 startRadius 与 endRadius 不生效 | +| startRadius | Number | 10 | null | 螺旋状布局的起始半径 | +| endRadius | Number | 100 | null | 螺旋状布局的结束半径 | +| clockwise | Boolean | true | true | 是否顺时针排列 | +| divisions | Number | 3 | 1 | 节点在环上的分段数(几个段将均匀分布),在 endRadius - startRadius != 0 时生效 | +| ordering | String | null | 'topology' | 'degree' | null | 节点在环上排序的依据。默认 null 代表直接使用数据中的顺序。'topology' 按照拓扑排序。'degree' 按照度数大小排序 | +| angleRatio | Number | 1 | 1 | 从第一个节点到最后节点之间相隔多少个 2*PI | + + + +#### Radial + + + +
**描述**:辐射状布局。 +
**API**:[Radial API](https://www.yuque.com/antv/g6/ngp0vg#7ZOs7) +
**参数**: + +| 参数名 | 类型 | 示例 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| center | Array | [ 0, 0 ] | 图的中心 | 随机布局的中心 | +| linkDistance | Number | 50 | 50 | 边长 | +| maxIteration | Number | 1000 | 1000 | 停止迭代到最大迭代数 | +| focusNode | String | Object | 'node1' | null | 中心点,默认为数据中第一个节点。可以传入节点 id 或节点本身。 | +| unitRadius | Number | 10 | 100 | 每一圈距离上一圈的距离。默认填充整个画布,即根据图的大小决定 | +| preventOverlap | Boolean | false | false | 是否防止重叠,必须配合属性 `nodeSize` ,只有设置了与当前图节点大小相同的 `nodeSize` 值,才能够进行节点重叠的碰撞检测。
3.1.6 后支持:
若未设置 `nodeSize`,则将会根据数据中节点的 size 字段数值进行碰撞检测计算。若二者皆未设置,则以节点大小为 10 进行计算。 | +| maxPreventOverlapIteration | Number | 500 | 200 | 防止重叠步骤的最大迭代次数 | +| nodeSize | Number | 10 | 10 | 节点大小(直径)。用于防止节点重叠时的碰撞检测。
3.1.6 后支持:
若未设置则使用数据中节点的 `size` 字段数值进行碰撞检测计算。若二者皆未设置,则以节点大小为 10 进行计算。 | +| nodeSpacing
3.1.6 后支持 | Number | Function | 示例 1 : 10
示例 2 : 
d => {
  // d 是一个节点
  if (d.id === 'node1') {
    return 100;
  }
  return 10;
} | 0 | ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1572589493571-733b149d-2887-4b75-bd22-a2808233d0d5.png#align=left&display=inline&height=115&name=image.png&originHeight=200&originWidth=378&search=&size=46987&status=done&width=217)
`preventOverlap` 为 `true` 时生效,防止重叠时节点边缘间距的最小值。可以是回调函数,为不同节点设置不同的最小间距,如示例 2 所示
| +| strictRadial | Boolean | true | false | 是否必须是严格的 radial 布局,即每一层的节点严格布局在一个环上。`preventOverlap` 为 `true` 时生效。详见 [Radial-strictRadial API](https://www.yuque.com/antv/g6/ngp0vg#7ZOs7)
- 当 `preventOverlap` 为 `true`,且 `strictRadial` 为 `false` 时,有重叠的节点严格沿着所在的环展开,但在一个环上若节点过多,可能无法完全避免节点重叠。
- 当 `preventOverlap` 为 `true`,且 `strictRadial` 为 `true` 时,允许同环上重叠的节点不严格沿着该环布局,可以在该环的前后偏移以避免重叠。
| + + + +#### MDS +![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571883196380-9194f4b6-fb45-49c1-9a15-17e1c694a82f.png#align=left&display=inline&height=138&name=image.png&originHeight=549&originWidth=862&search=&size=134489&status=done&width=216)
**描述**:高维数据降维算法布局。
**API**:[MDS API](https://www.yuque.com/antv/g6/kbvo7q)
**参数**: + +| 参数名 | 类型 | 示例 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| center | Array | [ 0, 0 ] | 图的中心 | 随机布局的中心 | +| linkDistance | Number | 50 | 50 | 边长 | + + + +#### Dagre +![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571883264071-64862e9a-a850-499b-8063-253c3d380b76.png#align=left&display=inline&height=159&name=image.png&originHeight=567&originWidth=392&search=&size=45070&status=done&width=110)
**描述**:层次布局。
**API**:[Dagre API](https://www.yuque.com/antv/g6/fkhp3c)
**参数**: + +| 参数名 | 类型 | 示例 / 可选值 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| rankdir | String | 'TB' | 'BT' | 'LR' | 'RL' | 'TB' | layout 的方向。T:top;B:bottom;L:left;R:right | +| align | String | 'UL' | 'UR' | 'DL' | 'DR' | 'UL' | 节点对齐方式。U:upper;D:down;L:left;R:right | +| nodesep | Number | 40 | 50 | 节点水平间距(px)。优先级高于 `nodesepFunc` | +| ranksep | Number | 40 | 50 | 层间距(px)。优先级高于 `ranksep``Func` | +| nodesepFunc

3.1.6 后支持 | Function | d => {
  // d 是一个节点
  if (d.id === 'node1') {
    return 100;
  }
  return 10;
} | undefined | 节点水平间距(px)的回调函数,通过该参数可以对不同节点设置不同的节点间距。优先级低于 `nodesep`,即若设置了 `nodesep`,则 `nodesepFunc` 不生效 | +| ranksepFunc

3.1.6 后支持 | Function | d => {
  // d 是一个节点
  if (d.id === 'node1') {
    return 100;
  }
  return 10;
} | undefined | 层间距(px)的回调函数,通过该参数可以对不同节点设置不同的层间距。优先级低于 `ranksep`,即若设置了 `ranksep`,则 `ranksepFunc` 不生效 | +| controlPoints | Boolean | true | true | 是否保留布局连线的控制点 | + + + +#### Concentric +![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571883276351-a0d32bcb-7d1d-4a29-b2b6-f78345c8c752.png#align=left&display=inline&height=186&name=image.png&originHeight=694&originWidth=728&search=&size=268711&status=done&width=195)
注:该算法参考 [cytoscape.js](https://github.com/cytoscape/cytoscape.js),遵守 MIT 开源协议。
**描述**:同心圆布局。
**API**:[Concentric API](https://www.yuque.com/antv/g6/lx038n)
**参数**: + +| 参数名 | 类型 | 示例 / 可选值 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| center | Array | [ 0, 0 ] | 图的中心 | 随机布局的中心 | +| nodeSize | Number | 30 | 30 | 节点大小(直径)。用于防止节点重叠时的碰撞检测 | +| minNodeSpacing | Number | 10 | 10 | 环与环之间最小间距,用于调整半径 | +| preventOverlap | Boolean | false | false | 是否防止重叠,必须配合属性 `nodeSize` ,只有设置了与当前图节点大小相同的 `nodeSize` 值,才能够进行节点重叠的碰撞检测。若未设置 `nodeSize` ,则将根据节点数据中的 `size` 进行碰撞检测。若二者都未设置,则默认以 30 为节点大小进行碰撞检测 | +| sweep | Number | Math.PI | undefined | 第一个节点与最后一个节点之间的弧度差 | +| equidistant | Boolean | false | false | 环与环之间的距离是否相等 | +| startAngle | Number | 3.14 | 3 / 2 * Math.PI | 开始放置节点的弧度 | +| clockwise | Boolean | false | false | 是否按照顺时针顺序 | +| maxLevelDiff | Number | 0.5 | undefined | 每一层同心值的求和。若为 undefined,则将会被设置为 maxValue / 4 ,其中 maxValue 为最大的排序依据的属性值。例如,若 sortBy='degree',则 maxValue 为所有节点中度数最大的节点的度数 | +| sortBy | String | 'degree' | 'property1' | 'weight' | ... | undefined | 指定的节点排序的依据(节点属性名)。该属性值高的放在中心。如果是 `sortBy` 为 `undefined` 则会计算节点度数,度数最高的放在中心。
| + + + +#### Grid +![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571883294360-430a03bf-82cf-4ebf-989e-ae0be742bf54.png#align=left&display=inline&height=151&name=image.png&originHeight=696&originWidth=1396&search=&size=529788&status=done&width=302)
注:该算法参考 [cytoscape.js](https://github.com/cytoscape/cytoscape.js),遵守 MIT 开源协议。
**描述**:网格布局。
**API**:[Grid API](https://www.yuque.com/antv/g6/wn4kg9)
**参数**: + +| 参数名 | 类型 | 示例 / 可选值 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| begin | Array | [ 0, 0 ] | [ 0, 0 ] | 网格开始位置(左上角) | +| preventOverlap | Boolean | false | false | 是否防止重叠,必须配合属性 `nodeSize` ,只有设置了与当前图节点大小相同的 `nodeSize` 值,才能够进行节点重叠的碰撞检测。若未设置 `nodeSize` ,则将根据节点数据中的 `size` 进行碰撞检测。若二者都未设置,则默认以 30 为节点大小进行碰撞检测 | +| preventOverlapPadding | Number | 10 | 10 | 避免重叠时节点的间距 padding。preventOverlap 为 true 时生效 | +| nodeSize | Number | 30 | 30 | 节点大小(直径)。用于防止节点重叠时的碰撞检测 | +| condense | Boolean | false | false | 为 false 时表示利用所有可用画布空间,为 true 时表示利用最小的画布空间 | +| rows | Number | 5 | undefined | 网格的行数,为 undefined 时算法根据节点数量、布局空间、cals(若指定)自动计算 | +| cals | Number | 5 | undefined | 网格的列数,为 undefined 时算法根据节点数量、布局空间、rows(若指定)自动计算 | +| sortBy | String | 'degree' | 'property1' | 'weight' | ... | 'degree' | 指定排序的依据(节点属性名),数值越高则该节点被放置得越中心。若为 undefined,则会计算节点的度数,度数越高,节点将被放置得越中心 | + + + +## 树图 TreeGraph +由于树图特殊性,G6扩展出了 TreeGraph ,详细文档请见:[TreeGraph](https://www.yuque.com/antv/g6/treegraph) API。树布局是一种能很好展示有一定层次结构数据的布局方式。推荐使用 G6.TreeGraph 实现。 + + +### 配置树图布局 +与一般图 Graph 配置方法相似,通过实例化图时配置 `layout` 属性设置树的布局,还可以通过 `modes` 属性为树配置 [展开/收缩行为](https://www.yuque.com/antv/g6/treegraph#157b6823)。以下代码声明了一个实例,定义了布局为从左到右结构的基础树图,并且定义了展开收缩行为。 +```javascript +const graph = new G6.TreeGraph({ + container: 'mountNode', + modes: { + default: [{ + // 定义展开/收缩行为 + type: 'collapse-expand' + }, 'drag-canvas'] + }, + // 定义布局 + layout: { + type: 'dendrogram', // 布局类型 + direction: 'LR', // 自左至右布局,可选的有 H / V / LR / RL / TB / BT + nodeSep: 50, // 节点之间间距 + rankSep: 100 // 每个层级之间的间距 + } + }); +``` + +### + +### 树图布局方法 + +#### compactBox +**描述**:紧凑树布局。从根节点开始,同一深度的节点在同一层,并且布局时会将节点大小考虑进去。
![compact-box.png](https://cdn.nlark.com/yuque/0/2019/png/174835/1551166323476-178c0e50-0999-4b07-ab72-a61f779cce28.png#align=left&display=inline&height=166&name=compact-box.png&originHeight=687&originWidth=1916&search=&size=53500&status=done&width=464)
**API**:[CompactBox API](https://www.yuque.com/antv/g6/rufc7b)
**参数**: + +| 参数名 | 类型 | 示例 / 可选值 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| direction | String | 'TB' | 'BT' | 'LR' | 'RL' | 'H' | 'V' | 'LR' | layout 的方向。
- TB —— 根节点在上,往下布局
- BT —— 根节点在下,往上布局
+![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571833657395-7b291d7b-5408-41fa-bfb6-533ef39250ad.png#align=left&display=inline&height=59&name=image.png&originHeight=744&originWidth=1786&search=&size=397159&status=done&width=141)      ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571833676794-31f862f3-8cb5-412e-81d4-2ac246e37c0d.png#align=left&display=inline&height=60&name=image.png&originHeight=762&originWidth=1790&search=&size=390312&status=done&width=140)> (左)TB。(右)BT。 + +- LR —— 根节点在左,往右布局
- RL —— 根节点在右,往左布局
+![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571833574730-5d76d7a2-0e82-4ef7-a7d9-a45efd5b6b30.png#align=left&display=inline&height=119&name=image.png&originHeight=906&originWidth=518&search=&size=164555&status=done&width=68)             ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571833593889-e98c6f6d-0c38-4408-a4c0-ba83d0bbba74.png#align=left&display=inline&height=115&name=image.png&originHeight=932&originWidth=454&search=&size=154391&status=done&width=56)> (左)LR。(右)RL。 + +- H —— 根节点在中间,水平对称布局
- V —— 根节点在中间,垂直对称布局
+![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571833726277-822e5104-2189-4fe4-bcdc-7b43d183d541.png#align=left&display=inline&height=110&name=image.png&originHeight=906&originWidth=824&search=&size=226469&status=done&width=100)          ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571833702068-8f409559-1765-4154-bd4d-bb782de8cd23.png#align=left&display=inline&height=92&name=image.png&originHeight=924&originWidth=1028&search=&size=314177&status=done&width=102)
> (左)H。(右)V。 | +| getId | Function | (d) => {
  // d 是一个节点
  return d.id;
} | undefined | 节点 id 的回调函数 | +| getHeight | Function | (d) => {
  // d 是一个节点
  return 10;
} | undefined | 节点高度的回调函数 | +| getWidth | Function | (d) => {
  // d 是一个节点
  return 20;
} | undefined | 节点宽度的回调函数 | +| getVGap | Function | (d) => {
  // d 是一个节点
  return 100;
} | undefined | 节点纵向间距的回调函数 | +| getHGap | Function | (d) => {
// d 是一个节点
  return 50;
} | undefined | 节点横向间距的回调函数 | +| radial | Boolean | true | false | 是否按照辐射状布局。若 `radial` 为 `true`,建议 `direction` 设置为 `'LR'` 或 `'RL'`:![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571833817425-f944eadd-fd68-4107-8425-81c1c9bd1ce4.png#align=left&display=inline&height=97&name=image.png&originHeight=886&originWidth=990&search=&size=213310&status=done&width=108) | + + + +#### dendrogram +**描述**:生态树布局。不管数据的深度多少,总是叶节点对齐。不考虑节点大小,布局时将节点视为1个像素点。
![dendrogram-lr.png](https://cdn.nlark.com/yuque/0/2019/png/174835/1551166332942-ecdc3c6f-bcc3-48f4-aa64-c9b1a3a2ab67.png#align=left&display=inline&height=145&name=dendrogram-lr.png&originHeight=652&originWidth=888&search=&size=75483&status=done&width=198)
**API**:[Dendrogram API](https://www.yuque.com/antv/g6/co00r6)
**参数**: + +| 参数名 | 类型 | 示例 / 可选值 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| direction | String | 'TB' | 'BT' | 'LR' | 'RL' | 'H' | 'V' | 'LR' | layout 的方向。
- TB —— 根节点在上,往下布局
- BT —— 根节点在下,往上布局
+![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571832831947-89713eef-7898-446b-9edc-604ed63b77d4.png#align=left&display=inline&height=48&name=image.png&originHeight=760&originWidth=1784&search=&size=518414&status=done&width=112)      ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571832849059-ada0d199-ca15-4ce0-83e0-de00f9482c0b.png#align=left&display=inline&height=50&name=image.png&originHeight=786&originWidth=1814&search=&size=517688&status=done&width=115)
> (左)TB。(右)BT。 + +- LR —— 根节点在左,往右布局
- RL —— 根节点在右,往左布局
+![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571832767625-ad86a4b6-dabb-4f53-9800-31bb3fef88c6.png#align=left&display=inline&height=114&name=image.png&originHeight=896&originWidth=408&search=&size=214689&status=done&width=52)             ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571832804357-6b4c6e65-22fe-45b1-ab9f-bf954cdb0b13.png#align=left&display=inline&height=116&name=image.png&originHeight=912&originWidth=410&search=&size=213061&status=done&width=52)> (左)LR。(右)RL。 + +- H —— 根节点在中间,水平对称布局
- V —— 根节点在中间,垂直对称布局
+![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571832893099-55fa98c8-30f2-49c6-b582-76dd69de7b4a.png#align=left&display=inline&height=104&name=image.png&originHeight=892&originWidth=712&search=&size=279079&status=done&width=83)          ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571832910720-f3d479c3-b822-4123-b207-a81e22fad324.png#align=left&display=inline&height=91&name=image.png&originHeight=922&originWidth=1172&search=&size=366086&status=done&width=116)
> (左)H。(右)V。 | +| nodeSep | Number | 50 | 0 | 节点间距 | +| rankSep | Number | 100 | 0 | 层与层之间的间距 | +| radial | Boolean | true | false | 是否按照辐射状布局。若 `radial` 为 `true`,建议 `direction` 设置为 `'LR'` 或 `'RL'`:
![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571833294684-7874d71d-fb44-4340-95d0-c03b56c67a18.png#align=left&display=inline&height=98&name=image.png&originHeight=926&originWidth=922&search=&size=286654&status=done&width=98) | + + + +#### indented +**描述**:缩进树布局。每个元素会占一行/一列。
![indented.png](https://cdn.nlark.com/yuque/0/2019/png/174835/1551172247854-99aa0e77-61f0-4b7e-8ab6-6d854fcd2396.png#align=left&display=inline&height=222&name=indented.png&originHeight=876&originWidth=497&search=&size=36070&status=done&width=126) + +**API**:[Indented API](https://www.yuque.com/antv/g6/hl4syb)
**参数**: + +| 参数名 | 类型 | 示例 / 可选值 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| direction | String | 'LR' | 'RL' | 'H' | 'LR' | layout 的方向。
- LR —— 根节点在左,往右布局(下图左) + +- RL —— 根节点在右,往左布局(下图中) + +- H —— 根节点在中间,水平对称布局(下图右) + +![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571832031826-33f11b5c-3d7a-4767-89b0-1d7cb6f64510.png#align=left&display=inline&height=172&name=image.png&originHeight=908&originWidth=354&search=&size=141929&status=done&width=67)  ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571832083137-c38a3f7a-885e-4acf-954a-73fbeb822bde.png#align=left&display=inline&height=166&name=image.png&originHeight=890&originWidth=278&search=&size=133215&status=done&width=52)  ![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571832100885-51d8526e-d530-4090-9f37-4fdd4f9e865a.png#align=left&display=inline&height=128&name=image.png&originHeight=910&originWidth=526&search=&size=205642&status=done&width=74) | +| indent | Number | 80 | 20 | 列间间距 | +| getHeight | Function | (d) => {
  // d 是一个节点
  return 10;
} | undefined | 节点高度的回调函数 | +| getWidth | Function | (d) => {
  // d 是一个节点
  return 20;
} | undefined | 节点宽度的回调函数 | + + + + +#### mindmap +**描述**:脑图布局。深度相同的节点将会被放置在同一层,与 compactBox 不同的是,布局不会考虑节点的大小。
![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571830487985-0c3dfc8c-fadd-4911-8ea4-1b4091a86538.png#align=left&display=inline&height=160&name=image.png&originHeight=906&originWidth=1266&search=&size=267710&status=done&width=223)
**API**:[Mindmap API](https://www.yuque.com/antv/g6/wk3mh8)
**参数**: + +| 参数名 | 类型 | 示例 / 可选值 | 默认值 | 说明 | +| --- | --- | --- | --- | --- | +| direction | String | 'H' | 'V' | 'H' | layout 的方向。
- H:horizontal(水平)—— 根节点的子节点分成两部分横向放置在根节点左右两侧
+![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571830487985-0c3dfc8c-fadd-4911-8ea4-1b4091a86538.png#align=left&display=inline&height=101&name=image.png&originHeight=906&originWidth=1266&search=&size=267710&status=done&width=141)
- V:vertical (竖直)—— 将根节点的所有孩子纵向排列
+![image.png](https://cdn.nlark.com/yuque/0/2019/png/156681/1571830515639-e66a5347-09fe-4583-81d6-178aa6920f7b.png#align=left&display=inline&height=112&name=image.png&originHeight=920&originWidth=982&search=&size=252410&status=done&width=120) | +| getHeight | Function | (d) => {
  // d 是一个节点
  return 10;
} | undefined | 节点高度的回调函数 | +| getWidth | Function | (d) => {
  // d 是一个节点
  return 20;
} | undefined | 节点宽度的回调函数 | +| getVGap | Function | (d) => {
  // d 是一个节点
  return 100;
} | 18 | 节点纵向间距的回调函数 | +| getHGap | Function | (d) => {
  // d 是一个节点
  return 50;
} | 18 | 节点横向间距的回调函数 | +| getSide | String | Function | (d) => {
  // d 是一个节点
  return 'left';
} | 'right' | 节点排布在根节点的左侧/右侧。若设置了该值,则所有节点会在根节点同一侧,即 direction = 'H' 不再起效。若该参数为回调函数,则可以指定每一个节点在根节点的左/右侧 | + + + +## 布局的切换机制 +G6 提供了两种关于布局的切换机制: + +- `updateLayout(params)`:布局方法或参数的切换 +- `changeData()`:数据的切换 + + +### 布局方法或参数切换 +**接口定义:** +```javascript +/** + * 更换布局或布局参数 + * @param {String | object} cfg 新布局配置项 + * 若 cfg 为 String 或含有 type 字段,且与之前的布局方法不同时将会更换布局 + * 否则只是更新原有布局的参数 + */ +updateLayout(cfg); +``` + +**布局方法切换:**
若参数 `cfg` 为 `String` 或是含有 `type` 字段的对象,且与之前的布局方法名不同时将会更换布局。 + +**布局参数切换:**
若参数 `cfg` 是对象且其中不含有 `type` 字段,或指定的布局方法名称与之前的布局方法相同,则保持原有布局方法,仅更新该布局的参数。 + + +### 数据切换 +**接口定义:** +```javascript +/** + * 更改源数据,根据新数据重新渲染视图 + * @param {object} data 源数据 + * @return {object} this + */ +changeData(data); +``` + + +### 切换示例 + +#### 期待效果 +初始化时使用默认 random 布局,2000 ms 后更换为允许节点重叠的 force 布局,4000 ms 后更换为不允许节点重叠的 force 布局,6000 ms 后更换数据为 `data2`。
![tutorial-layout.gif](https://cdn.nlark.com/yuque/0/2019/gif/156681/1569837754937-a1b91cef-8846-487f-a1cd-b5231fcf09a3.gif#align=left&display=inline&height=329&name=tutorial-layout.gif&originHeight=329&originWidth=440&search=&size=84736&status=done&width=440) + +#### 完整代码 +```html + + + + + Tutorial Layout Demo + + +
+ + + + + +``` + + +## 子图布局 +目前,子图布局独立与全局布局的思路,与 graph 不挂钩,直接使用实例化布局方法的方式,灌入子图数据,通过布局将位置写到相应数据中。这种机制还可供外部的全局布局使用,即使不用 G6 渲染,也可以计算节点布局后的位置。但与萧庆讨论后,决定这种方式暂时不透出够用户。在子图布局上,这种机制后续需要修改,并与全局布局思路统一( graph,controller )。 + + +### 使用方法 +```javascript +// 实例化布局 +const subgraphLayout = new G6.Layout['force']({ + center: [ 500, 450 ] +}); + +// 初始化布局,灌入子图数据 +subgraphLayout.init({ + 'nodes': subGraphNodes, + 'edges': subGraphEdges +}); + +//执行布局 +subgraphLayout.execute(); + +// 图实例根据数据更新节点位置 +graph.positionsAnimate(); +``` diff --git a/docs/manual/middle/mode.md b/docs/manual/middle/mode.md new file mode 100644 index 0000000000..1bff4dba56 --- /dev/null +++ b/docs/manual/middle/mode.md @@ -0,0 +1,82 @@ +--- +title: 交互模式 Mode +order: 5 +--- + + +## 什么是 Mode +用户在交互一张图时,可能由于意图不同而存在不同的交互模式,例如在编辑模式下点击节点需要弹出窗口让用户编辑,在查看模式下点击节点需要选中节点。 + +为了解决上述问题,G6 提供了交互模式 Mode,它是图上交互行为 [Behavior](./defaultBehavior) 的管理机制。一个图上可以有存在多种交互模式,每个交互模式包含多种交互行为 [Behavior](./defaultBehavior)。 + +例如,存在 default 和 edit 两种 mode(交互模式): +- default 模式中包含点击选中节点行为和拖拽画布行为; +- edit 模式中包含点击节点弹出编辑框行为和拖拽节点行为。 + +默认情况下,该图对 default 模式中的行为见效,即点击节点时节点被选中而不是弹出编辑框。用户可以通过简单的命令切换该图的行为模式到 edit 模式,则 default 模式中的行为失效,edit 交互模式中的行为起效,即点击节点将弹出编辑框。 + + +## 配置 Mode +在实例化图时配置 `modes` 属性: +```javascript +const graph = new G6.Graph({ + container: 'mountNode', + width: 500, + height: 500, + modes: { + // 支持的 behavior + default: [ 'drag-canvas', 'zoom-canvas' ], + edit: [ 'click-select' ] + } +}); +``` + +以上是模式定义的一个例子。在图上定义了两个模式,分别是 `default`, `edit` 。其中 `default` 包含两个个 [Behavior](https://www.yuque.com/antv/g6/default-behavior):`'drag-canvas'` 和 `'``zoom-canvas'`,都使用行为的默认参数。 + + +## 切换 Mode +默认时 Graph 会使用 `default` 的 Mode ,可以拖动和缩放画布,当需要点击选中节点时,可以通过 `graph.``setMode('edit')` 来切换到 `edit` 的 Mode 。 + +```javascript +graph.setMode('edit'); +``` + +此时 Graph 就支持了拖拽节点,`default` 模式下的拖拽画布 `'drag-canvas'`、放缩画布行为 `'zoom-canvas'` 失效。 + +在调用了 `setMode` 方法后,G6 内部进行了以下操作: + +- 解绑目前图模式的所有事件监听; +- 生成新的 Behavior ,进行事件初始化; +- 绑定新的行为对应的事件监听。 + + +## 编辑已有的 Mode +如果有已经定义好的 Behavior ([内置 Behavior](https://www.yuque.com/antv/g6/default-behavior) 或 [自定义 Behavior](https://www.yuque.com/antv/g6/self-behavior)),需要把它添加到某个模式下,可以通过 `graph.addBehaviors` 方法;需要从某个模式中移除一些 Behavior,可以使用 `graph.removeBehaviors` 方法。如下示例: +```javascript +// 向 default 模式中添加名为 drag-canvas 的行为,并使用行为的默认配置 +graph.addBehaviors('drag-canvas', 'default'); + +// 从 default 模式中移除名为 drag-canvas 的行为 +graph.removeBehaviors('drag-canvas', 'default'); + +// 向 edit 模式中添加名为 drag-canvas 的行为,并定义个性化配置 +graph.addBehaviors({ + type: 'drag-canvas', + direction: 'x' +}, 'edit'); + +// 从 edit 模式中移除名为 drag-canvas 的行为 +graph.removeBehaviors('drag-canvas', 'edit'); + +// 一次向 default 模式中添加多个行为 +graph.addBehaviors([ 'drag-canvas', 'zoom-canvas' ], 'default'); + +// 一次从 default 模式中移除多个行为 +graph.removeBehaviors([ 'drag-canvas', 'zoom-canvas' ], 'default'); +``` + + +## 相关阅读 + +- [内置交互行为 Behavior](./defaultBehavior) +- [自定义交互行为 Behavior](https://www.yuque.com/antv/g6/self-behavior) diff --git a/docs/manual/middle/nodeGroup.md b/docs/manual/middle/nodeGroup.md new file mode 100644 index 0000000000..b3f3d7d0ed --- /dev/null +++ b/docs/manual/middle/nodeGroup.md @@ -0,0 +1,254 @@ +--- +title: 节点分组 Group +order: 8 +--- + +> Feature 自 G6 3.1.2 开始支持自定义节点分组的标题了,可以渲染带有标题的分组。 + + +对于熟悉图可视化类库的用户来说,节点分组可能是比较实用的一个功能。自 G6 3.0.5 版本开始,G6 加入了节点分组的功能,详情参考[Demo](https://github.com/antvis/g6/blob/master/demos/drag-group.html)。
![group2.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1567391660645-308be946-1119-45c0-af7c-5373e78ffa7c.gif#align=left&display=inline&height=533&name=group2.gif&originHeight=533&originWidth=763&search=&size=261828&status=done&width=763) + + +### 数据结构 +新增节点分组功能时,尽量保持了 G6 数据结构的稳定性。为了体现分组的特性,我们在 nodes 数据项中加入了 groupId 属性,另外新增了 groups 字段,用于表示数据中所包括的分组及各分组之间的层级关系。 + +当 groups 中的对象包括 title 属性字段时,表示要渲染带有标题的分组,title 字段的类型可以是 string 或 object: + +- title:类型为 string 时,值表示标题名称,不能设置任何样式,也不能调整标题位置; +- title 为 object 时,可以设置标题的样式及位置,title 中各字段含义: + - text:必选,分组的标题,类型为 string; + - offsetX:可选,默认为 0,表示 x 方向上的偏移量; + - offsetY:可选,默认为 0,表示 y 方向上的偏移量; + - stroke:字体边框颜色,同时也支持 fill、fontSize 等所有的[文本样式属性](https://www.yuque.com/antv/g6/gs4gno)。 + + + +```javascript +{ + nodes: [ + { + id: 'node1', + label: 'node1', + groupId: 'group1', + x: 100, + y: 100 + }, + { + id: 'node2', + label: 'node2', + groupId: 'group1', + x: 150, + y: 100 + }, + { + id: 'node3', + label: 'node3', + groupId: 'group2', + x: 300, + y: 100 + }, + ], + edges: [ + { + source: 'node1', + target: 'node2' + } + ], + groups: [ + { + id: 'group1', + title: { + text: '第一个分组', + stroke: '#444', + offsetX: 0, + offsetY: 0 + }, + parentId: 'p1' + }, + { + id: 'group2', + parentId: 'p1' + }, + { + id: 'p1' + } + ] +} +``` + + +### 如何渲染 group +当 nodes 中存在 `groupId` 属性字段时,在渲染过程中,G6 就会自动去渲染分组,当存在 groups 属性时,G6 就会自定去判断各分组之间的层级关系,并渲染出嵌套的分组。但当没有使用任何布局的时候,需要在 nodes 中指定各个阶段的坐标信息,即阶段的 `x` 和 `y` 属性值。 + +```javascript +const data = { + nodes: [ + { + id: 'node6', + groupId: 'group3', + label: 'rect', + x: 100, + y: 300 + }, + { + id: 'node1', + label: 'fck', + groupId: 'group1', + x: 100, + y: 100 + }, + { + id: 'node9', + label: 'noGroup1', + groupId: 'p1', + x: 300, + y: 210 + }, + { + id: 'node2', + label: 'node2', + groupId: 'group1', + x: 150, + y: 200 + }, + { + id: 'node3', + label: 'node3', + groupId: 'group2', + x: 300, + y: 100 + }, + { + id: 'node7', + groupId: 'p1', + label: 'node7-p1', + x: 200, + y: 200 + }, + { + id: 'node10', + label: 'noGroup', + groupId: 'p2', + x: 300, + y: 210 + } + ], + edges: [ + { + source: 'node1', + target: 'node2' + }, + { + source: 'node2', + target: 'node3' + } + ], + groups: [ + { + id: 'group1', + title: { + text: '第一个分组', + stroke: '#444', + offsetX: -30, + offsetY: 30 + }, + parentId: 'p1' + }, + { + id: 'group2', + parentId: 'p1' + }, + { + id: 'group3', + parentId: 'p2' + }, + { + id: 'p1' + }, + { + id: 'p2' + } + ] +}; + +const graph = new G6.Graph({ + container: 'mountNode', + width: 800, + height: 600, + pixelRatio: 2, + modes: { + default: [ 'drag-canvas' ] + }, + defaultNode: { + shape: 'circleNode' + }, + defaultEdge: { + color: '#bae7ff' + } +}); + +graph.data(data); +graph.render(); +``` + +渲染的效果如下图所示:
![image.png](https://cdn.nlark.com/yuque/0/2019/png/244306/1571190983755-4599403c-7c3d-4c23-9539-e91a5c038984.png#align=left&display=inline&height=503&name=image.png&originHeight=1006&originWidth=1600&search=&size=415977&status=done&width=800)
此时,不能对分组中的节点及分组进行任何操作,接下来,我们介绍可以对分组进行的各种操作。 + + +### 操作分组 +只是简单地将分组渲染出来,并没有多大的实用价值,只有支持一系列的交互操作后,才能最大程度地体现分组的价值。 + +在 G6 中,我们内置了 `drag-group`、`collapse-expand-group` 及  `drag-node-with-group`  三个[Behavior](https://www.yuque.com/antv/g6/default-behavior),共支持以下的交互行为: + +- 拖动分组; +- 通过拖拽,动态改变分组中的节点数量及分组大小; +- 将一个分组从父分组中拖拽出来,并取消分组直接的关联关系,动态改变父分组的大小; +- 双击分组,收起和展开分组: + - 当收起分组后,与分组节点中的连线会自动连到分组上; + - 展开分组后,恢复之前的连接和位置。 +- 拖动节点,所在的分组高亮,当拖到其他分组时,其他分组高亮; +- [暂不支持] ~~将分组拖入到另外个分组,并改变分组层级的所属关系~~。 + + +#### drag-group +`drag-group` Behavior,支持拖动分组,拖动分组过程中,会动态改变分组中节点和边的位置,在拖拽完成以后,保持分组和节点的相对位置不变。 + + +#### collapse-expand-group +`collapse-expand-group` Behavior,支持双击分组收起和展开分组,收起分组以后,隐藏分组中的所有节点,外部节点和分组中节点有连线的情况下,所有连接会连接到分组上面。 + +优化目前只支持双击交互,正式发布时,会支持用户自定义交互方式,来实现分组的收起和展开。 + + +#### drag-node-with-group +`drag-node-with-group` Behavior 和 `drag-node` 类似,但该 Behavior 仅用于用 group 时 node 的拖拽。拖拽 node 过程中,会动态改变 node 所在的分组。 + +优化目前暂不支持将多个节点拖出拖入到分组中。 + +```javascript +const graph = new G6.Graph({ + container: 'mountNode', + width: 800, + height: 600, + pixelRatio: 2, + modes: { + default: [ 'drag-group', 'collapse-expand-group', 'drag- node-with-group' ] + }, + defaultNode: { + shape: 'circleNode' + }, + defaultEdge: { + color: '#bae7ff' + } +}); +``` + +将这三个内置提供的 Behavior 加入到 modes 中以后的效果如下图所示。 + +![group2.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1567391075518-249e7649-5861-41ec-9e81-ea58224de9cb.gif#align=left&display=inline&height=533&name=group2.gif&originHeight=533&originWidth=763&search=&size=261828&status=done&width=763) + +### 适用的场景 + +1. 风控、反洗钱、保险骗保、网络诈骗、信用卡诈骗等场景下团伙分析; +1. 特征分析:同一个分组中的节点在某些特征上面比较相似; +1. 整理节点:当类似的节点放到一个分组中,只渲染分组,不渲染节点,减少干扰元素。 + diff --git a/docs/manual/middle/randomLayout.png b/docs/manual/middle/randomLayout.png new file mode 100644 index 0000000000..2baaeaf343 Binary files /dev/null and b/docs/manual/middle/randomLayout.png differ diff --git a/docs/manual/middle/state.md b/docs/manual/middle/state.md new file mode 100644 index 0000000000..cae80f4048 --- /dev/null +++ b/docs/manual/middle/state.md @@ -0,0 +1,137 @@ +--- +title: 状态 State +order: 6 +--- + + +## 什么是 state +G6 中的 **state**,指的是状态,包括**交互状态**和**业务状态**两种。 + + +### 交互状态 +交互状态是与具体的交互动作密切相关的,如用户使用鼠标选中某个节点,hover 到某条边。 + +G6 中默认处理的是交互状态。 + + +### 业务状态 +指根据用户业务需求自定义的状态。业务状态是与交互动作无关的,与具体业务逻辑强相关的,也可理解为是强数据驱动的。如某个任务的执行状态、某条申请的审批状态等,不同的数据值代表不同的业务状态。业务状态与用户交互动作无关,但在 G6 中的处理方式同交互状态一致。 + + +## 何时使用 state +判断是否该使用 state 的原则很简单,从交互和业务两个层面来看: + +- 某个交互动作要改变节点或边的样式及属性; +- 呈现给用户的内容会根据数据改变(如 1 代表成功,0 代表失败)。 + +满足上述条件其一,则应该使用 state。 + + +## 配置不同 state 的样式 +在 G6 中,配置交互状态和业务状态的方式是相同的。对于部分只使用 G6 来完成某个需求的开发,而不想深入理解G6的用户,其实不用区分交互状态和业务状态的区别,使用相同的方式定义状态,使用相同的方式使用状态,完全没有理解成本。 + +在 G6 中,定义 state 时,我们有两种选择: + +- 在实例化 Graph 时,通过 `nodeStateStyles` 和 `edgeStateStyles` 来定义; +- 在自定义节点时,在 options 配置项的 `stateStyles` 中定义状态。 + + +### 实例化 Graph 时定义 state 样式 +```javascript +const graph = new G6.Graph({ + container: 'mountNode', + width: 800, + height: 600, + defaultNode: { + shape: 'diamond', + style: { // 默认状态样式 + fill: 'blue' + } + }, + nodeStateStyles: { + hover: { // hover 状态为 true 时的样式 + fill: '#d3adf7' + }, + running: { // running 状态为 true 时的样式 + stroke: 'steelblue' + } + } +}) +``` + +上面的实例代码中,我们在实例化 Graph 时候,通过 `nodeStateStyles` 定义了交互状态 `hover` 和业务状态`running`,当用户操作过程中,鼠标 `hover` 到某个节点上时,节点的填充色就会变为指定的颜色,当某个任务状态变为正在执行时,节点的边框就会变为 `running` 状态定义的颜色。
![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570584254138-c2ef66cc-0067-41bf-8235-63798c65a3c1.gif#align=left&display=inline&height=181&name=3.gif&originHeight=181&originWidth=247&search=&size=8886&status=done&width=247) + +同理,defaultEdge 中的 style 属性定义了默认状态下边的样式,使用 `edgeStateStyles` 可以定义不同状态下边的样式。 + + +### 自定义节点和边时定义 state 样式 +下面代码是在自定义节点时候通过 `stateStyles` 定义的交互状态 `hover` 和 `selected`。用户在操作过程中,如果hover到某个节点,则节点的透明度会变为 0.8,如果选中某个节点,选中节点的边框宽度变为 3。 +```javascript +G6.registerNode('customShape', { + // 自定义节点时的配置 + options: { + size: 60, + style: { + lineWidth: 1 + }, + stateStyles: { + // 鼠标hover状态下的配置 + hover: { + fillOpacity: 0.8 + }, + // 选中节点状态下的配置 + selected: { + lineWidth: 3 + } + } + } +} +``` +![3.gif](https://cdn.nlark.com/yuque/0/2019/gif/244306/1570584254137-65f129dd-45fc-430d-9485-991ee1d2dbba.gif#align=left&display=inline&height=181&name=3.gif&originHeight=181&originWidth=247&search=&size=8385&status=done&width=247) + + +## 使用 state +不管使用哪种方式,当我们定义好了 state 以后,**使用 `graph.setItemState` 来使定义的状态生效**。 + +那么,我们该在什么地方使用 **`graph.setItemState`** 来使 state 生效呢?一种是直接使用 `graph.on` 监听事件,在回调中使 state 生效,另一种是在自定义 Behavior 中使 state 生效。 + + +### graph.on +在回调函数中使定义的交互状态 hover 生效。 +```javascript +graph.on('node:mouseenter', evt => { + const { item } = evt + graph.setItemState(item, 'hover', true) +}) + +graph.on('node:mouseleave', evt => { + const { item } = evt + graph.setItemState(item, 'hover', false) +}) +``` + + +### Behavior +在自定义 Behavior 中使定义的交互状态 selected 生效。 +```javascript +G6.registerBehavior('nodeClick', { + getEvents() { + return { + 'node:click': 'onClick' + }; + }, + onClick(e) { + e.preventDefault(); + if (!this.shouldUpdate.call(this, e)) { + return; + } + const { item } = e; + const graph = this.graph; + graph.setItemState(item, 'selected', true) + } +}) +``` + + +## 小结 +G6 底层提供了状态管理的能力,通过使用 state,简化了状态管理,降低了用户的认知成本。更多关于 G6 中状态的内容请参考 [G6 状态量思考](https://www.yuque.com/antv/g6/xiux28)。