AntV X6 图编辑
可视化官方

AntV X6 图编辑

X6 图编辑引擎代码生成技能,支持流程图、DAG、ER图、血缘图等图编辑场景的节点/边/端口/交互/插件配置

yvonneyx
yvonneyx
浏览230
使用43

Skill 文件

Skill
references
SKILL.md
SKILL.md
name
antv-x6-editor
title
AntV X6 图编辑
description
X6 图编辑引擎代码生成技能,支持流程图、DAG、ER图、血缘图等图编辑场景的节点/边/端口/交互/插件配置
version
3.x

X6 图编辑引擎代码生成技能

核心约束(必须遵守)

<​!-- CONSTRAINTS:START --​>

X6 3.x 关键约束(强制)

  • graph.render() 不存在:X6 3.x 中 new Graph() / addNode / addEdge / fromJSON 均自动渲染,代码中不得出现 graph.render()
  • 不得声明 container 变量:运行环境会作为函数参数注入 container。Graph 初始化只使用字符串字面量 container: 'container',禁止 const/let/var container = ...,也禁止 document.getElementById('container')
  • 使用插件方法前必须先 graph.use(new Plugin(...)) 注册对应插件graph.toPNG / toSVG / toJPEG 依赖 Exportgraph.select / unselect 依赖 Selectiongraph.undo / redo 依赖 Historygraph.copy / paste / cut 依赖 Clipboardgraph.bindKey 依赖 Keyboard。未注册插件时对应方法不存在。
  • 自定义 shape 必须先注册再使用Graph.registerNode(name, def) / Graph.registerEdge(name, def) / Shape.HTML.register({ shape, ... }) 必须在首次 addNode / addEdge 之前完成。
  • @antv/x6 仅导出 11 个插件类ClipboardDndExportHistoryKeyboardMiniMapScrollerSelectionSnaplineStencilTransformmousewheelembeddingpanningconnectingtranslatinginteractingbackgroundgridnew Graph()构造选项,不是插件,不得 import 同名类、不得 graph.use(new XxxClass())。例:滚轮缩放写在 Graph 构造中 mousewheel: { enabled: true, zoomAtMousePosition: true, modifiers: ['ctrl'] }
  • 节点/边动画使用 cell.animate(keyframes, options)(Web Animations API 风格):X6 3.x 没有 node.transition(path, target, options) 方法。源码中 transition 仅作为 node.translate(tx, ty, { transition }) / node.rotate(deg, { transition })options 字段存在(boolean | KeyframeEffectOptions),并非独立方法。示例:
    javascript
    // 通用动画node.animate(  { fill: ['#fff', '#1890ff'], transform: ['scale(1)', 'scale(1.2)'] },  { duration: 500, iterations: 1, fill: 'forwards' },);// 仅平移过渡node.translate(120, 0, { transition: { duration: 500, easing: 'ease-in-out' } });
    多步属性变更可用 graph.startBatch('animate'); cell.attr(...); graph.stopBatch('animate'); 包装。

初始化规范

  • container 参数必填,必须使用字符串形式 container: 'container',运行时环境会自动解析为 DOM 元素
  • 必须设置背景色background: { color: '#F2F7FA' },所有画布都需要统一的浅蓝灰色背景
  • 不要添加 grid 配置,除非用户明确要求显示网格
  • 不要设置 width / height,除非用户明确指定画布尺寸;画布默认自适应容器大小
  • 导入方式:import { Graph } from '@antv/x6'仅导入实际使用到的类
  • 禁止无条件导入 Shape:仅在使用 Shape.HTML.register() 等 Shape 静态方法时才导入 Shape
  • 插件从 '@antv/x6' 直接导入,如 import { Graph, Selection, History } from '@antv/x6'
  • 禁止使用 @antv/x6-plugin-xxx 独立包导入(已废弃)
  • 标准初始化模板:
    javascript
    import { Graph } from '@antv/x6';const graph = new Graph({  container: 'container',  background: { color: '#F2F7FA' },});

