AntV X6 图编辑引擎使用文档 - 我的博客
我的博客

AntV X6 图编辑引擎使用文档

AntV X6 是蚂蚁集团开源的图编辑引擎,提供高性能、高可定制的图编辑能力,适用于流程图编辑器、ER 图、BPMN 编辑器等场景

| 3.4k 字 | 阅读时间 9 分钟

1. 概述

1.1 什么是 AntV X6

AntV X6 是蚂蚁集团 AntV 团队开源的图编辑引擎,专注于提供高性能、高可定制的图编辑能力。它基于 HTML 和 SVG 渲染,采用 MVC(Model-View-Controller)架构,为开发者提供了丰富的 API 和插件生态,用于快速构建图编辑、图分析、图可视化类应用。

X6 不是传统的图表库(如 G2),也不是纯粹的图可视化库(如 G6),而是专注于图编辑场景,强调节点和边的交互操作能力。

1.2 核心特性

特性说明
MVC 架构数据(Model)与视图(View)分离,通过事件总线通信
丰富的内置元素矩形、圆形、椭圆、多边形、路径、图片等内置节点/边类型
灵活的自定义能力支持自定义 Shape、HTML 节点、React/Vue 组件节点
强大的插件生态框选、对齐线、键盘快捷键、剪贴板、历史记录、小地图等 11 个内置插件
完善的交互系统拖拽、缩放、平移、连线、框选等开箱即用的交互能力
虚拟渲染v3.x 新增,支持大图场景下的按需渲染
动画系统v3.x 新增,基于 Web Animations API 的关键帧动画
框架集成官方支持 React、Vue、Angular 三大框架
TypeScript完整的 TypeScript 类型定义

1.3 适用场景

  • 流程图编辑器 — 工作流、审批流、业务流程
  • ER 图 — 数据库表关系可视化
  • BPMN 编辑器 — 业务流程建模
  • DAG 编辑器 — 任务编排、CI/CD 流水线
  • 思维导图 — 知识管理、头脑风暴
  • 组织架构图 — 人员层级关系
  • 网络拓扑图 — 网络设备连接关系
  • UML 类图 — 软件设计

1.4 版本历史

版本状态关键变化
v1.x已停止维护初始稳定版本,API 基本成型
v2.x已停止维护默认异步渲染(async: true),API 微调
v3.x当前稳定版插件合并到主包、动画系统、虚拟渲染、默认启用画布拖拽

2. 快速开始

2.1 安装

# npm
npm install @antv/x6 --save

# yarn
yarn add @antv/x6

# pnpm
pnpm add @antv/x6

框架集成包(按需安装):

# React 集成(需要 React 18+)
npm install @antv/x6-react-shape --save

# Vue 集成
npm install @antv/x6-vue-shape --save

# Angular 集成
npm install @antv/x6-angular-shape --save

2.2 第一个图

import { Graph } from '@antv/x6'

const graph = new Graph({
  container: document.getElementById('container'),
  width: 800,
  height: 600,
  background: { color: '#F2F7FA' },
  grid: true,
  panning: true,
  mousewheel: true,
})

const source = graph.addNode({
  shape: 'rect', x: 80, y: 40, width: 100, height: 40,
  label: '开始',
  attrs: {
    body: { fill: '#e6f7ff', stroke: '#5F95FF', strokeWidth: 2, rx: 6, ry: 6 },
    text: { fill: '#333', fontSize: 14 },
  },
})

const target = graph.addNode({
  shape: 'rect', x: 300, y: 40, width: 100, height: 40,
  label: '结束',
  attrs: {
    body: { fill: '#f6ffed', stroke: '#52c41a', strokeWidth: 2, rx: 6, ry: 6 },
    text: { fill: '#333', fontSize: 14 },
  },
})

graph.addEdge({
  shape: 'edge', source, target,
  attrs: {
    line: {
      stroke: '#5F95FF', strokeWidth: 2,
      targetMarker: { name: 'block', args: { fill: '#5F95FF' } },
    },
  },
})

3. 核心概念

3.1 架构概览

X6 采用经典的 MVC(Model-View-Controller) 架构:

层级核心类职责
ControllerGraph主 API 入口,编排模型、视图、插件和注册表
ModelCell / Model / Collection维护 Cell 集合,通过事件总线发出变更事件
ViewCellView / NodeView / EdgeView将模型渲染为 SVG DOM 元素

3.2 Cell(基类)

CellNodeEdge 的共同基类:

cell.prop('attrs/body/fill', '#ff0000')   // 修改属性
cell.attr('body/fill', '#ff0000')          // 修改 SVG 属性
cell.setData({ status: 'active' })         // 设置业务数据
cell.getData()                              // 获取业务数据
cell.remove()                               // 删除元素
cell.clone()                                // 克隆元素
cell.toBack() / cell.toFront()             // 层级操作

