@blueking/flow-canvas 0.0.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +725 -0
  2. package/dist/core/apply-command.d.ts +11 -0
  3. package/dist/core/editor.d.ts +50 -0
  4. package/dist/core/errors.d.ts +6 -0
  5. package/dist/core/history.d.ts +15 -0
  6. package/dist/core/plugin-manager.d.ts +58 -0
  7. package/dist/index-BAAMFT_J.js +236 -0
  8. package/dist/index-CleU3x1v.cjs +1 -0
  9. package/dist/index-DD3pv5ZZ.cjs +21 -0
  10. package/dist/index-siYsjzl4.js +181 -0
  11. package/dist/index.cjs.js +1 -0
  12. package/dist/index.d.ts +33 -0
  13. package/dist/index.esm.js +2709 -0
  14. package/dist/plugins/clipboard.d.ts +9 -0
  15. package/dist/plugins/connection-validator.d.ts +3 -0
  16. package/dist/plugins/minimap.d.ts +7 -0
  17. package/dist/plugins/selection.d.ts +7 -0
  18. package/dist/plugins/snapline.d.ts +6 -0
  19. package/dist/runtime/canvas-api.d.ts +25 -0
  20. package/dist/runtime/canvas-runtime-core.vue.d.ts +36 -0
  21. package/dist/runtime/event-bridge.d.ts +28 -0
  22. package/dist/runtime/graph-bridge.d.ts +127 -0
  23. package/dist/runtime/overlay-manager.d.ts +4 -0
  24. package/dist/runtime/shape-registry.d.ts +8 -0
  25. package/dist/runtime/use-edge-delete-tool.d.ts +11 -0
  26. package/dist/runtime/use-node-hover.d.ts +8 -0
  27. package/dist/runtime/use-port-visibility.d.ts +15 -0
  28. package/dist/shell/canvas-layout.vue.d.ts +35 -0
  29. package/dist/shell/canvas-node-palette.vue.d.ts +10 -0
  30. package/dist/shell/canvas-toolbar.vue.d.ts +11 -0
  31. package/dist/shell/default-node.vue.d.ts +4 -0
  32. package/dist/shell/default-schema.d.ts +39 -0
  33. package/dist/shell/node-actions-toolbar.vue.d.ts +18 -0
  34. package/dist/shell/node-quick-add-popover.vue.d.ts +36 -0
  35. package/dist/shell/toolbar-items.d.ts +13 -0
  36. package/dist/style.css +1 -0
  37. package/dist/types/api.d.ts +104 -0
  38. package/dist/types/command.d.ts +160 -0
  39. package/dist/types/flow-model.d.ts +46 -0
  40. package/dist/types/history.d.ts +18 -0
  41. package/dist/types/overlay.d.ts +17 -0
  42. package/dist/types/plugin.d.ts +64 -0
  43. package/dist/types/schema.d.ts +77 -0
  44. package/dist/utils/path.d.ts +7 -0
  45. package/dist/utils/uuid.d.ts +1 -0
  46. package/package.json +55 -0