节点操作规范

  • 优先使用 graph.addNode() 逐个添加节点,而非 graph.fromJSON() 批量导入(除非用户明确要求批量加载数据)
  • 内置 shape:'rect''circle''ellipse''polygon''polyline''path''text''text-block''image''html'
  • 节点样式通过 attrs 配置,遵循 SVG 属性命名
  • 节点位置通过 xy 设置(左上角坐标),尺寸通过 widthheight 设置
  • 默认节点样式(除非用户指定其他样式,所有节点统一使用此默认样式):
    javascript
    attrs: {  body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },}
  • 禁止在 attrs 中使用 CSS 属性名(如 background-color),必须用 SVG 属性(如 fill

边操作规范

  • 使用 graph.addEdge({ source, target, ... }) 添加边
  • source/target 可以是:节点实例、节点 ID 字符串、{ cell: node, port: 'portId' } 对象、坐标 { x, y }
  • 边样式:attrs: { line: { stroke, strokeWidth, strokeDasharray, targetMarker, sourceMarker } }
  • 默认边样式(除非用户指定其他样式):attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } }
  • 箭头:targetMarker: 'classic'(经典箭头)、'block''circle''diamond'
  • 路由器:router: 'orth'(正交)、'manhattan''metro''er'
  • 连接器:connector: 'rounded'(圆角)、'smooth'(贝塞尔曲线)、'jumpover'

连接桩(Ports)规范

  • 连接桩定义在节点配置的 ports 字段中
  • 端口组:ports: { groups: { groupName: { position, attrs, ... } }, items: [{ id, group }] }
  • position 取值:'top''bottom''left''right'
  • 端口是连线的锚点,设置 attrs: { circle: { magnet: true } } 允许从端口拖出连线
  • 必须设置 magnet: true 才能从该端口发起或接收连线

交互配置规范

  • 连线交互在 Graph 配置中通过 connecting 字段设置
  • connecting: { allowBlank: false, router: 'orth', connector: 'rounded', createEdge() {...} }
  • 节点移动限制:translating: { restrict: true } 或传函数限制区域
  • 嵌入:embedding: { enabled: true } 允许节点拖入分组

插件使用规范

  • 插件从 @antv/x6 导入,通过 graph.use(new Plugin(options)) 注册
  • 可用插件:SelectionSnaplineHistoryClipboardKeyboardScrollerMiniMapTransformExportStencilDnd
  • Selection: graph.use(new Selection({ enabled: true, rubberband: true }))
  • Snapline: graph.use(new Snapline({ enabled: true }))
  • History: graph.use(new History({ enabled: true }))
  • Clipboard: graph.use(new Clipboard({ enabled: true }))
  • Keyboard: graph.use(new Keyboard({ enabled: true }))
  • Scroller: graph.use(new Scroller({ enabled: true }))
  • MiniMap: graph.use(new MiniMap({ enabled: true, container: minimapContainer }))
  • Transform: graph.use(new Transform({ resizing: { enabled: true }, rotating: { enabled: true } }))
  • Export: graph.use(new Export())(注册后可调用 graph.toPNG() / graph.toSVG()
  • 动态控制:graph.enablePlugins('selection') / graph.disablePlugins('selection')
  • 禁止在 Graph 构造函数中直接传入 selectingsnapline 等选项(3.x 不支持)

序列化规范

  • 导出:const data = graph.toJSON() 返回 { cells: [...] } 对象
  • 导入:graph.fromJSON(data) 加载整个图数据
  • 清空:graph.clearCells() 清除所有元素
  • 禁止手动构造 cells 数组中的内部字段(如 zIndexparent),应通过 API 操作

事件规范

  • 节点事件:graph.on('node:click', ({ node, e }) =​> {...})
  • 边事件:graph.on('edge:click', ({ edge, e }) =​> {...})
  • 画布事件:graph.on('blank:click', ({ e }) =​> {...})
  • 变更事件:graph.on('node:moved', ({ node }) =​> {...})
  • 事件回调参数是对象,不是位置参数:({ node, e }) 而非 (node, e)

导入规范

  • 所有使用到的类都必须出现在 import 语句中:如使用 Selection,必须 import { Graph, Selection } from '@antv/x6'
  • 禁止使用 Graph.SelectionGraph.Keyboard 等命名空间写法(不存在)
  • 禁止使用未导入的类:new Selection(...) 必须对应 import { Selection } from '@antv/x6'
  • import 自检清单(强制,输出代码前必须逐行核对):对代码中每一个 new XxxYyy(...) 调用,XxxYyy 必须字面出现在第一行 import { ..., XxxYyy } from '@antv/x6' 的花括号内。常见漏写:SelectionKeyboardHistoryClipboardSnaplineMiniMapTransformScrollerExportStencilDndShape(用到 Shape.HTML.register 时)。
  • import 漏写为何会变成 Illegal constructor 等运行时错:评测/Playground 环境用 UMD 构建window.X6)执行代码,而不是真正的 ES Module。SelectionKeyboard 等会根据 import 列表window.X6 解构出来;如果 import 漏写,标识符 Selection回退到 window.Selection(浏览器原生 Selection 接口),new Selection({...}) 会抛 Failed to construct 'Selection': Illegal constructorKeyboard / History 等同理(会 is not a constructor)。
  • import 漏写的标准修法:把所有用到的插件类合并到同一行 import { Graph, Selection, Keyboard, History, ... } from '@antv/x6';,不要分多行 import,也不要遗漏。