3.3 Node(节点)

const node = graph.addNode({
  shape: 'rect', x: 100, y: 40, width: 100, height: 40,
  label: '节点',
  attrs: {
    body: { fill: '#fff', stroke: '#333', strokeWidth: 2, rx: 6, ry: 6 },
    text: { fill: '#000', fontSize: 14 },
  },
})

3.4 Edge(边)

const edge = graph.addEdge({
  shape: 'edge', source: 'node1', target: 'node2',
  vertices: [{ x: 100, y: 200 }],
  router: { name: 'orth' },
  connector: { name: 'rounded' },
  labels: ['边标签'],
  attrs: { line: { stroke: '#333', strokeWidth: 2, targetMarker: 'block' } },
})

3.5 Port(连接桩)

const node = graph.addNode({
  shape: 'rect', x: 100, y: 40, width: 100, height: 40,
  ports: {
    groups: {
      top: { position: 'top', attrs: { circle: { r: 4, magnet: true, stroke: '#5F95FF', fill: '#fff' } } },
    },
    items: [{ group: 'top', id: 'port1' }],
  },
})

4. Graph 画布详解

4.1 构造器选项

const graph = new Graph({
  container: document.getElementById('container'),
  width: 800,
  height: 600,
  autoResize: true,
  panning: true,
  mousewheel: true,
  grid: { visible: true, type: 'doubleMesh', size: 10 },
  background: { color: '#F2F7FA' },
})

4.2 画布操作

graph.resize(800, 600)              // 调整大小
graph.translate(20, 20)               // 平移
graph.zoom(0.2)                       // 放大 0.2
graph.zoom(-0.2)                     // 缩小 0.2
graph.zoomTo(1.2)                    // 设置缩放比例
graph.zoomToFit({ maxScale: 1 })     // 缩放适应所有元素
graph.centerContent()                 // 居中显示
graph.dispose()                       // 销毁画布

4.3 背景与网格

const graph = new Graph({
  container: document.getElementById('container'),
  background: {
    color: '#F2F7FA',
    image: 'data:image/svg+xml,...',
    repeat: 'repeat',
    opacity: 0.5,
  },
  grid: {
    visible: true,
    type: 'doubleMesh',
    args: [
      { color: '#eee', thickness: 1 },
      { color: '#ddd', thickness: 1, factor: 4 },
    ],
    size: 10,
  },
})

5. 节点详解

5.1 内置节点类型

构造器Shape 名称说明
Shape.Rectrect矩形
Shape.Circlecircle圆形
Shape.Ellipseellipse椭圆
Shape.Polygonpolygon多边形
Shape.Polylinepolyline折线
Shape.Pathpath路径
Shape.Imageimage图片
Shape.HTMLhtmlHTML 节点

5.2 节点操作

const node = graph.addNode({ shape: 'rect', x: 100, y: 40, width: 100, height: 40 })

// 位置
node.position(200, 100)
node.move(50, 30)

// 大小
node.resize(120, 60)
node.scale(1.5, 1.5)

// 旋转
node.rotate(45)

// 显示/隐藏
node.show() / node.hide() / node.toggleVisible()

// 删除
node.remove()
graph.removeCells([node1, node2])

// 克隆
const cloned = node.clone()

// 层级
node.toFront() / node.toBack() / node.setZIndex(10)

5.3 节点数据绑定

node.setData({ status: 'active', count: 5 })
const data = node.getData()

node.on('change:data', ({ current, previous }) => {
  console.log('数据变更:', previous, '->', current)
  if (current.status === 'active') {
    node.attr('body/fill', '#e6f7ff')
  }
})

6. 边详解

6.1 路由(Router)

路由说明
normal直线连接(默认)
orth正交路由(仅水平/垂直线段)
oneSide单侧路由
manhattan曼哈顿路由
metro地铁线路风格
erER 图专用路由
graph.addEdge({
  source: 'node1', target: 'node2',
  router: { name: 'orth', args: { padding: 20 } },
})

6.2 连接器(Connector)

连接器说明
normal直线连接(默认)
rounded圆角连接
smooth平滑曲线
jumpover交叉跳线

6.3 箭头(Marker)

箭头说明
block实心三角
classic经典箭头
diamond菱形
cross十字
circle圆形

6.4 连接规则

const graph = new Graph({
  connecting: {
    snap: true,
    allowBlank: false,
    allowLoop: false,
    allowMulti: false,
    allowNode: false,
    allowPort: true,
    router: { name: 'manhattan' },
    connector: { name: 'rounded', args: { radius: 8 } },
    validateConnection({ sourceCell, targetCell }) {
      return sourceCell !== targetCell
    },
  },
})