package/README.md ADDED
@@ -0,0 +1,725 @@
1
+ # @blueking/flow-canvas 使用文档
2
+
3
+ ## 概述
4
+
5
+ `@blueking/flow-canvas` 是一个通用流程画布编辑引擎,基于 AntV X6 构建,提供数据驱动的图编辑能力。适用于 DAG / 流程图 / 工作流等场景。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ npm install @blueking/flow-canvas
11
+ ```
12
+
13
+ ### 必需的对等依赖
14
+
15
+ ```bash
16
+ npm install @antv/x6 @antv/x6-plugin-minimap @antv/x6-plugin-selection @antv/x6-plugin-snapline @antv/x6-vue-shape vue
17
+ ```
18
+
19
+ ### 可选依赖
20
+
21
+ ```bash
22
+ npm install @antv/x6-plugin-dnd # 拖拽建节点(DND)功能需要
23
+ ```
24
+
25
+ ## 快速开始
26
+
27
+ ```vue
28
+ <template>
29
+ <CanvasLayout>
30
+ <template #sidebar>
31
+ <!-- 自定义侧边栏 -->
32
+ </template>
33
+ <CanvasRuntime :editor="editor" @ui-event="handleUiEvent">
34
+ <template #node-overlay="{ node, screenAnchors, api }">
35
+ <!-- 节点悬浮操作按钮 -->
36
+ </template>
37
+ </CanvasRuntime>
38
+ <CanvasToolbar :editor="editor" />
39
+ </CanvasLayout>
40
+ </template>
41
+
42
+ <script setup lang="ts">
43
+ import {
44
+ useCanvasEditor,
45
+ CanvasRuntime,
46
+ CanvasLayout,
47
+ CanvasToolbar,
48
+ selectionPlugin,
49
+ snaplinePlugin,
50
+ connectionValidatorPlugin,
51
+ type CanvasSchema,
52
+ type CanvasUiEvent,
53
+ type FlowModel,
54
+ } from '@blueking/flow-canvas';
55
+ import '@blueking/flow-canvas/style';
56
+ import MyTaskNode from './components/my-task-node.vue';
57
+
58
+ const schema: CanvasSchema = {
59
+ nodeTypes: {
60
+ task: {
61
+ component: MyTaskNode,
62
+ getSize: () => ({ width: 180, height: 60 }),
63
+ getPorts: () => [
64
+ { id: 'left', group: 'left' },
65
+ { id: 'right', group: 'right' },
66
+ ],
67
+ },
68
+ },
69
+ edgeTypes: {
70
+ default: {
71
+ router: { name: 'manhattan', args: { padding: 10 } },
72
+ connector: 'rounded',
73
+ },
74
+ },
75
+ defaultEdgeType: 'default',
76
+ };
77
+
78
+ const initialFlowModel: FlowModel = {
79
+ version: '1.0',
80
+ nodes: {
81
+ node1: { id: 'node1', type: 'task', position: { x: 100, y: 200 }, label: '任务 1' },
82
+ node2: { id: 'node2', type: 'task', position: { x: 400, y: 200 }, label: '任务 2' },
83
+ },
84
+ edges: {
85
+ edge1: {
86
+ id: 'edge1',
87
+ source: { nodeId: 'node1', portId: 'right' },
88
+ target: { nodeId: 'node2', portId: 'left' },
89
+ },
90
+ },
91
+ };
92
+
93
+ const editor = useCanvasEditor({
94
+ initialFlowModel,
95
+ schema,
96
+ plugins: [
97
+ selectionPlugin(),
98
+ snaplinePlugin(),
99
+ connectionValidatorPlugin((ctx) => {
100
+ if (ctx.sourceNode.id === ctx.targetNode.id) {
101
+ return { valid: false, reason: '不允许自环连线' };
102
+ }
103
+ return { valid: true };
104
+ }),
105
+ ],
106
+ onFlowModelChange(event) {
107
+ console.log('流程变更:', event.flowModel);
108
+ },
109
+ });
110
+
111
+ function handleUiEvent(event: CanvasUiEvent) {
112
+ if (event.type === 'node.click') {
113
+ console.log('点击了节点:', event.nodeId);
114
+ }
115
+ }
116
+ </script>
117
+ ```
118
+
119
+ ---
120
+
121
+ ## 核心 API
122
+
123
+ ### useCanvasEditor(options)
124
+
125
+ 创建画布编辑器实例。
126
+
127
+ #### CanvasEditorOptions
128
+
129
+ | 参数 | 类型 | 必填 | 默认 | 说明 |
130
+ | ----------------- | ---------------------- | ---- | -------- | --------------------------------------- |
131
+ | initialFlowModel | `FlowModel` | 是 | - | 初始流程模型 |
132
+ | schema | `CanvasSchema` | 是 | - | 节点/边类型定义 |
133
+ | plugins | `CanvasPlugin[]` | 否 | `[]` | 插件列表 |
134
+ | mode | `CanvasMode` | 否 | `'edit'` | `'edit'` / `'readonly'` / `'thumbnail'` |
135
+ | historyOptions | `CanvasHistoryOptions` | 否 | - | 历史配置 |
136
+ | onCommandResult | `(result) => void` | 否 | - | 命令执行结果回调 |
137
+ | onFlowModelChange | `(event) => void` | 否 | - | FlowModel 变更回调 |
138
+
139
+ #### CanvasEditorContext(返回值)
140
+
141
+ | 属性/方法 | 类型 | 说明 |
142
+ | ------------------------ | --------------------------------------------- | ------------------------------ |
143
+ | flowModel | `Readonly<Ref<FlowModel>>` | 当前流程模型(响应式) |
144
+ | history | `CanvasHistory` | 历史管理器 |
145
+ | schema | `CanvasSchema` | Schema 定义 |
146
+ | mode | `Ref<CanvasMode>` | 当前模式 |
147
+ | api | `Ref<CanvasApi \| null>` | 画布 API(Runtime 挂载后可用) |
148
+ | toolbarItems | `Ref<CanvasToolbarItem[]>` | 插件聚合的工具栏项 |
149
+ | extendedApi | `Record<string, Function>` | 插件扩展的 API |
150
+ | executeCommand(envelope) | `(CommandEnvelope) => CommandExecutionResult` | 执行命令 |
151
+ | replaceFlowModel(model) | `(FlowModel) => void` | 整体替换流程模型 |
152
+ | setMode(mode) | `(CanvasMode) => void` | 切换模式 |
153
+
154
+ ---
155
+
156
+ ## FlowModel 数据结构
157
+
158
+ ```typescript
159
+ interface FlowModel {
160
+ version: '1.0';
161
+ nodes: Record<string, FlowNodeModel>; // 节点字典,key = nodeId
162
+ edges: Record<string, FlowEdgeModel>; // 边字典,key = edgeId
163
+ meta?: Record<string, unknown>; // 全局元数据
164
+ extensions?: Record<string, unknown>; // 扩展数据
165
+ }
166
+
167
+ interface FlowNodeModel {
168
+ id: string;
169
+ type: string; // 对应 schema.nodeTypes 的 key
170
+ position: { x: number; y: number };
171
+ label?: string;
172
+ ports?: FlowPortModel[];
173
+ payload?: Record<string, unknown>; // 业务数据
174
+ extensions?: Record<string, unknown>; // 扩展数据
175
+ }
176
+
177
+ interface FlowEdgeModel {
178
+ id: string;
179
+ type?: string; // 对应 schema.edgeTypes 的 key
180
+ source: { nodeId: string; portId?: string };
181
+ target: { nodeId: string; portId?: string };
182
+ labels?: FlowEdgeLabelModel[];
183
+ payload?: Record<string, unknown>;
184
+ extensions?: Record<string, unknown>;
185
+ }
186
+ ```
187
+
188
+ ---
189
+
190
+ ## CanvasSchema 配置
191
+
192
+ ### 节点类型定义
193
+
194
+ ```typescript
195
+ interface CanvasNodeDefinition {
196
+ component: Component; // Vue 组件,渲染节点内容
197
+ getSize: (node) => { width; height };
198
+ getPorts?: (node) => FlowPortModel[];
199
+ getBehavior?: (node, ctx) => NodeBehaviorConfig;
200
+ getOverlayAnchors?: (node) => NodeOverlayAnchors;
201
+ x6CellConfig?: Record<string, unknown>; // 透传给 X6 的额外配置
202
+ }
203
+ ```
204
+
205
+ 节点 Vue 组件内可通过 `inject('getNode')` 获取 X6 Node 实例,读取 `node.getData()` 访问 `FlowNodeModel`。
206
+
207
+ ### 边类型定义
208
+
209
+ ```typescript
210
+ interface CanvasEdgeDefinition {
211
+ router?: string | { name: string; args?: Record<string, unknown> };
212
+ connector?: string | { name: string; args?: Record<string, unknown> };
213
+ style?: (edge, state: EdgeRenderState) => EdgeStyle; // 动态样式
214
+ labelDraggable?: boolean;
215
+ x6EdgeConfig?: Record<string, unknown>; // 透传给 X6 的额外配置
216
+
217
+ // @experimental — 尚未完整实现,请勿在生产环境依赖
218
+ // labelRenderer?: Component;
219
+ }
220
+ ```
221
+
222
+ **EdgeRenderState** 包含 `selected`、`highlighted`、`hovered` 三个布尔值,`style()` 可据此返回不同的 `stroke`、`strokeWidth`、`strokeDasharray`。
223
+
224
+ > **注意:** `labelRenderer` 字段在类型定义中存在但标记为 `@experimental`,当前版本尚未完整实现。如需自定义边标签样式,建议通过 `x6EdgeConfig.defaultLabel` 配置 X6 原生标签 markup。
225
+
226
+ > **注意:** `labelRenderer` 字段在类型定义中存在但标记为 `@experimental`,当前版本尚未完整实现。如需自定义边标签样式,建议通过 `x6EdgeConfig.defaultLabel` 配置 X6 原生标签 markup。
227
+
228
+ ---
229
+
230
+ ## 命令系统
231
+
232
+ 所有 FlowModel 变更必须通过命令执行:
233
+
234
+ ```typescript
235
+ import { generateId } from '@blueking/flow-canvas';
236
+
237
+ editor.executeCommand({
238
+ id: generateId(),
239
+ source: 'user:panel',
240
+ label: '添加节点',
241
+ timestamp: Date.now(),
242
+ commands: [
243
+ { type: 'node.add', node: { id: 'n1', type: 'task', position: { x: 100, y: 100 } } },
244
+ { type: 'edge.add', edge: { id: 'e1', source: { nodeId: 'n0' }, target: { nodeId: 'n1' } } },
245
+ ],
246
+ });
247
+ ```
248
+
249
+ ### 命令类型一览
250
+
251
+ | 命令 | 说明 |
252
+ | --------------------- | ------------------------------------------- |
253
+ | `node.add` | 添加节点 |
254
+ | `node.move` | 移动节点位置 |
255
+ | `node.remove` | 删除节点(自动级联删除关联边) |
256
+ | `node.update` | 更新节点结构字段(不含 payload/extensions) |
257
+ | `node.set-payload` | 按路径更新节点 payload |
258
+ | `node.set-extensions` | 按路径更新节点 extensions |
259
+ | `edge.add` | 添加边 |
260
+ | `edge.remove` | 删除边 |
261
+ | `edge.reconnect` | 重连边端点 |
262
+ | `edge.update` | 更新边结构字段 |
263
+ | `edge.set-payload` | 按路径更新边 payload |
264
+ | `edge.label.update` | 更新边标签 |
265
+ | `model.set-meta` | 按路径更新全局 meta |
266
+
267
+ `path` 参数使用 `string[]` 格式:`{ path: ['config', 'timeout'], value: 30 }`。
268
+
269
+ ### CommandSource 类型
270
+
271
+ `'user:drag'` | `'user:keyboard'` | `'user:toolbar'` | `'user:quick-add'` | `'user:panel'` | `'plugin'` | `'system'` | `'system:replace'`
272
+
273
+ ---
274
+
275
+ ## 组件
276
+
277
+ ### CanvasRuntime
278
+
279
+ 核心渲染组件,负责创建 X6 Graph 并双向桥接 FlowModel。
280
+
281
+ | Prop | 类型 | 说明 |
282
+ | ------------ | ------------------------- | ------------------------------------------ |
283
+ | editor | `CanvasEditorContext` | 编辑器实例(必填) |
284
+ | graphOptions | `Record<string, unknown>` | 额外 X6 Graph 选项 |
285
+ | nodeActions | `NodeActionsConfig` | 节点快捷操作工具栏配置(见下方详细说明) |
286
+ | quickAdd | `QuickAddConfig` | 右侧端口快捷添加按钮配置(见下方详细说明) |
287
+
288
+ | Emit | 参数 | 说明 |
289
+ | -------- | --------------- | -------------------- |
290
+ | ui-event | `CanvasUiEvent` | 非命令类 UI 交互事件 |
291
+
292
+ | Slot | Props | 说明 |
293
+ | --------------- | ------------------------------------------------ | ----------------------------------------------------------- |
294
+ | node-overlay | `{ node, screenAnchors, api }` | 节点悬浮层,鼠标移入节点时显示 |
295
+ | quick-add-panel | `{ node, api, insertNodeToRight, closePopover }` | 快捷添加弹层内容,点击右侧"+"按钮时显示(默认显示提示文字) |
296
+
297
+ #### 节点快捷操作工具栏
298
+
299
+ `CanvasRuntime` 内置节点快捷操作工具栏,hover 节点时在右下角显示。通过 `nodeActions` prop 进行全局配置:
300
+
301
+ ```html
302
+ <CanvasRuntime :editor="editor" :node-actions="{ showDebug: true, showCopy: false }" />
303
+ ```
304
+
305
+ **NodeActionsConfig(全局开关)**
306
+
307
+ | 属性 | 类型 | 默认 | 说明 |
308
+ | ---------------- | --------- | ------- | ---------------------------- |
309
+ | `showDebug` | `boolean` | `false` | 是否显示调试按钮 |
310
+ | `showDelete` | `boolean` | `true` | 是否显示删除按钮 |
311
+ | `showCopy` | `boolean` | `true` | 是否显示复制按钮 |
312
+ | `showCopyInsert` | `boolean` | `true` | 是否显示复制并插入按钮 |
313
+ | `showDisconnect` | `boolean` | `true` | 是否显示断开连线按钮 |
314
+ | `insertGap` | `number` | `100` | 向右插入节点的水平间距(px) |
315
+
316
+ **NodeBehaviorConfig 中的工具栏相关字段(逐节点控制)**
317
+
318
+ 通过 schema `getBehavior` 返回值控制每个节点类型的工具栏行为:
319
+
320
+ | 属性 | 说明 |
321
+ | -------------------- | -------------------------------------------------------- |
322
+ | `showActions` | `false` → 该节点类型不显示整个工具栏 |
323
+ | `deletable` | `false` → 隐藏删除按钮 |
324
+ | `copyable` | `false` → 隐藏复制和复制并插入按钮 |
325
+ | `disconnectable` | `false` → 隐藏断开连线按钮 |
326
+ | `debuggable` | `false` → 隐藏调试按钮(需全局 `showDebug` 也为 `true`) |
327
+ | `deleteDisabled` | `true` → 删除按钮可见但置灰不可点击 |
328
+ | `copyDisabled` | `true` → 复制按钮置灰 |
329
+ | `copyInsertDisabled` | `true` → 复制并插入按钮置灰 |
330
+ | `disconnectDisabled` | `true` → 断开连线按钮置灰 |
331
+ | `debugDisabled` | `true` → 调试按钮置灰 |
332
+
333
+ 按钮有效可见性 = 全局 `show*` AND 逐节点 `*able !== false`;
334
+ 按钮禁用状态 = 逐节点 `*Disabled === true`。
335
+
336
+ 操作触发后通过 `@ui-event` 发出对应事件:`node.action.delete` / `node.action.copy` / `node.action.copy-insert` / `node.action.disconnect` / `node.action.debug`。
337
+
338
+ #### 节点快捷添加按钮
339
+
340
+ hover 节点时,右侧端口显示为"+"按钮,支持点击弹出面板和拖拽发起连线。通过 `quickAdd` prop 进行全局配置:
341
+
342
+ ```html
343
+ <CanvasRuntime :editor="editor" :quick-add="{ enabled: true }">
344
+ <template #quick-add-panel="{ node, api, insertNodeToRight, closePopover }">
345
+ <!-- 自定义节点选择面板 -->
346
+ </template>
347
+ </CanvasRuntime>
348
+ ```
349
+
350
+ **QuickAddConfig(全局配置)**
351
+
352
+ | 属性 | 类型 | 默认 | 说明 |
353
+ | ------------- | --------- | ------ | --------------------------------------- |
354
+ | `enabled` | `boolean` | `true` | 全局开关 |
355
+ | `tooltipText` | `string` | `''` | 自定义 tooltip 文案(空值使用内置提示) |
356
+
357
+ **NodeBehaviorConfig 中的快捷添加相关字段(逐节点控制)**
358
+
359
+ | 属性 | 说明 |
360
+ | ----------------- | --------------------------------------------------------------- |
361
+ | `quickAddEnabled` | `false` → 该节点不显示"+"按钮(如结束节点、已有出边的开始节点) |
362
+
363
+ 生效规则:显示 = `global.enabled !== false` AND `perNode.quickAddEnabled !== false`。
364
+
365
+ **quick-add-panel Slot Props**
366
+
367
+ | Prop | 类型 | 说明 |
368
+ | ------------------- | ------------------------------------------------- | ------------------------------- |
369
+ | `node` | `FlowNodeModel` | 当前触发的源节点 |
370
+ | `api` | `CanvasApi` | 画布 API |
371
+ | `insertNodeToRight` | `(node: Omit<FlowNodeModel, 'position'>) => void` | 快捷插入方法(自动连线 + 事件) |
372
+ | `closePopover` | `() => void` | 关闭弹层 |
373
+
374
+ 操作触发后通过 `@ui-event` 发出对应事件:`node.quick-add`(弹层打开时)/ `node.action.quick-insert`(插入成功时)。
375
+
376
+ ### CanvasLayout
377
+
378
+ 可选的布局骨架组件。
379
+
380
+ | Prop | 类型 | 默认 | 说明 |
381
+ | ---------------- | --------- | ------- | -------------- |
382
+ | sidebarCollapsed | `boolean` | `false` | 侧边栏是否收起 |
383
+ | sidebarWidth | `number` | `260` | 侧边栏宽度 |
384
+ | hideSidebar | `boolean` | `false` | 是否隐藏侧边栏 |
385
+ | hideFooter | `boolean` | `false` | 是否隐藏底部栏 |
386
+
387
+ | Slot | 说明 |
388
+ | ------- | ------------------------------------------------ |
389
+ | sidebar | 侧边栏内容 |
390
+ | default | 主画布区域(放置 CanvasRuntime + CanvasToolbar) |
391
+ | footer | 底部栏 |
392
+
393
+ ### CanvasToolbar
394
+
395
+ 可选的工具栏组件。默认浮动在画布左上角,包含搜索、下载、缩放、重置等操作。
396
+
397
+ | Prop | 类型 | 默认 | 说明 |
398
+ | ------- | ---------------------- | ---------- | --------------------------------------- |
399
+ | editor | `CanvasEditorContext` | - | 编辑器实例(必填) |
400
+ | items | `CanvasToolbarItem[]` | 内置默认项 | 工具栏项列表,传入后完全替换默认项 |
401
+ | exclude | `BuiltinToolbarType[]` | - | 排除特定默认项(仅在未传 items 时生效) |
402
+
403
+ #### createDefaultToolbarItems(options?)
404
+
405
+ 工厂函数,用于获取默认工具栏项列表,便于自定义组合。
406
+
407
+ ```typescript
408
+ import { createDefaultToolbarItems } from '@blueking/flow-canvas';
409
+
410
+ // 排除搜索,追加自定义项
411
+ const items = [
412
+ ...createDefaultToolbarItems({ exclude: ['search'] }),
413
+ { id: 'my-tool', type: 'custom', icon: 'my-icon-class', onClick: handleClick },
414
+ ];
415
+ ```
416
+
417
+ #### CanvasToolbarItem 字段
418
+
419
+ | 字段 | 类型 | 说明 |
420
+ | ----------- | -------------------------------------- | ----------------------------------------- |
421
+ | id | `string` | 唯一标识 |
422
+ | type | `BuiltinToolbarType \| 'custom'` | 操作类型 |
423
+ | icon | `string` | CSS 类名(字体图标) |
424
+ | component | `Component` | Vue 组件,渲染在按钮内部作为图标/内容区域 |
425
+ | text | `string` | 无图标时的兜底显示文字 |
426
+ | description | `string` | 操作说明,有值时 hover 显示 tooltip 气泡 |
427
+ | onClick | `(ctx: CanvasCallbackContext) => void` | 点击回调 |
428
+
429
+ ---
430
+
431
+ ## CanvasApi
432
+
433
+ `editor.api.value` 在 `CanvasRuntime` 挂载后可用,之前为 `null`。
434
+
435
+ | 方法 | 说明 |
436
+ | ----------------------------------------------- | ------------------------------------------------ |
437
+ | zoomIn() / zoomOut() | 缩放 |
438
+ | zoomTo(value) | 缩放到指定比例 |
439
+ | zoomToFit() | 自适应画布 |
440
+ | getZoom() | 获取当前缩放比例 |
441
+ | centerContent() | 居中画布内容 |
442
+ | scrollToNode(nodeId) | 滚动到指定节点 |
443
+ | getSelection() | 获取当前选区 `{ nodeIds, edgeIds }` |
444
+ | selectNodes(ids) | 选中指定节点 |
445
+ | selectEdges(ids) | 选中指定边 |
446
+ | clearSelection() | 清除选区 |
447
+ | registerDndSource(el, factory) | 注册 DND 拖拽源,返回清理函数 |
448
+ | startConnection(nodeId, portId?) | 从指定节点/端口发起连线 |
449
+ | highlightNodes(ids) / highlightEdges(ids) | 高亮指定元素 |
450
+ | clearHighlight() | 清除所有高亮 |
451
+ | exportAsImage(options?) | 导出为 PNG Blob |
452
+ | exportAsSVG() | 导出为 SVG 字符串 |
453
+ | overlay | `OverlayManager` 实例,提供节点屏幕定位 |
454
+ | insertNodeToRight(sourceNodeId, node, options?) | 在指定节点右侧插入新节点,支持自动连线和重叠检测 |
455
+ | getContextMenuItems(position) | 收集插件提供的右键菜单项 |
456
+ | onGraphEvent(event, handler) | 监听 X6 底层事件,返回取消函数 |
457
+ | unsafeGetGraph() | 获取 X6 Graph 实例(谨慎使用) |
458
+
459
+ ---
460
+
461
+ ## 内置插件
462
+
463
+ ### selectionPlugin(options?)
464
+
465
+ 启用节点/边的框选和多选能力。
466
+
467
+ ```typescript
468
+ selectionPlugin({
469
+ rubberband: true, // 框选,默认 true
470
+ multiple: true, // 多选,默认 true
471
+ movable: true, // 选中后可拖拽移动,默认 true
472
+ });
473
+ ```
474
+
475
+ ### snaplinePlugin(options?)
476
+
477
+ 节点拖拽时显示对齐辅助线。
478
+
479
+ ```typescript
480
+ snaplinePlugin({ tolerance: 10 }); // 对齐容差,默认 10
481
+ ```
482
+
483
+ ### connectionValidatorPlugin(validator)
484
+
485
+ 连线校验。
486
+
487
+ ```typescript
488
+ connectionValidatorPlugin((ctx) => {
489
+ // ctx.flowModel: 当前 FlowModel
490
+ // ctx.sourceNode / targetNode: 源/目标节点
491
+ // ctx.existingEdges: 已有边列表
492
+ if (ctx.sourceNode.id === ctx.targetNode.id) {
493
+ return { valid: false, reason: '不允许自环' };
494
+ }
495
+ return { valid: true };
496
+ });
497
+ ```
498
+
499
+ ### minimapPlugin(options?)
500
+
501
+ 小地图。传入 `container` 后启用。
502
+
503
+ ```typescript
504
+ minimapPlugin({
505
+ container: document.getElementById('minimap'),
506
+ width: 200,
507
+ height: 160,
508
+ });
509
+ ```
510
+
511
+ ### clipboardPlugin()
512
+
513
+ Cmd/Ctrl+C 复制选中节点/边,Cmd/Ctrl+V 粘贴(生成新 ID、偏移位置)。
514
+
515
+ ---
516
+
517
+ ## 自定义插件
518
+
519
+ ```typescript
520
+ const myPlugin: CanvasPlugin = {
521
+ name: 'my-plugin',
522
+ priority: 50,
523
+
524
+ // editor 阶段:仅有 flowModel / history / schema
525
+ install(ctx) {},
526
+
527
+ // runtime 阶段:api / graph 已可用
528
+ attachRuntime(ctx) {
529
+ ctx.api.onGraphEvent('cell:mouseenter', () => {
530
+ /* ... */
531
+ });
532
+ },
533
+ detachRuntime() {},
534
+
535
+ // 命令拦截/增强(不可变管道)
536
+ transformCommand(envelope, preview, ctx) {
537
+ // 返回新 envelope = 修改后的命令
538
+ // 返回 { rejected: true, reason: '...' } = 拒绝
539
+ // 返回 null = 丢弃
540
+ return envelope;
541
+ },
542
+
543
+ // 命令执行后
544
+ afterCommand(envelope, prevModel, newModel, ctx) {},
545
+
546
+ // UI 事件
547
+ onUiEvent(event, ctx) {},
548
+ onKeyboardShortcut(event, ctx) {
549
+ return false;
550
+ },
551
+ onSelectionChange(selection, ctx) {},
552
+
553
+ // 视觉装饰
554
+ decorateNode(node, ctx) {
555
+ if (node.payload?.hasError) {
556
+ return { borderColor: '#ff4d4d', badge: { text: '!', color: '#ff4d4d' } };
557
+ }
558
+ },
559
+ decorateEdge(edge, ctx) {},
560
+
561
+ // 工具栏扩展
562
+ provideToolbarItems(ctx) {
563
+ return [{ id: 'my-tool', type: 'custom', text: '自定义工具', onClick: () => {} }];
564
+ },
565
+
566
+ // API 扩展
567
+ extendApi(api, ctx) {
568
+ return {
569
+ doSomething: () => {
570
+ /* ... */
571
+ },
572
+ };
573
+ },
574
+ };
575
+ ```
576
+
577
+ ---
578
+
579
+ ## 工具函数与底层 API
580
+
581
+ | 导出 | 说明 |
582
+ | ------------------------------------------------- | --------------------------------------------------------------------------------- |
583
+ | `createEmptyFlowModel()` | 创建一个空的 FlowModel(`version: '1.0'`, 空 nodes/edges) |
584
+ | `generateId()` | 生成唯一 ID |
585
+ | `applyCanvasCommand(model, cmd)` | 纯函数 reducer,将单条命令应用到 FlowModel,返回新 FlowModel |
586
+ | `createCanvasHistory(initialFlowModel, options?)` | 创建独立的历史管理器实例(通常由 `useCanvasEditor` 内部调用,高级场景可直接使用) |
587
+ | `CanvasConstraintError` | 命令违反 FlowModel 不变量时抛出的错误类(如重复 ID、悬挂引用等) |
588
+ | `CanvasSchemaError` | 未知节点/边类型等 Schema 级错误类 |
589
+
590
+ ```typescript
591
+ import { createEmptyFlowModel, generateId } from '@blueking/flow-canvas';
592
+
593
+ const emptyModel = createEmptyFlowModel();
594
+ // { version: '1.0', nodes: {}, edges: {} }
595
+ ```
596
+
597
+ ---
598
+
599
+ ## 撤销/重做
600
+
601
+ ```typescript
602
+ editor.history.undo();
603
+ editor.history.redo();
604
+ editor.history.canUndo.value; // boolean
605
+ editor.history.canRedo.value; // boolean
606
+ editor.history.clear();
607
+ ```
608
+
609
+ ---
610
+
611
+ ## 事件类型 (CanvasUiEvent)
612
+
613
+ | type | 附加字段 | 说明 |
614
+ | ------------------------ | ----------------------- | ---------------- |
615
+ | node.click | nodeId | 节点点击 |
616
+ | node.dblclick | nodeId | 节点双击 |
617
+ | node.contextmenu | nodeId, position | 节点右键 |
618
+ | edge.click | edgeId | 边点击 |
619
+ | edge.label.click | edgeId, labelId | 边标签点击 |
620
+ | blank.click | position | 空白区域点击 |
621
+ | blank.contextmenu | position | 空白区域右键 |
622
+ | selection.change | nodeIds, edgeIds | 选区变更 |
623
+ | node.action.delete | nodeId | 快捷删除节点 |
624
+ | node.action.copy | sourceNodeId, newNodeId | 快捷复制节点 |
625
+ | node.action.copy-insert | sourceNodeId, newNodeId | 快捷复制并插入 |
626
+ | node.action.disconnect | nodeId, edgeIds | 快捷断开连线 |
627
+ | node.action.debug | nodeId | 快捷调试 |
628
+ | node.quick-add | nodeId, position | 快捷添加弹层打开 |
629
+ | node.action.quick-insert | sourceNodeId, newNodeId | 快捷插入节点 |
630
+
631
+ ---
632
+
633
+ ## 公开类型参考
634
+
635
+ 以下类型从包入口公开导出,供 TypeScript 接入方使用。
636
+
637
+ ### 数据模型
638
+
639
+ | 类型 | 说明 |
640
+ | -------------------- | ---------------------------- |
641
+ | `FlowModel` | 流程模型,编辑态唯一权威状态 |
642
+ | `FlowNodeModel` | 节点模型 |
643
+ | `FlowEdgeModel` | 边模型 |
644
+ | `FlowPortModel` | 端口模型 |
645
+ | `FlowEdgeLabelModel` | 边标签模型 |
646
+
647
+ ### Schema 与渲染
648
+
649
+ | 类型 | 说明 |
650
+ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
651
+ | `CanvasSchema` | 画布配置(nodeTypes / edgeTypes) |
652
+ | `CanvasNodeDefinition` | 节点类型定义(component / getSize / getPorts / getBehavior / getOverlayAnchors) |
653
+ | `CanvasEdgeDefinition` | 边类型定义(router / connector / style / labelDraggable)。`labelRenderer` 字段为 `@experimental`,当前未实现 |
654
+ | `CanvasCallbackContext` | 运行时上下文(api / flowModel / history / mode) |
655
+ | `CanvasMode` | 模式:`'edit'` / `'readonly'` / `'thumbnail'` |
656
+ | `NodeBehaviorConfig` | 节点行为配置(showActions / draggable / selectable / deletable / connectable / copyable / disconnectable / debuggable / quickAddEnabled + 各按钮 Disabled 状态) |
657
+ | `EdgeRenderState` | 边渲染状态(selected / highlighted / hovered) |
658
+ | `EdgeStyle` | 边样式(stroke / strokeWidth / strokeDasharray) |
659
+
660
+ ### 命令系统
661
+
662
+ | 类型 | 说明 |
663
+ | ----------------------------------- | --------------------------------------------- |
664
+ | `CanvasCommand` | 原子命令联合类型(node.add / edge.remove 等) |
665
+ | `CommandEnvelope` | 命令信封(id / source / commands[]) |
666
+ | `CommandSource` | 命令来源标识 |
667
+ | `CommandExecutionResult` | 命令执行结果 |
668
+ | `CommandExecutionError` | 命令执行错误详情 |
669
+ | `CommandPreview` | 命令预览接口(用于 transformCommand) |
670
+ | `CommandRejection` | 命令拒绝结果 |
671
+ | `FlowModelChangeEvent` | FlowModel 变更事件 |
672
+ | `CanvasUiEvent` | UI 交互事件联合类型 |
673
+ | `ScreenPosition` / `CanvasPosition` | 坐标类型 |
674
+
675
+ ### 插件系统
676
+
677
+ | 类型 | 说明 |
678
+ | ---------------------- | -------------------------------------------------------------------------- |
679
+ | `CanvasPlugin` | 插件接口(install / attachRuntime / transformCommand / decorateNode 等) |
680
+ | `EditorPluginContext` | editor 阶段插件上下文(flowModel / history / schema / executeCommand) |
681
+ | `RuntimePluginContext` | runtime 阶段插件上下文(继承 EditorPluginContext + api / graph / overlay) |
682
+ | `CanvasSelection` | 选区数据(nodeIds / edgeIds) |
683
+ | `NodeDecoration` | 节点装饰(className / badge / borderColor) |
684
+ | `EdgeDecoration` | 边装饰(className / strokeColor) |
685
+ | `ContextMenuItem` | 右键菜单项 |
686
+
687
+ ### API 与工具栏
688
+
689
+ | 类型 | 说明 |
690
+ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
691
+ | `CanvasApi` | 画布公共 API 接口(含 `insertNodeToRight`) |
692
+ | `CanvasToolbarItem` | 工具栏项配置 |
693
+ | `BuiltinToolbarType` | 内置工具类型(`'undo'` / `'redo'` / `'select'` / `'auto-layout'` / `'search'` / `'minimap'` / `'export'` / `'zoom-in'` / `'zoom-out'` / `'reset'` 等) |
694
+ | `NodeActionsConfig` | 节点快捷操作工具栏全局配置(showDebug / showDelete / showCopy / showCopyInsert / showDisconnect / insertGap) |
695
+ | `QuickAddConfig` | 快捷添加按钮全局配置(enabled / tooltipText) |
696
+ | `InsertNodeOptions` | `insertNodeToRight` 选项(autoWireEdges / gap / source / label) |
697
+ | `ExportOptions` | 导出选项(backgroundColor / padding / quality) |
698
+ | `ConnectionValidator` | 连接校验函数类型 |
699
+ | `ConnectionValidateContext` | 连接校验上下文 |
700
+ | `ConnectionValidateResult` | 连接校验结果 |
701
+
702
+ ### 历史与 Overlay
703
+
704
+ | 类型 | 说明 |
705
+ | ---------------------- | -------------------------- |
706
+ | `CanvasHistory` | 历史管理器接口 |
707
+ | `CanvasHistoryOptions` | 历史配置(maxHistorySize) |
708
+ | `OverlayManager` | Overlay 管理器接口 |
709
+ | `NodeOverlayAnchors` | 节点 Overlay 锚点定义 |
710
+ | `OverlayAnchor` | 单个锚点坐标 |
711
+
712
+ ### 编辑器
713
+
714
+ | 类型 | 说明 |
715
+ | --------------------- | ------------------------------ |
716
+ | `CanvasEditorContext` | `useCanvasEditor()` 返回值类型 |
717
+ | `CanvasEditorOptions` | `useCanvasEditor()` 参数类型 |
718
+
719
+ ### 插件选项
720
+
721
+ | 类型 | 说明 |
722
+ | ------------------------ | -------------------- |
723
+ | `SelectionPluginOptions` | selectionPlugin 配置 |
724
+ | `SnaplinePluginOptions` | snaplinePlugin 配置 |
725
+ | `MinimapPluginOptions` | minimapPlugin 配置 |