节点工具(Tools)规范

  • 添加工具:node.addTools([{ name: 'button-remove', args: { x: 0, y: 0 } }])graph.addTools(node, [...])
  • 移除工具:node.removeTools()graph.removeTools(node)
  • 检查工具:node.hasTools()
  • 禁止使用 node.hideTools() / node.showTools()(3.x 不存在此 API)
  • 悬停显示/隐藏工具的正确方式:
    javascript
    graph.on('node:mouseenter', ({ node }) =​> {  node.addTools([{ name: 'button-remove', args: { x: 0, y: 0 } }]);});graph.on('node:mouseleave', ({ node }) =​> {  node.removeTools();});

渐变色规范

  • X6 attrs 中 fill 支持渐变对象语法,禁止直接操作 graph.defsdocument.createElementNS 创建 SVG 渐变
  • 线性渐变正确写法:
    javascript
    attrs: {  body: {    fill: {      type: 'linearGradient',      stops: [        { offset: '0%', color: '#0000ff' },        { offset: '100%', color: '#00ff00' },      ],    },  },}

代码输出规范

  • 必须输出纯 JavaScript,禁止使用 TypeScript 语法(如 private、类型注解 : stringas 类型断言)
  • HTML 自定义节点使用 Shape.HTML.register({ shape, html, effect }) 注册自定义 shape,禁止使用 class extends Node 方式
  • 禁止 Graph.registerHTMLComponent(name, factory) —— 这是 X6 2.x 旧 API,3.x 源码已无此方法。所有 HTML 节点统一通过 Shape.HTML.register 注册(详见 references/core/x6-core-html-shape.md
  • effect 数组指定哪些属性变化时触发重新渲染(如 ['data']);纯静态展示节点不要加 effect
  • HTML 节点正确写法:
    javascript
    import { Graph, Shape } from '@antv/x6';Shape.HTML.register({  shape: 'my-html',  effect: ['data'],  html(node) {    const div = document.createElement('div');    div.style.width = '100%';    div.style.height = '100%';    div.innerHTML = node.getData().content || '';    return div;  },});const graph = new Graph({ container: 'container' });graph.addNode({ shape: 'my-html', x: 100, y: 100, width: 200, height: 80, data: { content: '<​div​>Hello<​/div​>' } });

Stencil 插件规范

  • Stencil 通过 graph.use(new Stencil({ target: graph, groups: [...] })) 注册
  • 注册后通过 graph.getPlugin('stencil') 获取实例,将 stencil.container 挂载到 DOM
  • Stencil 内的节点模板使用 graph.createNode(...) 创建(非 graph.addNode),再通过 stencil.load(nodes, groupName) 加载

动态端口规范

  • 使用 node.addPort() 动态添加端口时,必须在节点初始化时预定义对应的 ports.groups
  • 如果没有预定义 group,端口无法正确定位,可能导致渲染异常
  • 正确写法:
    javascript
    const node = graph.addNode({  ...,  ports: {    groups: {      in: { position: 'left', attrs: { circle: { r: 4, magnet: true, stroke: '#8f8f8f', fill: '#fff' } } },      out: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#8f8f8f', fill: '#fff' } } },    },  },});node.addPort({ id: 'port1', group: 'out' });
  • registerNode + addNode 的 ports 合并陷阱(强约束)Graph.registerNode(name, { ports: { items: [{ id: 'in1', group: 'in' }] } }) 之后,如果再 graph.addNode({ shape: name, ports: { items: [{ id: 'in1', group: 'in' }] } }),X6 内部 Cell 构造时 ObjectExt.merge(defaults, metadata) 会按数组下标合并、node.addPorts 走的也是 [...current, ...new] 简单拼接,不会去重,运行时直接抛 Error: Duplicitied port id.。正确做法二选一:
    • registerNode 里只声明 ports.groups,把 ports.items 留给 addNode / 后续 node.addPort 提供;
    • 或在 registerNode 里完整声明 ports.itemsaddNode不再传 ports.items(如需追加端口,调用 node.addPort({ id: '新id', group: 'xxx' }),且新 id 不能与 registry 里已声明的重名)。

DOM/CSS 操作规范(HTML 节点 / Stencil / 自定义工具)

  • HTML 节点 html(node) 回调里给 DOM 设样式时,禁止直接写连字符属性:el.style.box-sizing = '...'el.style.font-size = '...' 会被 JS 解析为 el.style.box - sizing = ...,抛 Invalid left-hand side in assignment。正确写法二选一:
    • 驼峰:el.style.boxSizing = 'border-box'el.style.fontSize = '14px'el.style.backgroundColor = '#fff'
    • 方括号:el.style['box-sizing'] = 'border-box'el.style['font-size'] = '14px'
    • 多条样式优先用 el.style.cssText = 'box-sizing:border-box;font-size:14px;'Object.assign(el.style, { boxSizing: 'border-box', fontSize: '14px' })
  • 同理,el.classList.add('...') / el.setAttribute('data-x', '...') 是合法 API;禁止 el.class = '...' / el['class-name'] = ...

不存在的 API(禁止使用)

  • 禁止 graph.scrollToCell() → 正确方式:graph.centerCell(cell) 滚动并居中到指定 cell
  • 禁止 graph.highlightCell() / graph.highlightNode() → 正确方式:通过 node.attr('body/stroke', '#f00') 或添加 CSS class 实现高亮
  • 禁止 Shape.Cylinder / Shape.Diamond 等不存在的内置 Shape → 用 'rect' + rx/ry'polygon' 自定义
  • 禁止 Shape.Edge.define() / Shape.Node.define() → 正确方式:Graph.registerEdge() / Graph.registerNode()
  • 禁止 Shape.Group / Shape.Group.define() / new Shape.Group() → X6 3.x 的 Shape 命名空间没有 Group 导出(实际只有 Circle / Edge / Ellipse / HTML / Image / Path / Polygon / Polyline / Rect / TextBlock,运行时会报 Cannot read properties of undefined (reading 'define'))。父子分组的正确方式:直接 graph.addNode({ shape: 'rect', ... }) 创建一个普通节点作为父节点,再通过 parent.addChild(child) / parent.embed(child) 建立父子关系;或用 Graph.registerNode('my-group', { inherit: 'rect', markup: [...], attrs: {...} }) 注册一个自定义分组形状再 addNode({ shape: 'my-group' })
  • 禁止Embedding 当插件 import / new / graph.use(new Embedding(...)) → X6 3.x 没有 Embedding 插件类(运行时会报 Embedding is not a constructor)。节点嵌入是 Graph 构造选项new Graph({ container, embedding: { enabled: true, findParent: 'bbox', frontOnly: false, validate: ({ child, parent }) =​> true } })。Hover 高亮通过 highlighting.embedding 配置,嵌入/解除嵌入事件为 node:embedding / node:embedded
  • 禁止 history.batch() → 正确方式:graph.startBatch('custom'); ...; graph.stopBatch('custom');graph.batchUpdate(() =​> { ... })
  • 禁止 graph.defs / graph.svgDoc / document.createElementNS('...', 'linearGradient' | 'defs' | 'marker') → X6 3.x 不暴露 graph.defs / graph.svgDoc,运行时会报 Cannot read properties of undefined。正确方式:
    • 节点/边普通 fill 渐变:直接用 attrs 中的渐变对象语法(fill: { type: 'linearGradient', stops: [...] }
    • 自定义 marker 需要渐变填充:先 const id = graph.defineGradient({ type: 'linearGradient', stops: [{ offset: 0, color: '#f00' }, { offset: 1, color: '#0f0' }] }),再在 marker 对象里写 fill: \url(#${id})``
    • 自定义 marker / filter 同理使用 graph.defineMarker(options) / graph.defineFilter(options)

渲染输出规范(必须遵守)

  • 画布初始化后必须存在至少一个 graph.addNode / graph.addEdge / graph.fromJSON 调用,确保画布有可视内容。即使用户 query 只描述了交互(panning / mousewheel / 插件等)配置,也必须自行补 2~3 个示例节点 + 1 条边作为渲染载体,否则视觉验证会被判定为「白屏」。
  • 所有节点/边添加完成后,必须在末尾调用 graph.centerContent()(或在画布需要随内容缩放时使用 graph.zoomToFit({ padding: 20, maxScale: 1 }))。X6 默认不会自动居中,缺失该调用会导致内容偏向左上角、视觉评分不通过。两者二选一,不可同时调用。
  • 多个交互(panning + mousewheel + Selection rubberband)同时启用时,必须用 modifiers 错开触发条件(例如:panning 用 'shift',mousewheel 用 'ctrl',rubberband 留空)。禁止'mouseWheel' 放进 panning.eventTypes 同时又启用 mousewheel,两者会争抢滚轮事件。

<​!-- CONSTRAINTS:END --​>


禁止的错误模式

❌ 使用已废弃的独立插件包

javascript
// 错误:独立插件包已废弃import { Selection } from '@antv/x6-plugin-selection';import { History } from '@antv/x6-plugin-history';
// 正确:从 @antv/x6 直接导入import { Graph, Selection, History } from '@antv/x6';const graph = new Graph({ container: 'container' });graph.use(new Selection({ enabled: true, rubberband: true }));graph.use(new History({ enabled: true }));

❌ 在构造函数中传入插件选项

javascript
// 错误:3.x 不支持构造函数选项模式const graph = new Graph({  container: 'container',  selecting: { enabled: true },  // ❌  snapline: { enabled: true },   // ❌  history: { enabled: true },    // ❌});
// 正确:使用 graph.use() 注册插件import { Graph, Selection, Snapline, History } from '@antv/x6';const graph = new Graph({ container: 'container' });graph.use(new Selection({ enabled: true }));graph.use(new Snapline({ enabled: true }));graph.use(new History({ enabled: true }));

❌ 混淆 CSS 属性和 SVG 属性

javascript
// 错误:使用 CSS 属性名attrs: {  body: {    'background-color': '#fff',  // ❌    'border-radius': '6px',      // ❌  }}
// 正确:使用 SVG 属性名attrs: {  body: {    fill: '#fff',               // ✅ 背景色    rx: 6,                      // ✅ 圆角    ry: 6,    stroke: '#8f8f8f',          // ✅ 边框色    strokeWidth: 1,             // ✅ 边框宽度  }}

❌ 缺少 container

javascript
// 错误:遗漏 containerconst graph = new Graph({});
// 正确:container 必填const graph = new Graph({ container: 'container' });

❌ 连接桩未设置 magnet

javascript
// 错误:端口无法连线ports: {  items: [{ id: 'port1', group: 'out' }],  groups: {    out: { position: 'right', attrs: { circle: { r: 5 } } }  }}
// 正确:设置 magnet: trueports: {  items: [{ id: 'port1', group: 'out' }],  groups: {    out: { position: 'right', attrs: { circle: { r: 5, magnet: true, stroke: '#8f8f8f' } } }  }}

❌ 事件回调使用位置参数

javascript
// 错误:参数不是位置传递graph.on('node:click', (node, e) =​> { ... });
// 正确:解构对象参数graph.on('node:click', ({ node, e }) =​> { ... });

基础结构模板

javascript
import { Graph } from '@antv/x6';
const graph = new Graph({  container: 'container',  background: { color: '#F2F7FA' },});
const source = graph.addNode({  shape: 'rect',  x: 40,  y: 40,  width: 100,  height: 40,  label: 'Source',  attrs: {    body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },  },});
const target = graph.addNode({  shape: 'rect',  x: 300,  y: 200,  width: 100,  height: 40,  label: 'Target',  attrs: {    body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },  },});
graph.addEdge({  source,  target,  attrs: {    line: { stroke: '#8f8f8f', strokeWidth: 1 },  },});
// 内容居中:所有节点/边添加完成后调用,使画布内容相对于容器居中显示// 如需缩放以适应容器,使用 graph.zoomToFit({ padding: 20, maxScale: 1 }) 替代graph.centerContent();

场景选择指南

场景推荐配置关键特性
DAG 数据管道ports + orth router + connecting有向无环、端口连线
ER 实体关系图HTML 节点 + er router表格式节点、字段展示
流程图/审批流菱形判断节点 + 分支边条件分支、多路径
组织架构图orth router + 树形布局层级关系、折叠
血缘分析左右布局 + smooth connector多层流转、端口
网络拓扑圆形节点 + 星型结构设备类型、连接状态
状态机圆形节点 + 边标签状态转换、事件触发

内置节点类型

shape形状适用场景
rect矩形通用节点、流程步骤
circle圆形状态节点、端点
ellipse椭圆通用强调
polygon多边形菱形(判断)、六边形
text纯文本标注、注释
image图片图标节点
htmlHTML富文本、表格式节点

路由器与连接器

路由器(Router)— 决定边的路径走向

类型效果适用场景
normal直线(默认)简单图
orth正交折线流程图、DAG
manhattan智能正交(绕障)复杂布局
metro地铁线风格地铁图
erER 图专用实体关系图

连接器(Connector)— 决定边的线条样式

类型效果适用场景
normal直线段(默认)简单图
rounded圆角折线流程图(推荐)
smooth贝塞尔曲线血缘图、关系图
jumpover跨线跳跃复杂交叉

插件速查

插件注册方式功能
Selectiongraph.use(new Selection({ enabled: true, rubberband: true }))框选节点
Snaplinegraph.use(new Snapline({ enabled: true }))对齐辅助线
Historygraph.use(new History({ enabled: true }))撤销/重做
Clipboardgraph.use(new Clipboard({ enabled: true }))复制/粘贴
Keyboardgraph.use(new Keyboard({ enabled: true }))快捷键绑定
Scrollergraph.use(new Scroller({ enabled: true }))滚动画布
MiniMapgraph.use(new MiniMap({ enabled: true, container }))小地图导航
Transformgraph.use(new Transform({ resizing: { enabled: true }, rotating: { enabled: true } }))节点缩放/旋转
Exportgraph.use(new Export())导出 PNG/SVG
Stencilgraph.use(new Stencil({ target: graph, groups: [...] }))侧边栏拖拽面板
Dndgraph.use(new Dnd({ target: graph }))拖拽创建节点
Ln 1, Col 1MarkdownSpaces: 2
No errors