7. 连接桩(Port)

7.1 Port 分组

ports: {
  groups: {
    in: {
      position: 'left',
      attrs: { circle: { r: 5, magnet: true, stroke: '#31d0c6', fill: '#fff', strokeWidth: 2 } },
    },
    out: {
      position: 'right',
      attrs: { circle: { r: 5, magnet: true, stroke: '#5F95FF', fill: '#fff', strokeWidth: 2 } },
    },
  },
  items: [
    { group: 'in', id: 'in-1' },
    { group: 'out', id: 'out-1' },
  ],
}

7.2 连接桩交互

node.addPort({ group: 'out', id: 'out-3' })    // 添加
node.removePort('port-id')                      // 删除
node.getPorts()                                 // 获取所有
node.getPort('port-id')                         // 获取指定
node.setPortProp('port-id', 'attrs/circle/fill', '#ff0000')

graph.on('port:click', ({ node, port }) => {
  console.log('点击连接桩:', port.id)
})

8. 事件系统

8.1 鼠标事件

事件NodeEdgeGraph(空白)
单击node:clickedge:clickblank:click
双击node:dblclickedge:dblclickblank:dblclick
右键node:contextmenuedge:contextmenublank:contextmenu
进入node:mouseenteredge:mouseentergraph:mouseenter
离开node:mouseleaveedge:mouseleavegraph:mouseleave
graph.on('node:click', ({ e, x, y, node }) => {
  console.log('点击节点:', node.id)
})

graph.on('blank:click', ({ e, x, y }) => {
  console.log('点击空白区域:', x, y)
})

graph.on('node:mouseenter', ({ node }) => { node.attr('body/stroke', '#1890ff') })
graph.on('node:mouseleave', ({ node }) => { node.attr('body/stroke', '#333') })

8.2 数据变更事件

graph.on('node:change:position', ({ node, current, previous }) => {
  console.log(`${node.id} 位置变更:`, previous, '->', current)
})

8.3 画布事件

事件说明
scale画布缩放
resize画布尺寸变化
translate画布平移
blank:click点击空白区域
blank:mousedown空白区域鼠标按下
blank:mouseup空白区域鼠标释放

9. 自定义形状

9.1 注册自定义节点

Graph.registerNode('custom-rect', {
  inherit: 'rect',
  width: 160,
  height: 80,
  markup: [
    { tagName: 'rect', selector: 'body' },
    { tagName: 'text', selector: 'label' },
  ],
  attrs: {
    body: { fill: '#f5f5f5', stroke: '#333', strokeWidth: 1 },
    label: { fill: '#333', fontSize: 14, textAnchor: 'middle', textVerticalAnchor: 'middle' },
  },
}, true)

9.2 自定义边

Graph.registerEdge('custom-edge', {
  inherit: 'edge',
  attrs: {
    line: { stroke: '#5F95FF', strokeWidth: 2 }
  },
  router: { name: 'manhattan' },
  connector: { name: 'rounded', args: { radius: 10 } },
}, true)

10. HTML 节点

10.1 基本用法

Graph.registerNode('html-node', {
  inherit: 'rect',
  width: 120,
  height: 60,
  html: (cell) => {
    const div = document.createElement('div')
    div.style.cssText = 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;'
    div.textContent = cell.getData().label
    return div
  },
}, true)

graph.addNode({
  shape: 'html-node',
  x: 100, y: 100,
  data: { label: 'HTML 节点' },
})

11. 框架集成

11.1 React 集成

npm install @antv/x6-react-shape --save
import { ReactShape } from '@antv/x6-react-shape'

Graph.registerNode('react-shape', ReactShape, true)

const CustomNode = ({ node }) => {
  const { data } = node
  return (
    <div style={{ padding: 20, border: '1px solid #333', borderRadius: 8 }}>
      <div>{data.title}</div>
      <div style={{ color: '#999' }}>{data.desc}</div>
    </div>
  )
}

graph.addNode({
  shape: 'react-shape',
  x: 100, y: 100,
  data: { title: '标题', desc: '描述' },
  component: <CustomNode />,
})

11.2 Vue 集成

npm install @antv/x6-vue-shape --save

12. 插件系统

12.1 框选插件

import { Selection } from '@antv/x6'

graph.use(new Selection({
  enabled: true,
  multiple: true,
  showNodeSelectionBox: true,
  showEdgeSelectionBox: true,
  rubberEdge: true,
  rubberNode: true,
}))

12.2 对齐线插件

import { Snapline } from '@antv/x6'

graph.use(new Snapline({
  enabled: true,
  resizing: true,
  connecting: true,
}))

