以下是对这段 AntV X6 代码的详细分步解释,包含逐段代码的功能说明和关键逻辑注释:
一、引入依赖与初始化准备
javascript
import { Graph, Shape, Addon } from '@antv/x6' // 引入核心绘图组件
import insertCss from 'insert-css' // 用于注入样式
// 辅助函数:创建DOM结构并注入样式
function preWork() {
const container = document.createElement('div') // 创建根容器
container.id = 'container'
document.body.appendChild(container) // 插入到页面主体
// 创建左侧工具栏容器
const stencilContainer = document.createElement('div')
stencilContainer.id = 'stencil'
// 创建右侧画布容器
const graphContainer = document.createElement('div')
graphContainer.id = 'graph-container'
// 组装布局
container.appendChild(stencilContainer)
container.appendChild(graphContainer)
// 注入全局样式
insertCss(`
#container { display: flex; border: 1px solid #dfe3e8; }
#stencil { width: 180px; border-right: 1px solid #dfe3e8; }
#graph-container { width: calc(100% - 180px); }
/* 省略部分样式(主要用于调整工具栏和画布视觉效果) */
`)
}
preWork() // 执行初始化准备
关键点:
创建左右布局:左侧为工具栏(Stencil),右侧为绘图区域
通过 insertCss 注入基础样式,实现容器布局和组件视觉定制
二、画布初始化(核心配置)
javascript
const graph = new Graph({
container: document.getElementById('graph-container')!, // 绑定画布DOM
grid: true, // 显示网格线
mousewheel: { // 鼠标滚轮配置
enabled: true, // 启用滚轮
zoomAtMousePosition: true, // 以鼠标位置为中心缩放
modifiers: 'ctrl', // 需要按住Ctrl键触发
minScale: 0.5, maxScale: 3, // 缩放范围
},
connecting: { // 连线配置
router: { name: 'manhattan', args: { padding: 1 } }, // 曼哈顿路由(直角折线)
connector: { name: 'rounded', args: { radius: 8 } }, // 圆角连线
anchor: 'center', // 锚点位置
createEdge() { // 自定义连线样式
return new Shape.Edge({
attrs: {
line: {
stroke: '#A2B1C3', // 线条颜色
strokeWidth: 2, // 线条粗细
targetMarker: { name: 'block', width: 12, height: 8 }, // 终点箭头
},
},
zIndex: 0, // 层级
})
},
validateConnection: ({ targetMagnet }) => !!targetMagnet, // 必须连接到磁性端点
},
highlighting: { // 高亮效果
magnetAdsorbed: { // 吸附到锚点时的高亮
name: 'stroke',
args: { attrs: { fill: '#5F95FF', stroke: '#5F95FF' } },
},
},
// 其他功能启用
resizing: true, // 节点缩放
rotating: true, // 节点旋转
selecting: { enabled: true, rubberband: true }, // 框选功能
snapline: true, // 吸附线
keyboard: true, // 键盘快捷键
clipboard: true, // 剪贴板功能
})
核心功能:
交互配置:支持缩放、平移、框选、键盘操作
连线逻辑:使用曼哈顿路由实现直角折线,圆角连线 + 终点箭头
节点交互:鼠标悬停时锚点高亮,必须连接到有效锚点
三、工具栏(Stencil)初始化
javascript
const stencil = new Addon.Stencil({
title: '流程图', // 工具栏标题
target: graph, // 关联画布
stencilGraphWidth: 200, // 工具栏宽度
stencilGraphHeight: 180, // 初始高度
collapsable: true, // 可折叠
groups: [ // 分组配置
{ title: '基础流程图', name: 'group1' }, // 基础图形组
{
title: '系统设计图',
name: 'group2',
graphHeight: 250, // 组内高度
layoutOptions: { rowHeight: 70 } // 垂直间距
},
],
layoutOptions: { // 全局布局配置
columns: 2, // 每行2列
columnWidth: 80, // 列宽
rowHeight: 55, // 行高
},
})
document.getElementById('stencil')!.appendChild(stencil.container) // 插入DOM
作用:
创建左侧工具栏,分为两个分组:基础流程图和系统设计图
定义分组布局:基础组每行 2 列,系统组垂直间距更大
支持工具栏折叠,节省空间
四、快捷键与事件绑定
javascript
// 复制/剪切/粘贴
graph.bindKey(['meta+c', 'ctrl+c'], () => graph.copy(graph.getSelectedCells()))
graph.bindKey(['meta+x', 'ctrl+x'], () => graph.cut(graph.getSelectedCells()))
graph.bindKey(['meta+v', 'ctrl+v'], () => { // 粘贴时偏移32px避免重叠
if (!graph.isClipboardEmpty()) {
const cells = graph.paste({ offset: 32 })
graph.select(cells)
}
})
// 撤销/重做
graph.bindKey(['meta+z', 'ctrl+z'], () => graph.history.undo())
graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => graph.history.redo())
// 全选/删除
graph.bindKey(['meta+a', 'ctrl+a'], () => graph.select(graph.getNodes()))
graph.bindKey('backspace', () => graph.removeCells(graph.getSelectedCells()))
// 缩放控制(±0.1倍)
graph.bindKey(['ctrl+1', 'meta+1'], () => graph.zoom(0.1))
graph.bindKey(['ctrl+2', 'meta+2'], () => graph.zoom(-0.1))
// 锚点显示控制:鼠标进入节点时显示锚点,离开时隐藏
graph.on('node:mouseenter', () => {
const ports = document.querySelectorAll('.x6-port-body') as NodeListOf<SVGElement>
ports.forEach(port => port.style.visibility = 'visible')
})
graph.on('node:mouseleave', () => {
const ports = document.querySelectorAll('.x6-port-body') as NodeListOf<SVGElement>
ports.forEach(port => port.style.visibility = 'hidden')
})
关键逻辑:
实现完整的快捷键系统:支持复制 / 粘贴 / 撤销 / 全选等标准操作
锚点优化:默认隐藏锚点,鼠标悬停时显示,避免界面杂乱
粘贴时添加偏移量(offset: 32),防止复制的节点重叠
五、自定义节点注册
1. 通用锚点配置
javascript
const ports = { // 定义节点四周的锚点
groups: {
top: { position: 'top', /* 顶部锚点样式 */ },
right: { position: 'right' },
bottom: { position: 'bottom' },
left: { position: 'left' },
},
items: [{ group: 'top' }, { group: 'right' }, { group: 'bottom' }, { group: 'left' }],
}
作用:
为节点定义四个方向的锚点(圆形,半径 4px,默认隐藏)
magnet: true 表示锚点可吸附连线
2. 注册矩形节点
javascript
Graph.registerNode('custom-rect', {
inherit: 'rect', // 继承基础矩形节点
width: 66, height: 36, // 尺寸
attrs: { // 图形属性
body: { stroke: '#5F95FF', fill: '#EFF4FF', rx: 20 }, // 带圆角的矩形
text: { fontSize: 12, fill: '#262626' }, // 文本样式
},
ports: { ...ports }, // 应用通用锚点配置
}, true)
变体:
r1:圆角矩形(rx:20, ry:26),用于表示 “开始” 节点
r2:标准矩形(默认圆角)
r3:小圆角矩形(rx:6, ry:6),表示 “可选过程”
3. 注册多边形节点
javascript
Graph.registerNode('custom-polygon', {
inherit: 'polygon', // 继承多边形节点
width: 66, height: 36,
attrs: {
body: {
refPoints: '0,10 10,0 20,10 10,20', // 菱形坐标(决策节点)
// 另一个多边形:梯形坐标(数据节点)
// refPoints: '10,0 40,0 30,20 0,20'
},
},
ports: { ...ports, items: [{ group: 'top' }, { group: 'bottom' }] }, // 仅上下锚点
}, true)
特点:
通过 refPoints 定义多边形形状(菱形 / 梯形)
决策节点仅保留上下锚点(符合流程图逻辑)
4. 注册圆形节点
javascript
Graph.registerNode('custom-circle', {
inherit: 'circle', // 继承圆形节点
width: 45, height: 45, // 直径
attrs: { body: { fill: '#EFF4FF' } }, // 空心圆
ports: { ...ports }, // 四周锚点
}, true)
用途:连接节点(流程图中的连接符号)
5. 注册图片节点
javascript
Graph.registerNode('custom-image', {
inherit: 'rect', // 基于矩形容器
width: 52, height: 52,
markup: [ // 自定义渲染结构
{ tagName: 'rect', selector: 'body' }, // 背景矩形
{ tagName: 'image' }, // 图标
{ tagName: 'text', selector: 'label' }, // 文本
],
attrs: {
body: { fill: '#5F95FF' }, // 蓝色背景
image: {
width: 26, height: 26,
refX: 13, refY: 16 // 图标居中
},
label: {
refX: 3, refY: 2, // 文本位置
fill: '#fff' // 白色文字
},
},
ports: { ...ports }, // 四周锚点
}, true)
功能:
支持图标 + 文本组合节点(用于系统设计图)
通过 markup 自定义渲染结构,插入 <image> 标签
六、向工具栏添加节点
javascript
// 基础流程图组(group1)
const r1 = graph.createNode({ shape: 'custom-rect', label: '开始', attrs: { body: { rx:20, ry:26 } } })
const r4 = graph.createNode({ shape: 'custom-polygon', label: '决策', attrs: { body: { refPoints: '菱形坐标' } } })
stencil.load([r1, r2, r3, r4, r5, r6], 'group1') // 加载到基础组
// 系统设计图组(group2)
const imageNodes = imageShapes.map(item =>
graph.createNode({
shape: 'custom-image',
label: item.label,
attrs: { image: { 'xlink:href': item.image } }
})
)
stencil.load(imageNodes, 'group2') // 加载到系统组
流程:
创建各类型节点实例(指定标签、样式)
通过 stencil.load() 将节点添加到对应分组
系统设计图组使用图标节点,通过 xlink:href 加载远程 SVG 图标
根据以上内容,总结Ant v X6的使用
最新发布