选择X6还是G6
在技术选型的时候遇到X6和G6都可以做流程图。 大家可以看下www.zhihu.com/question/43… 大佬们的回答
总结下来就是,偏交互和编辑就X6 偏展示,图大就G6
什么是X6
X6 是基于 HTML 和 SVG 的图编辑引擎,提供低成本的定制能力和开箱即用的内置扩展,方便我们快速搭建 DAG 图、ER 图、流程图、血缘图等应用。
思维导图
SVG基本知识
SVG 是 Scalable Vector Graphics 的缩写,意为可缩放矢量图形,改变大小不会有png图片模糊的问题。
底层用的svg所以很多自定义的图形之类的可以直接使用svg来进行绘制。
- 语法
<svg>
<circle cx="100" cy="100" r="50"/>
</svg>
- 基本图形
- 圆形 (circle)
- 矩形(rect)
- 椭圆 (ellipse)
- 线条(line)
- 折线 (polyline)
- 多边形(polygon)
- 路径 (path)
- 文本(text)
应用场景
优点和缺点
优点
- 🌱 极易定制:支持使用 SVG/HTML/React/Vue 定制节点样式和交互;
- 🚀 开箱即用:内置 10+ 图编辑配套扩展,如框选、对齐线、小地图等;
- 🧲 数据驱动:基于 MVC 架构,用户更加专注于数据逻辑和业务逻辑;
- 💯 事件驱动:可以监听图表内发生的任何事件。
缺点
- 学习曲线较陡:如果你对 JavaScript 或图表绘制库没有经验,学习和使用 antv X6 可能需要一些时间和精力。它使用了一些复杂的概念和术语,并有自己的一套 API,需要花些时间来理解和适应。
- 文档和示例不够丰富:尽管 antv X6 有一份官方文档和示例,但在某些方面可能仍然缺乏详细和全面的解释。这可能会给新用户带来困惑和挫败感。
- 社区支持相对较小:与一些其他知名的图表库相比,antv X6 的社区规模相对较小。这意味着你可能会在使用过程中遇到问题时,获得的帮助和支持相对有限。
快速入门
安装
# npm
$ npm install @antv/x6 --save
# yarn
$ yarn add @antv/x6
画布
- 在 X6 中,Graph 是图的载体,它包含了图上的所有元素(节点、边等)。 就是将所有元素绘制在上面
配置
new Graph(options: Options)
// 等同于
const graph = new Graph({
container: document.getElementById('container'), // 画布容器 类型vue的挂载的元素
width:"100px",
height:"200px"
mousewheel:true, // 鼠标滚轮缩放,默认禁用
grid:true, // 网格是不显示
panning: {
enabled: true,
},
})
元素
Cell 是 Node 和 Edge 的基类,包含节点和边的通用属性和方法定义,如属性样式、可见性、业务数据等,并且在实例化、样式定制、默认选项、自定义选项等方面具有相同的行为。
| 选项名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| id | String | undefined | 节点/边的唯一标识,默认使用自动生成的 UUID。 |
| markup | Markup | undefined | 节点/边的 SVG/HTML 片段。 |
| attrs | Object | { } | 节点/边属性样式。 |
| shape | String | undefined | 渲染节点/边的图形。 |
| view | String | undefined | 渲染节点/边的视图。 |
| zIndex | Number | undefined | 节点/边在画布中的层级,默认根据节点/边添加顺序自动确定。 |
| visible | Boolean | true | 节点/边是否可见。 |
| parent | String | undefined | 父节点。 |
| children | String[] | undefined | 子节点/边。 |
| data | any | undefined | 节点/边关联的业务数据。 |
节点
节点类型
- 内置节点 创建方式
graph.addNode({
x: 360, // 相对于画布的X轴
y: 340, // 相对于画布的Y轴
width: 120,
height: 60,
label: "rect", // 节点标签文字节点元素
attrs: { // 属性
body: {
stroke: "#237804", // 线条颜色
fill: "#73d13d", // 填充色
rx: 10, // 圆角
ry: 10
},
// 文本元素的属性
label: {
refX: "100%", // 相对于节点X轴的宽度的100%
refX2: -8,
refY: "100%", // 相对于节点Y轴的宽度的100%
refY2: -8,
textAnchor: "end", // 文本在画布x轴的位置 start middle end
textVerticalAnchor: "bottom" // 文本在画布x轴的位置 top middle bottom
}
}
});
- 自定义节点
我们可以通过 markup 和 attrs 来定制节点的形状和样式markup 可以类比 HTML,attrs 类比 CSS
makup
interface Markup {
tagName: string // SVG/HTML 元素标签名。
ns?: string // SVG/HTML 元素命名空间。 nameSpace
selector?: string // 该元素的选择器(唯一),通过选择器来定位该元素或为该元素指定属性样式。
groupSelector?: string | string[] //该元素的群组选择器,可以同时为该群组对应的多个元素指定样式
// 该元素的默认属性键值对,通常用于定义那些不变的通用属性,这些默认属性也可以在实例化节点时被覆盖。需要注意的是 markup 中的 attrs 属性只支持原生的 SVG 属性,也就是说 X6 的在这里不可用。
attrs?: { [key: string]: string | number }
style?: { [key: string]: string | number }
className?: string | string[]
textContent?: string // 该元素的文本内容。
children?: Markup[]
}
- svg
import { Graph } from '@antv/x6'
// 自定义节点需要注册,注册后可以直接使用上面的 grap.addNode('custom-node')来进行添加
Graph.registerNode(
'custom-node',
{
width: 200,
height: 60,
attrs: {
body: {
stroke: '#5F95FF',
strokeWidth: 1,
fill: 'rgba(95,149,255,0.05)',
refWidth: 1,
refHeight: 1,
},
image: {
'xlink:href':
'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',
width: 16,
height: 16,
x: 12,
y: 12,
},
title: {
text: 'Node',
refX: 40,
refY: 14,
fill: 'rgba(0,0,0,0.85)',
fontSize: 12,
'text-anchor': 'start',
},
text: {
text: 'this is content text',
refX: 40,
refY: 38,
fontSize: 12,
fill: 'rgba(0,0,0,0.6)',
'text-anchor': 'start',
},
},
markup: [
{
tagName: 'rect', // 对应svg的名字,还有一些是X6 自带的
selector: 'body', // 和上面的body 对应
},
{
tagName: 'image',
selector: 'image',
},
{
tagName: 'text',
selector: 'title',
},
{
tagName: 'text',
selector: 'text',
},
],
},
true,
)
const graph = new Graph({
container: document.getElementById('container')!,
grid: true,
})
graph.addNode({
x: 200,
y: 160,
shape: 'custom-node',
})
- react
- vue
// 子组件
<template>
<div class="app-content">
<div id="container"></div>
<TeleportContainer />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import ProgressNode from './components/ProgressNode.vue'
import { Graph } from '@antv/x6'
import { register, getTeleport } from '@antv/x6-vue-shape'
register({
shape: 'custom-vue-node',
width: 100,
height: 100,
component: ProgressNode,
})
const TeleportContainer = getTeleport()
export default defineComponent({
name: 'App',
components: {
TeleportContainer,
},
mounted() {
const graph = new Graph({
container: document.getElementById('container')!,
background: {
color: '#F2F7FA',
},
autoResize: true,
})
graph.addNode({
shape: 'custom-vue-node',
x: 100,
y: 60,
})
},
})
</script>
连接桩
连接桩是节点上的固定连接点,很多图应用都有连接桩,并且有些应用还将连接桩分为输入连接桩和输出连接桩
连接桩分组:同行为和外观的连接桩归为同一组,并通过 groups 选项来设置分组
interface PortGroupMetadata {
markup?: Markup // 连接桩 DOM 结构定义。
attrs?: Attr.CellAttrs // 属性和样式。
zIndex?: number | 'auto' // 连接桩的 DOM 层级,值越大层级越高。
// 群组中连接桩的布局。
position?: [number, number] | string | { name: string; args?: object }
label?: {
// 连接桩标签
markup?: Markup
position?: {
// 连接桩标签布局
name: string // 布局名称
args?: object // 布局参数
}
}
}
边
-
连接到画布上的点
const edge = graph.addEdge({ source: { x: 40, y: 40 }, // 起点的坐标 target: { x: 180, y: 80 }, // 终点的坐标 }) -
连接到节点/边
const edge = graph.addEdge({ source: { cell: 'source-cell-id' }, // 元素的ID target: { cell: 'target-cell-id' }, // 元素的id }) -
连接到节点上的连接桩
const edge = graph.addEdge({ source: { cell: 'source-cell-id', port: 'port-id' }, // 元素的ID 和连接点的ID target: { cell: 'target-cell-id', port: 'port-id' }, }) -
连接到节点上的某个元素
const edge = graph.addEdge({ source: { cell: 'source-cell-id', selector: 'some-selector' }, target: { cell: 'target-cell-id', selector: 'some-selector' }, })
属性
| 选项 | 类型 | 默认值 | 必选 | 描述 | |
|---|---|---|---|---|---|
| source | TerminalData | 起点或起始节点、连接桩信息。 | |||
| target | TerminalData | 终点或终止节点、连接桩信息。 | |||
| vertices | Point.PointLike[] | 路径点。 | |||
| router | RouterData | 路由。 | |||
| connector | ConnectorData | 连接器。 | |||
| labels | Label[] | string[] | 标签。 | ||
| defaultLabel | Label | 默认标签。 |
箭头
内置箭头样式
this.graph.addEdge({
source: [80, 160], // 开始的坐标
target: [480, 160], // 结束点的坐标
attrs: {
line: {
sourceMarker: 'block', //开始箭头
targetMarker: 'block', // 结束
stroke: '#8f8f8f',
strokeWidth: 1,
},
},
})
自定义箭头
// svg path 自定义箭头
graph.addEdge({
source: { x: 100, y: 40 }, // 开始的坐标
target: { x: 400, y: 40 }, // 结束的坐标
attrs: {
line: {
stroke: '#31d0c6',
sourceMarker: {
name: 'path',
d: 'M5.5,15.499,15.8,21.447,15.8,15.846,25.5,21.447,25.5,9.552,15.8,15.152,15.8,9.552z',
},
targetMarker: {
name: 'path',
offsetX: 10,
d: 'M4.834,4.834L4.833,4.833c-5.889,5.892-5.89,15.443,0.001,21.334s15.44,5.888,21.33-0.002c5.891-5.891,5.893-15.44,0.002-21.33C20.275-1.056,10.725-1.056,4.834,4.834zM25.459,5.542c0.833,0.836,1.523,1.757,2.104,2.726l-4.08,4.08c-0.418-1.062-1.053-2.06-1.912-2.918c-0.859-0.859-1.857-1.494-2.92-1.913l4.08-4.08C23.7,4.018,24.622,4.709,25.459,5.542zM10.139,20.862c-2.958-2.968-2.959-7.758-0.001-10.725c2.966-2.957,7.756-2.957,10.725,0c2.954,2.965,2.955,7.757-0.001,10.724C17.896,23.819,13.104,23.817,10.139,20.862zM5.542,25.459c-0.833-0.837-1.524-1.759-2.105-2.728l4.081-4.081c0.418,1.063,1.055,2.06,1.914,2.919c0.858,0.859,1.855,1.494,2.917,1.913l-4.081,4.081C7.299,26.982,6.379,26.292,5.542,25.459zM8.268,3.435l4.082,4.082C11.288,7.935,10.29,8.571,9.43,9.43c-0.858,0.859-1.494,1.855-1.912,2.918L3.436,8.267c0.58-0.969,1.271-1.89,2.105-2.727C6.377,4.707,7.299,4.016,8.268,3.435zM22.732,27.563l-4.082-4.082c1.062-0.418,2.061-1.053,2.919-1.912c0.859-0.859,1.495-1.857,1.913-2.92l4.082,4.082c-0.58,0.969-1.271,1.891-2.105,2.728C24.623,26.292,23.701,26.983,22.732,27.563z',
},
},
},
})
自定义箭头注册
// 注册
// image2 是注册的name
Graph.registerMarker('image2', (args) => {
const { imageUrl, imageWidth, imageHeight, ...attrs } = args
return {
...attrs, // 原样返回非特殊涵义的参数
tagName: 'image', // 使用 svg <image> 标签渲染箭头,其余键值对都将作为该元素的属性。
width: imageWidth, // 宽
height: imageHeight, // 高
'xlink:href': imageUrl, // url地址
}
})
// 使用注册的箭头
graph.addEdge({
source: { x: 140, y: 400 },
target: { x: 420, y: 400 },
attrs: {
line: {
sourceMarker: {
name: 'image2',
imageUrl:
'http://cdn3.iconfinder.com/data/icons/49handdrawing/24x24/left.png',
imageWidth: 24,
imageHeight: 24,
y: -12,
},
targetMarker: {
name: 'image2', // name和注册name 要一致
imageUrl:
'http://cdn3.iconfinder.com/data/icons/49handdrawing/24x24/left.png',
imageWidth: 24,
imageHeight: 24,
y: -12,
},
},
},
})
交互
X6 最吸引开发者的地方是具备非常完整的交互定制能力。
- 连接的时候是否吸附
- 是不是可以建循环连线
- 是否允许边连接到节点(非节点上的连接桩)
- 是不是允许连接到边
- 拖动是不是课可以高亮
AntV X6 的交互功能使得用户可以与图形进行直接的互动操作和控制,以实现更丰富的用户体验。以下是 AntV X6 交互的一些常见功能:
- 节点拖拽和调整:用户可以通过鼠标拖拽节点来调整它们的位置,改变节点间的连接关系和布局。这对于网络拓扑图、流程图等应用非常有用。
- 缩放和平移:用户可以使用鼠标滚轮来缩放图形,或者通过拖动画布来平移图形的显示区域。这使得用户能够对大规模的图形进行浏览和导航。
- 高亮和选中:用户可以通过悬停鼠标或单击节点来高亮相关的图形元素,以突出显示它们或触发其他操作,例如显示详细信息或执行特定的操作。
- 节点大小和样式调整:用户可以调整节点的大小、形状和样式,以满足特定的需求。这对于定制化图形的外观和美观性非常重要。
- 数据筛选和筛选器:用户可以根据特定的条件和参数来筛选数据,并动态更新图形的显示。这有助于用户通过交互性的方式探索和分析数据。
- 事件交互:AntV X6 提供了各种事件处理机制,允许开发者定义和处理不同的用户交互事件,例如点击、拖拽、放大缩小等,以及自定义的交互行为。
AntV X6 的交互功能使得开发者能够根据不同的场景和需求,为图形应用添加交互性和用户操作的能力,从而提升应用的可用性和用户体验。
事件
视图交互事件
用来监听视图的事件
| 事件 | cell 节点/边 | node 节点 | port 连接桩 | edge 边 | blank 画布空白区域 |
|---|---|---|---|---|---|
| 单击 | cell:click | node:click | node:port:click | edge:click | blank:click |
| 双击 | cell:dblclick | node:dblclick | node:port:dblclick | edge:dblclick | blank:dblclick |
| 右键 | cell:contextmenu | node:contextmenu | node:port:contextmenu | edge:contextmenu | blank:contextmenu |
| 鼠标按下 | cell:mousedown | node:mousedown | node:port:mousedown | edge:mousedown | blank:mousedown |
| 移动鼠标 | cell:mousemove | node:mousemove | node:port:mousemove | edge:mousemove | blank:mousemove |
| 鼠标抬起 | cell:mouseup | node:mouseup | node:port:mouseup | edge:mouseup | blank:mouseup |
| 鼠标滚轮 | cell:mousewheel | node:mousewheel | - | edge:mousewheel | blank:mousewheel |
| 鼠标进入 | cell:mouseenter | node:mouseenter | node:port:mouseenter | edge:mouseenter | graph:mouseenter |
| 鼠标离开 | cell:mouseleave | node:mouseleave | node:port:mouseleave | edge:mouseleave | graph:mouseleave |
graph.on('cell:click', ({ e, x, y, cell, view }) => {})
graph.on('node:click', ({ e, x, y, node, view }) => {})
graph.on('edge:click', ({ e, x, y, edge, view }) => {})
graph.on('blank:click', ({ e, x, y }) => {})
graph.on('cell:mouseenter', ({ e, cell, view }) => {})
graph.on('node:mouseenter', ({ e, node, view }) => {})
graph.on('edge:mouseenter', ({ e, edge, view }) => {})
graph.on('graph:mouseenter', ({ e }) => {})
数据
导出
{
id: string,
shape: string,
position: {
x: number
y: number
},
size: {
width: number
height: number
},
attrs: object,
zIndex: number,
}
导入
graph.fromJSON([
{
id: 'node1',
x: 40,
y: 40,
width: 100,
height: 40,
label: 'Hello',
shape: 'rect',
},
{
id: 'node2',
x: 40,
y: 40,
width: 100,
height: 40,
label: 'Hello',
shape: 'ellipse',
},
{
id: 'edge1',
source: 'node1',
target: 'node2',
shape: 'edge',
},
])
丰富的扩展能力
节点的工具
node-edite
编辑节点
// 2.8.0 版本之前使用方式
graph.on('node:dblclick', ({ node, e }) => {
node.addTools({
name: 'node-editor',
args: {
event: e,
},
})
})
// 2.8.0 版本之后使用方式
node.addTools({
name: 'node-editor',
})
边的工具
edge-edtie
// 2.8.0 版本之前使用方式
graph.on('node:dblclick', ({ node, e }) => {
edge.addTools({
name: 'edge-editor',
args: {
event: e,
},
})
})
// 2.8.0 版本之后使用方式
edge.addTools({
name: 'edge-editor',
})
插件
- 图形变换
- 对齐线
- 复制粘贴
- 快捷键
- 撤销重做
- 框选
- 滚动画布
- 小地图
- Dnd
- Stencil
- 导出 demo