12.3 历史记录插件

import { History } from '@antv/x6'

graph.use(new History({
  enabled: true,
}))

// 操作
graph.undo()
graph.redo()
graph.canUndo()
graph.canRedo()

12.4 小地图插件

import { Minimap } from '@antv/x6'

graph.use(new Minimap({
  enabled: true,
  container: document.getElementById('minimap'),
  width: 200,
  height: 150,
}))

12.5 键盘快捷键插件

import { Keyboard } from '@antv/x6'

graph.use(new Keyboard({
  enabled: true,
}))

// 绑定快捷键
graph.bindKey('ctrl+c', () => graph.getSelectedCells())
graph.bindKey('ctrl+v', () => graph.pasteCells())
graph.bindKey('ctrl+z', () => graph.undo())
graph.bindKey('delete', () => graph.removeCells(graph.getSelectedCells()))

13. 高级特性

13.1 虚拟渲染

const graph = new Graph({
  container: document.getElementById('container'),
  virtual: true,
  async: true,
})

13.2 动画系统

node.animate(
  [
    { attrs: { body: { fill: '#ff0000' } }, { duration: 200 },
    { attrs: { body: { fill: '#00ff00' } }, { duration: 200 },
  ],
  { delay: 0, repeat: Infinity }
)

13.3 导出功能

graph.toPNG()
graph.toSVG()
graph.toDataURL()
graph.toBase64()

14. 实战案例

14.1 流程图编辑器

const graph = new Graph({
  container: document.getElementById('container'),
  width: 1000,
  height: 600,
  grid: true,
  panning: true,
  mousewheel: true,
  connecting: {
    snap: true,
    router: { name: 'manhattan' },
    connector: { name: 'rounded', args: { radius: 8 } },
  },
  selecting: {
    enabled: true,
    multiple: true,
  },
})

// 添加开始节点
graph.addNode({
  shape: 'rect',
  x: 400, y: 50,
  width: 100, height: 40,
  label: '开始',
  style: { fill: '#e6f7ff', stroke: '#5F95FF' },
})

// 添加结束节点
graph.addNode({
  shape: 'rect',
  x: 400, y: 300,
  width: 100, height: 40,
  label: '结束',
  style: { fill: '#f6ffed', stroke: '#52c41a' },
})

14.2 DAG 任务编排

const tasks = [
  { id: 'task1', name: '数据采集', deps: [] },
  { id: 'task2', name: '数据清洗', deps: ['task1'] },
  { id: 'task3', name: '特征工程', deps: ['task2'] },
  { id: 'task4', name: '模型训练', deps: ['task3'] },
  { id: 'task5', name: '模型评估', deps: ['task4'] },
]

tasks.forEach(task => {
  const x = (task.deps.length + 1) * 150
  const y = tasks.indexOf(task) * 100

  graph.addNode({
    id: task.id,
    shape: 'rect',
    x, y,
    width: 120, height: 60,
    label: task.name,
  })

  task.deps.forEach(depId => {
    graph.addEdge({
      source: depId,
      target: task.id,
      router: { name: 'manhattan' },
      connector: { name: 'rounded', args: { radius: 8 } },
    })
  })
})

15. 版本升级指南

15.1 v2 到 v3 主要变化

变化说明
插件合并到主包x6-plugin-* 包合并到 @antv/x6 主包
画布拖拽默认启用panning: true 成为默认行为
虚拟渲染新增 virtual 选项支持大图优化
动画系统新增基于 Web Animations API 的动画能力
API 调整部分 API 微调,详见官方迁移指南

15.2 迁移建议

// v2
import { Graph } from '@antv/x6'
import { Snapline } from '@antv/x6-plugin-snapline'

// v3
import { Graph, Snapline } from '@antv/x6'

const graph = new Graph({...})
graph.use(new Snapline())

16. 最佳实践

16.1 性能优化

  • 对大数据量场景启用虚拟渲染(virtual: true
  • 使用 async: true 启用异步渲染
  • 避免频繁调用 graph.render(),使用批量操作
  • 合理使用 node.setData() 而非直接修改属性

16.2 交互体验

  • 启用对齐线提升连线体验
  • 配置合适的缩放范围(scaling: { min: 0.1, max: 4 }
  • 使用 rubberband 提供框选功能
  • 添加键盘快捷键提升操作效率

16.3 数据管理

  • 使用 data 属性存储业务数据,与视图分离
  • 利用事件系统监听数据变化,保持状态同步
  • 导出/导入时使用 graph.toJSON() / graph.fromJSON()

17. 参考资源

本文档基于 AntV X6 v3.1.7 编写,如有疑问请参考官方文档。

评论