@blueking/flow-canvas 0.0.1-beta.1 → 0.0.1-beta.3
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.
- package/README.md +715 -62
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +983 -992
- package/dist/runtime/canvas-runtime-core.vue.d.ts +1 -6
- package/dist/runtime/overlay-manager.d.ts +1 -2
- package/dist/runtime/use-node-hover.d.ts +3 -1
- package/dist/shell/node-actions-toolbar.vue.d.ts +4 -0
- package/dist/shell/toolbar-items.d.ts +3 -1
- package/dist/style.css +1 -1
- package/dist/types/flow-model.d.ts +1 -1
- package/dist/types/overlay.d.ts +0 -14
- package/dist/types/schema.d.ts +5 -2
- package/package.json +1 -1
- package/dist/index-BAAMFT_J.js +0 -236
- package/dist/index-CleU3x1v.cjs +0 -1
- package/dist/index-DD3pv5ZZ.cjs +0 -21
- package/dist/index-siYsjzl4.js +0 -181
package/README.md
CHANGED
|
@@ -10,31 +10,67 @@
|
|
|
10
10
|
npm install @blueking/flow-canvas
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### 项目中另外还需要安装以下前置依赖
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npm install @antv/x6 @antv/x6-plugin-minimap @antv/x6-plugin-selection @antv/x6-plugin-snapline @antv/x6-vue-shape vue
|
|
16
|
+
npm install @antv/x6 @antv/x6-plugin-minimap @antv/x6-plugin-selection @antv/x6-plugin-snapline @antv/x6-plugin-dnd @antv/x6-vue-shape vue
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
## 快速开始
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
### 零配置启动
|
|
22
|
+
|
|
23
|
+
使用 `createDefaultSchema` 可零配置启动一个可拖拽、可连线的画布:
|
|
24
|
+
|
|
25
|
+
```vue
|
|
26
|
+
<template>
|
|
27
|
+
<CanvasLayout :editor="editor" :palette-items="paletteItems">
|
|
28
|
+
<CanvasRuntime :editor="editor" @ui-event="handleUiEvent" />
|
|
29
|
+
<CanvasToolbar :editor="editor" />
|
|
30
|
+
</CanvasLayout>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
import {
|
|
35
|
+
useCanvasEditor,
|
|
36
|
+
CanvasRuntime,
|
|
37
|
+
CanvasLayout,
|
|
38
|
+
CanvasToolbar,
|
|
39
|
+
createDefaultSchema,
|
|
40
|
+
createEmptyFlowModel,
|
|
41
|
+
selectionPlugin,
|
|
42
|
+
snaplinePlugin,
|
|
43
|
+
type CanvasUiEvent,
|
|
44
|
+
} from '@blueking/flow-canvas';
|
|
45
|
+
import '@blueking/flow-canvas/style';
|
|
46
|
+
|
|
47
|
+
const { schema, paletteItems } = createDefaultSchema();
|
|
48
|
+
|
|
49
|
+
const editor = useCanvasEditor({
|
|
50
|
+
initialFlowModel: createEmptyFlowModel(),
|
|
51
|
+
schema,
|
|
52
|
+
plugins: [selectionPlugin(), snaplinePlugin()],
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
function handleUiEvent(event: CanvasUiEvent) {
|
|
56
|
+
console.log('UI 事件:', event.type);
|
|
57
|
+
}
|
|
58
|
+
</script>
|
|
23
59
|
```
|
|
24
60
|
|
|
25
|
-
|
|
61
|
+
传入 `editor` prop 后,`CanvasLayout` 会自动在侧边栏渲染内置节点面板 `CanvasNodePalette`,用户可直接拖拽节点到画布。
|
|
62
|
+
|
|
63
|
+
### 自定义 Schema
|
|
64
|
+
|
|
65
|
+
如需完全控制节点/边类型,可手动定义 `CanvasSchema`:
|
|
26
66
|
|
|
27
67
|
```vue
|
|
28
68
|
<template>
|
|
29
69
|
<CanvasLayout>
|
|
30
70
|
<template #sidebar>
|
|
31
|
-
|
|
71
|
+
<MySidebar :editor="editor" />
|
|
32
72
|
</template>
|
|
33
|
-
<CanvasRuntime :editor="editor" @ui-event="handleUiEvent"
|
|
34
|
-
<template #node-overlay="{ node, screenAnchors, api }">
|
|
35
|
-
<!-- 节点悬浮操作按钮 -->
|
|
36
|
-
</template>
|
|
37
|
-
</CanvasRuntime>
|
|
73
|
+
<CanvasRuntime :editor="editor" @ui-event="handleUiEvent" />
|
|
38
74
|
<CanvasToolbar :editor="editor" />
|
|
39
75
|
</CanvasLayout>
|
|
40
76
|
</template>
|
|
@@ -116,7 +152,7 @@ npm install @antv/x6-plugin-dnd # 拖拽建节点(DND)功能需要
|
|
|
116
152
|
</script>
|
|
117
153
|
```
|
|
118
154
|
|
|
119
|
-
|
|
155
|
+
<br>
|
|
120
156
|
|
|
121
157
|
## 核心 API
|
|
122
158
|
|
|
@@ -151,13 +187,13 @@ npm install @antv/x6-plugin-dnd # 拖拽建节点(DND)功能需要
|
|
|
151
187
|
| replaceFlowModel(model) | `(FlowModel) => void` | 整体替换流程模型 |
|
|
152
188
|
| setMode(mode) | `(CanvasMode) => void` | 切换模式 |
|
|
153
189
|
|
|
154
|
-
|
|
190
|
+
<br>
|
|
155
191
|
|
|
156
192
|
## FlowModel 数据结构
|
|
157
193
|
|
|
158
194
|
```typescript
|
|
159
195
|
interface FlowModel {
|
|
160
|
-
version
|
|
196
|
+
version?: '1.0'; // 数据模型版本标识,可选,未传时引擎自动补全为 '1.0'
|
|
161
197
|
nodes: Record<string, FlowNodeModel>; // 节点字典,key = nodeId
|
|
162
198
|
edges: Record<string, FlowEdgeModel>; // 边字典,key = edgeId
|
|
163
199
|
meta?: Record<string, unknown>; // 全局元数据
|
|
@@ -185,7 +221,7 @@ interface FlowEdgeModel {
|
|
|
185
221
|
}
|
|
186
222
|
```
|
|
187
223
|
|
|
188
|
-
|
|
224
|
+
<br>
|
|
189
225
|
|
|
190
226
|
## CanvasSchema 配置
|
|
191
227
|
|
|
@@ -197,7 +233,6 @@ interface CanvasNodeDefinition {
|
|
|
197
233
|
getSize: (node) => { width; height };
|
|
198
234
|
getPorts?: (node) => FlowPortModel[];
|
|
199
235
|
getBehavior?: (node, ctx) => NodeBehaviorConfig;
|
|
200
|
-
getOverlayAnchors?: (node) => NodeOverlayAnchors;
|
|
201
236
|
x6CellConfig?: Record<string, unknown>; // 透传给 X6 的额外配置
|
|
202
237
|
}
|
|
203
238
|
```
|
|
@@ -223,29 +258,322 @@ interface CanvasEdgeDefinition {
|
|
|
223
258
|
|
|
224
259
|
> **注意:** `labelRenderer` 字段在类型定义中存在但标记为 `@experimental`,当前版本尚未完整实现。如需自定义边标签样式,建议通过 `x6EdgeConfig.defaultLabel` 配置 X6 原生标签 markup。
|
|
225
260
|
|
|
226
|
-
>
|
|
261
|
+
<br>
|
|
262
|
+
|
|
263
|
+
## createDefaultSchema — 开箱即用的 Schema 工厂
|
|
227
264
|
|
|
228
|
-
|
|
265
|
+
`createDefaultSchema` 提供内置的节点类型和边类型定义,可零配置快速启动画布。
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { createDefaultSchema } from '@blueking/flow-canvas';
|
|
269
|
+
|
|
270
|
+
const { schema, paletteItems } = createDefaultSchema(options?);
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### DefaultSchemaOptions
|
|
274
|
+
|
|
275
|
+
| 参数 | 类型 | 默认 | 说明 |
|
|
276
|
+
| --------------- | --------------------------------------- | ------------- | ---------------------------------------------- |
|
|
277
|
+
| nodeTypes | `Record<string, DefaultNodeTypeConfig>` | 7 种内置类型 | 自定义节点类型列表,传入后替换内置类型 |
|
|
278
|
+
| defaultEdgeType | `string` | `'manhattan'` | 默认连线类型,内置 `'manhattan'` 和 `'bezier'` |
|
|
279
|
+
| edgeTypes | `Record<string, CanvasEdgeDefinition>` | - | 额外/覆盖的边类型定义,会与内置类型合并 |
|
|
280
|
+
|
|
281
|
+
### 返回值
|
|
282
|
+
|
|
283
|
+
| 属性 | 类型 | 说明 |
|
|
284
|
+
| ------------ | ------------------- | -------------------------------------------- |
|
|
285
|
+
| schema | `CanvasSchema` | 可直接传给 `useCanvasEditor` 的 Schema 定义 |
|
|
286
|
+
| paletteItems | `NodePaletteItem[]` | 可传给 `CanvasLayout` 的 `paletteItems` prop |
|
|
287
|
+
|
|
288
|
+
### 内置节点类型
|
|
289
|
+
|
|
290
|
+
不传 `nodeTypes` 参数时,默认包含 7 种节点:
|
|
291
|
+
|
|
292
|
+
| 类型 | 标签 | 尺寸 |
|
|
293
|
+
| ------------------------------ | ------------ | -------- |
|
|
294
|
+
| `start` | 开始 | 88 × 40 |
|
|
295
|
+
| `end` | 结束 | 88 × 40 |
|
|
296
|
+
| `empty` | 空节点 | 240 × 48 |
|
|
297
|
+
| `parallel-gateway` | 并行网关 | 64 × 64 |
|
|
298
|
+
| `branch-gateway` | 分支网关 | 64 × 64 |
|
|
299
|
+
| `converge-gateway` | 汇聚网关 | 64 × 64 |
|
|
300
|
+
| `conditional-parallel-gateway` | 条件并行网关 | 64 × 64 |
|
|
301
|
+
|
|
302
|
+
每种节点均使用内置 `DefaultNode` 组件渲染,自带上/右/下/左四个连接端口。
|
|
303
|
+
|
|
304
|
+
自定义节点类型列表:
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
const { schema, paletteItems } = createDefaultSchema({
|
|
308
|
+
nodeTypes: {
|
|
309
|
+
task: { label: '任务节点', width: 180, height: 60 },
|
|
310
|
+
approval: { label: '审批节点', icon: 'my-icon-class', width: 200, height: 60 },
|
|
311
|
+
notification: { label: '通知节点', width: 160, height: 50 },
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### 连线类型配置
|
|
317
|
+
|
|
318
|
+
`createDefaultSchema` 内置两种连线类型:
|
|
319
|
+
|
|
320
|
+
| 类型 | 路由 | 连接器 | 说明 |
|
|
321
|
+
| ------------------- | ----------- | ---------------------- | --------------------- |
|
|
322
|
+
| `manhattan`(默认) | `manhattan` | `rounded`(radius: 8) | 直角折线,圆角转弯 |
|
|
323
|
+
| `bezier` | 无 | `smooth` | 贝塞尔曲线,平滑 S 形 |
|
|
324
|
+
|
|
325
|
+
**切换为贝塞尔曲线连线:**
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
const { schema, paletteItems } = createDefaultSchema({
|
|
329
|
+
defaultEdgeType: 'bezier',
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**使用自定义边类型:**
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
const { schema, paletteItems } = createDefaultSchema({
|
|
337
|
+
defaultEdgeType: 'myEdge',
|
|
338
|
+
edgeTypes: {
|
|
339
|
+
myEdge: {
|
|
340
|
+
connector: 'normal',
|
|
341
|
+
style: (_edge, state) => ({
|
|
342
|
+
stroke: state.hovered ? 'red' : 'gray',
|
|
343
|
+
strokeWidth: 2,
|
|
344
|
+
}),
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**手动定义边类型(不使用 `createDefaultSchema`):**
|
|
351
|
+
|
|
352
|
+
在手动编写 `CanvasSchema` 时,同样可以通过 `edgeTypes` 和 `defaultEdgeType` 配置连线样式:
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
const schema: CanvasSchema = {
|
|
356
|
+
nodeTypes: {
|
|
357
|
+
/* ... */
|
|
358
|
+
},
|
|
359
|
+
edgeTypes: {
|
|
360
|
+
bezier: {
|
|
361
|
+
connector: { name: 'smooth' },
|
|
362
|
+
style: (_edge, state) => ({
|
|
363
|
+
stroke: state.hovered ? '#3a84ff' : '#abb5cc',
|
|
364
|
+
strokeWidth: 2,
|
|
365
|
+
}),
|
|
366
|
+
x6EdgeConfig: {
|
|
367
|
+
attrs: {
|
|
368
|
+
line: {
|
|
369
|
+
stroke: '#abb5cc',
|
|
370
|
+
strokeWidth: 2,
|
|
371
|
+
targetMarker: { name: 'block', width: 8, height: 8 },
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
manhattan: {
|
|
377
|
+
router: { name: 'manhattan', args: { padding: 10, maxDirectionChange: 90 } },
|
|
378
|
+
connector: { name: 'rounded', args: { radius: 8 } },
|
|
379
|
+
style: (_edge, state) => ({
|
|
380
|
+
stroke: state.hovered ? '#3a84ff' : '#abb5cc',
|
|
381
|
+
strokeWidth: 2,
|
|
382
|
+
}),
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
defaultEdgeType: 'bezier',
|
|
386
|
+
};
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### 默认连线与端口样式
|
|
390
|
+
|
|
391
|
+
- **端口**:半径 6px,背景 `#3a84ff`,1px 白色描边。默认隐藏(`visibility: hidden`),hover 节点时显示;拖拽连线时自动显示所有节点端口。
|
|
392
|
+
- **连线**:宽度 2px,颜色 `#abb5cc`,hover 变 `#3a84ff`,平角箭头(`block` marker)。`zIndex: -1` 确保在节点下方,不阻挡端口交互。
|
|
393
|
+
- **连接点**:`connectionPoint: 'anchor'` + `anchor: 'center'`,连线直达端口中心,紧贴节点。
|
|
394
|
+
|
|
395
|
+
<br>
|
|
229
396
|
|
|
230
397
|
## 命令系统
|
|
231
398
|
|
|
232
|
-
所有 FlowModel
|
|
399
|
+
所有 FlowModel 变更必须通过命令执行。每条命令通过 `CommandEnvelope` 包装,一个信封可包含多条原子命令,作为一次事务整体执行(撤销时整体回退)。
|
|
233
400
|
|
|
234
401
|
```typescript
|
|
235
402
|
import { generateId } from '@blueking/flow-canvas';
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
**添加节点和连线:**
|
|
236
406
|
|
|
407
|
+
```typescript
|
|
237
408
|
editor.executeCommand({
|
|
238
409
|
id: generateId(),
|
|
239
410
|
source: 'user:panel',
|
|
240
411
|
label: '添加节点',
|
|
241
412
|
timestamp: Date.now(),
|
|
242
413
|
commands: [
|
|
243
|
-
{ type: 'node.add', node: { id: 'n1', type: 'task', position: { x: 100, y: 100 } } },
|
|
244
|
-
{
|
|
414
|
+
{ type: 'node.add', node: { id: 'n1', type: 'task', position: { x: 100, y: 100 }, label: '审批' } },
|
|
415
|
+
{
|
|
416
|
+
type: 'edge.add',
|
|
417
|
+
edge: { id: 'e1', source: { nodeId: 'n0', portId: 'right' }, target: { nodeId: 'n1', portId: 'left' } },
|
|
418
|
+
},
|
|
419
|
+
],
|
|
420
|
+
});
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**删除节点(自动级联删除关联边):**
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
editor.executeCommand({
|
|
427
|
+
id: generateId(),
|
|
428
|
+
source: 'user:panel',
|
|
429
|
+
label: '删除节点',
|
|
430
|
+
timestamp: Date.now(),
|
|
431
|
+
commands: [{ type: 'node.remove', nodeId: 'n1' }],
|
|
432
|
+
});
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**删除连线:**
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
editor.executeCommand({
|
|
439
|
+
id: generateId(),
|
|
440
|
+
source: 'user:panel',
|
|
441
|
+
label: '删除连线',
|
|
442
|
+
timestamp: Date.now(),
|
|
443
|
+
commands: [{ type: 'edge.remove', edgeId: 'e1' }],
|
|
444
|
+
});
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**移动节点:**
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
editor.executeCommand({
|
|
451
|
+
id: generateId(),
|
|
452
|
+
source: 'user:panel',
|
|
453
|
+
label: '移动节点',
|
|
454
|
+
timestamp: Date.now(),
|
|
455
|
+
commands: [{ type: 'node.move', nodeId: 'n1', position: { x: 300, y: 200 } }],
|
|
456
|
+
});
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**更新节点结构字段(label、type、ports 等,不含 payload/extensions):**
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
editor.executeCommand({
|
|
463
|
+
id: generateId(),
|
|
464
|
+
source: 'user:panel',
|
|
465
|
+
label: '重命名节点',
|
|
466
|
+
timestamp: Date.now(),
|
|
467
|
+
commands: [{ type: 'node.update', nodeId: 'n1', patch: { label: '新名称' } }],
|
|
468
|
+
});
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**按路径更新节点 payload(业务数据):**
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
// 设置 payload.config.timeout = 30
|
|
475
|
+
editor.executeCommand({
|
|
476
|
+
id: generateId(),
|
|
477
|
+
source: 'user:panel',
|
|
478
|
+
label: '更新超时配置',
|
|
479
|
+
timestamp: Date.now(),
|
|
480
|
+
commands: [{ type: 'node.set-payload', nodeId: 'n1', path: ['config', 'timeout'], value: 30 }],
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
// 设置整个 payload.config 对象
|
|
484
|
+
editor.executeCommand({
|
|
485
|
+
id: generateId(),
|
|
486
|
+
source: 'user:panel',
|
|
487
|
+
label: '更新节点配置',
|
|
488
|
+
timestamp: Date.now(),
|
|
489
|
+
commands: [{ type: 'node.set-payload', nodeId: 'n1', path: ['config'], value: { timeout: 30, retryable: true } }],
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// 删除 payload 中的某个字段(value 传 undefined)
|
|
493
|
+
editor.executeCommand({
|
|
494
|
+
id: generateId(),
|
|
495
|
+
source: 'user:panel',
|
|
496
|
+
label: '清除超时配置',
|
|
497
|
+
timestamp: Date.now(),
|
|
498
|
+
commands: [{ type: 'node.set-payload', nodeId: 'n1', path: ['config', 'timeout'], value: undefined }],
|
|
499
|
+
});
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
**重连边端点:**
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
editor.executeCommand({
|
|
506
|
+
id: generateId(),
|
|
507
|
+
source: 'user:panel',
|
|
508
|
+
label: '重连边',
|
|
509
|
+
timestamp: Date.now(),
|
|
510
|
+
commands: [
|
|
511
|
+
{
|
|
512
|
+
type: 'edge.reconnect',
|
|
513
|
+
edgeId: 'e1',
|
|
514
|
+
target: { nodeId: 'n2', portId: 'left' }, // 只改 target,source 不变
|
|
515
|
+
},
|
|
516
|
+
],
|
|
517
|
+
});
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**更新边标签:**
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
editor.executeCommand({
|
|
524
|
+
id: generateId(),
|
|
525
|
+
source: 'user:panel',
|
|
526
|
+
label: '更新边标签',
|
|
527
|
+
timestamp: Date.now(),
|
|
528
|
+
commands: [{ type: 'edge.label.update', edgeId: 'e1', labelId: 'label1', patch: { text: '条件成立' } }],
|
|
529
|
+
});
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
**更新全局 meta:**
|
|
533
|
+
|
|
534
|
+
```typescript
|
|
535
|
+
editor.executeCommand({
|
|
536
|
+
id: generateId(),
|
|
537
|
+
source: 'user:panel',
|
|
538
|
+
label: '更新全局变量',
|
|
539
|
+
timestamp: Date.now(),
|
|
540
|
+
commands: [{ type: 'model.set-meta', path: ['variables', 'env'], value: 'production' }],
|
|
541
|
+
});
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**批量操作(一个信封包含多条命令,一次性执行):**
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
editor.executeCommand({
|
|
548
|
+
id: generateId(),
|
|
549
|
+
source: 'user:panel',
|
|
550
|
+
label: '批量删除选中',
|
|
551
|
+
timestamp: Date.now(),
|
|
552
|
+
commands: [
|
|
553
|
+
{ type: 'edge.remove', edgeId: 'e1' },
|
|
554
|
+
{ type: 'edge.remove', edgeId: 'e2' },
|
|
555
|
+
{ type: 'node.remove', nodeId: 'n1' },
|
|
556
|
+
{ type: 'node.remove', nodeId: 'n2' },
|
|
245
557
|
],
|
|
246
558
|
});
|
|
247
559
|
```
|
|
248
560
|
|
|
561
|
+
**处理命令执行结果:**
|
|
562
|
+
|
|
563
|
+
```typescript
|
|
564
|
+
const result = editor.executeCommand({
|
|
565
|
+
/* ... */
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
if (result.status === 'applied') {
|
|
569
|
+
console.log('执行成功,新模型:', result.flowModel);
|
|
570
|
+
} else if (result.status === 'rejected') {
|
|
571
|
+
console.warn('被插件拒绝:', result.error?.reason);
|
|
572
|
+
} else if (result.status === 'invalid') {
|
|
573
|
+
console.error('违反约束:', result.error?.reason);
|
|
574
|
+
}
|
|
575
|
+
```
|
|
576
|
+
|
|
249
577
|
### 命令类型一览
|
|
250
578
|
|
|
251
579
|
| 命令 | 说明 |
|
|
@@ -270,7 +598,7 @@ editor.executeCommand({
|
|
|
270
598
|
|
|
271
599
|
`'user:drag'` | `'user:keyboard'` | `'user:toolbar'` | `'user:quick-add'` | `'user:panel'` | `'plugin'` | `'system'` | `'system:replace'`
|
|
272
600
|
|
|
273
|
-
|
|
601
|
+
<br>
|
|
274
602
|
|
|
275
603
|
## 组件
|
|
276
604
|
|
|
@@ -291,7 +619,6 @@ editor.executeCommand({
|
|
|
291
619
|
|
|
292
620
|
| Slot | Props | 说明 |
|
|
293
621
|
| --------------- | ------------------------------------------------ | ----------------------------------------------------------- |
|
|
294
|
-
| node-overlay | `{ node, screenAnchors, api }` | 节点悬浮层,鼠标移入节点时显示 |
|
|
295
622
|
| quick-add-panel | `{ node, api, insertNodeToRight, closePopover }` | 快捷添加弹层内容,点击右侧"+"按钮时显示(默认显示提示文字) |
|
|
296
623
|
|
|
297
624
|
#### 节点快捷操作工具栏
|
|
@@ -317,25 +644,26 @@ editor.executeCommand({
|
|
|
317
644
|
|
|
318
645
|
通过 schema `getBehavior` 返回值控制每个节点类型的工具栏行为:
|
|
319
646
|
|
|
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` → 调试按钮置灰
|
|
647
|
+
| 属性 | 说明 |
|
|
648
|
+
| -------------------- | --------------------------------------------------------------------------------- |
|
|
649
|
+
| `showActions` | `false` → 该节点类型不显示整个工具栏 |
|
|
650
|
+
| `deletable` | `false` → 隐藏删除按钮 |
|
|
651
|
+
| `copyable` | `false` → 隐藏复制和复制并插入按钮 |
|
|
652
|
+
| `disconnectable` | `false` → 隐藏断开连线按钮 |
|
|
653
|
+
| `debuggable` | `false` → 隐藏调试按钮(需全局 `showDebug` 也为 `true`) |
|
|
654
|
+
| `deleteDisabled` | `true` → 删除按钮可见但置灰不可点击 |
|
|
655
|
+
| `copyDisabled` | `true` → 复制按钮置灰 |
|
|
656
|
+
| `copyInsertDisabled` | `true` → 复制并插入按钮置灰 |
|
|
657
|
+
| `disconnectDisabled` | `true` → 断开连线按钮置灰 |
|
|
658
|
+
| `debugDisabled` | `true` → 调试按钮置灰 |
|
|
659
|
+
| `actionsOffset` | `{ x?: number; y?: number }` — 工具栏位置偏移(px),相对于默认位置(节点右下角) |
|
|
332
660
|
|
|
333
661
|
按钮有效可见性 = 全局 `show*` AND 逐节点 `*able !== false`;
|
|
334
662
|
按钮禁用状态 = 逐节点 `*Disabled === true`。
|
|
335
663
|
|
|
336
664
|
操作触发后通过 `@ui-event` 发出对应事件:`node.action.delete` / `node.action.copy` / `node.action.copy-insert` / `node.action.disconnect` / `node.action.debug`。
|
|
337
665
|
|
|
338
|
-
####
|
|
666
|
+
#### 节点快捷添加按钮(Quick Add)
|
|
339
667
|
|
|
340
668
|
hover 节点时,右侧端口显示为"+"按钮,支持点击弹出面板和拖拽发起连线。通过 `quickAdd` prop 进行全局配置:
|
|
341
669
|
|
|
@@ -373,22 +701,223 @@ hover 节点时,右侧端口显示为"+"按钮,支持点击弹出面板和
|
|
|
373
701
|
|
|
374
702
|
操作触发后通过 `@ui-event` 发出对应事件:`node.quick-add`(弹层打开时)/ `node.action.quick-insert`(插入成功时)。
|
|
375
703
|
|
|
704
|
+
**完整的 quick-add-panel 使用示例:**
|
|
705
|
+
|
|
706
|
+
```vue
|
|
707
|
+
<template>
|
|
708
|
+
<CanvasLayout :editor="editor" :palette-items="paletteItems">
|
|
709
|
+
<CanvasRuntime :editor="editor" :quick-add="{ enabled: true }" @ui-event="handleUiEvent">
|
|
710
|
+
<template #quick-add-panel="{ node, insertNodeToRight, closePopover }">
|
|
711
|
+
<div class="quick-add-menu">
|
|
712
|
+
<div class="quick-add-menu__title">选择节点类型</div>
|
|
713
|
+
<div
|
|
714
|
+
v-for="item in quickAddNodeList"
|
|
715
|
+
:key="item.type"
|
|
716
|
+
class="quick-add-menu__item"
|
|
717
|
+
@click="handleQuickAdd(item, insertNodeToRight, closePopover)">
|
|
718
|
+
<i :class="item.icon" />
|
|
719
|
+
<span>{{ item.label }}</span>
|
|
720
|
+
</div>
|
|
721
|
+
</div>
|
|
722
|
+
</template>
|
|
723
|
+
</CanvasRuntime>
|
|
724
|
+
<CanvasToolbar :editor="editor" />
|
|
725
|
+
</CanvasLayout>
|
|
726
|
+
</template>
|
|
727
|
+
|
|
728
|
+
<script setup lang="ts">
|
|
729
|
+
import {
|
|
730
|
+
useCanvasEditor,
|
|
731
|
+
CanvasRuntime,
|
|
732
|
+
CanvasLayout,
|
|
733
|
+
CanvasToolbar,
|
|
734
|
+
createDefaultSchema,
|
|
735
|
+
createEmptyFlowModel,
|
|
736
|
+
generateId,
|
|
737
|
+
type FlowNodeModel,
|
|
738
|
+
} from '@blueking/flow-canvas';
|
|
739
|
+
import '@blueking/flow-canvas/style';
|
|
740
|
+
|
|
741
|
+
const { schema, paletteItems } = createDefaultSchema();
|
|
742
|
+
const editor = useCanvasEditor({ initialFlowModel: createEmptyFlowModel(), schema });
|
|
743
|
+
|
|
744
|
+
const quickAddNodeList = [
|
|
745
|
+
{ type: 'empty', label: '空节点', icon: 'flow-canvas-icon canvas-jiedi' },
|
|
746
|
+
{ type: 'parallel-gateway', label: '并行网关', icon: 'flow-canvas-icon canvas-bingxingwangguan' },
|
|
747
|
+
];
|
|
748
|
+
|
|
749
|
+
function handleQuickAdd(
|
|
750
|
+
item: { type: string; label: string },
|
|
751
|
+
insertNodeToRight: (node: Omit<FlowNodeModel, 'position'>) => void,
|
|
752
|
+
closePopover: () => void,
|
|
753
|
+
) {
|
|
754
|
+
insertNodeToRight({
|
|
755
|
+
id: generateId(),
|
|
756
|
+
type: item.type,
|
|
757
|
+
label: item.label,
|
|
758
|
+
});
|
|
759
|
+
closePopover();
|
|
760
|
+
}
|
|
761
|
+
</script>
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
通过 `getBehavior` 可动态控制哪些节点显示"+"按钮:
|
|
765
|
+
|
|
766
|
+
```typescript
|
|
767
|
+
const schema: CanvasSchema = {
|
|
768
|
+
nodeTypes: {
|
|
769
|
+
end: {
|
|
770
|
+
component: EndNode,
|
|
771
|
+
getSize: () => ({ width: 88, height: 40 }),
|
|
772
|
+
getBehavior: () => ({
|
|
773
|
+
quickAddEnabled: false, // 结束节点不显示"+"按钮
|
|
774
|
+
deletable: false,
|
|
775
|
+
}),
|
|
776
|
+
},
|
|
777
|
+
task: {
|
|
778
|
+
component: TaskNode,
|
|
779
|
+
getSize: () => ({ width: 180, height: 60 }),
|
|
780
|
+
getBehavior: (node, ctx) => {
|
|
781
|
+
const hasOutEdge = Object.values(ctx.flowModel.edges).some((e) => e.source.nodeId === node.id);
|
|
782
|
+
return {
|
|
783
|
+
quickAddEnabled: !hasOutEdge, // 已有出边时隐藏"+"按钮
|
|
784
|
+
};
|
|
785
|
+
},
|
|
786
|
+
},
|
|
787
|
+
},
|
|
788
|
+
};
|
|
789
|
+
```
|
|
790
|
+
|
|
376
791
|
### CanvasLayout
|
|
377
792
|
|
|
378
|
-
|
|
793
|
+
可选的布局骨架组件,提供侧边栏 + 主画布 + 底栏的三栏布局。
|
|
794
|
+
|
|
795
|
+
| Prop | 类型 | 默认 | 说明 |
|
|
796
|
+
| ---------------- | --------------------- | ----------- | ---------------------------------------------------- |
|
|
797
|
+
| sidebarCollapsed | `boolean` | `false` | 侧边栏是否收起 |
|
|
798
|
+
| sidebarWidth | `number` | `260` | 侧边栏宽度(px) |
|
|
799
|
+
| hideSidebar | `boolean` | `false` | 是否隐藏侧边栏 |
|
|
800
|
+
| hideFooter | `boolean` | `false` | 是否隐藏底部栏 |
|
|
801
|
+
| editor | `CanvasEditorContext` | `undefined` | 编辑器实例,传入后自动渲染内置 `CanvasNodePalette` |
|
|
802
|
+
| paletteItems | `NodePaletteItem[]` | `undefined` | 节点面板项列表,配合 `editor` 使用自定义面板节点列表 |
|
|
803
|
+
|
|
804
|
+
| Emit | 参数 | 说明 |
|
|
805
|
+
| ----------------------- | --------- | ------------------ |
|
|
806
|
+
| update:sidebarCollapsed | `boolean` | 侧边栏收起状态变更 |
|
|
807
|
+
|
|
808
|
+
| Slot | 说明 |
|
|
809
|
+
| ------- | --------------------------------------------------------- |
|
|
810
|
+
| sidebar | 侧边栏内容(传入后覆盖内置 `CanvasNodePalette` 默认面板) |
|
|
811
|
+
| default | 主画布区域(放置 `CanvasRuntime` + `CanvasToolbar`) |
|
|
812
|
+
| footer | 底部栏 |
|
|
379
813
|
|
|
380
|
-
|
|
381
|
-
| ---------------- | --------- | ------- | -------------- |
|
|
382
|
-
| sidebarCollapsed | `boolean` | `false` | 侧边栏是否收起 |
|
|
383
|
-
| sidebarWidth | `number` | `260` | 侧边栏宽度 |
|
|
384
|
-
| hideSidebar | `boolean` | `false` | 是否隐藏侧边栏 |
|
|
385
|
-
| hideFooter | `boolean` | `false` | 是否隐藏底部栏 |
|
|
814
|
+
#### 侧边栏的三种使用方式
|
|
386
815
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
816
|
+
**方式一:自动渲染内置节点面板**
|
|
817
|
+
|
|
818
|
+
传入 `editor` prop 且不提供 `sidebar` slot,`CanvasLayout` 自动在侧边栏渲染 `CanvasNodePalette`,用户可从面板拖拽节点到画布:
|
|
819
|
+
|
|
820
|
+
```vue
|
|
821
|
+
<CanvasLayout :editor="editor" :palette-items="paletteItems">
|
|
822
|
+
<CanvasRuntime :editor="editor" />
|
|
823
|
+
</CanvasLayout>
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
通过 `paletteItems` prop 自定义面板中显示的节点类型列表:
|
|
827
|
+
|
|
828
|
+
```vue
|
|
829
|
+
<script setup lang="ts">
|
|
830
|
+
import { createDefaultSchema, useCanvasEditor, createEmptyFlowModel } from '@blueking/flow-canvas';
|
|
831
|
+
|
|
832
|
+
const { schema, paletteItems } = createDefaultSchema();
|
|
833
|
+
const editor = useCanvasEditor({ initialFlowModel: createEmptyFlowModel(), schema });
|
|
834
|
+
|
|
835
|
+
// 也可以手动指定面板项,只展示部分节点类型
|
|
836
|
+
const customPaletteItems = [
|
|
837
|
+
{ type: 'start', label: '开始节点', icon: 'flow-canvas-icon canvas-kaishi' },
|
|
838
|
+
{ type: 'end', label: '结束节点', icon: 'flow-canvas-icon canvas-stop' },
|
|
839
|
+
{ type: 'empty', label: '空节点', icon: 'flow-canvas-icon canvas-jiedi' },
|
|
840
|
+
];
|
|
841
|
+
</script>
|
|
842
|
+
|
|
843
|
+
<template>
|
|
844
|
+
<CanvasLayout :editor="editor" :palette-items="customPaletteItems">
|
|
845
|
+
<CanvasRuntime :editor="editor" />
|
|
846
|
+
</CanvasLayout>
|
|
847
|
+
</template>
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
**方式二:通过 sidebar slot 完全自定义侧边栏**
|
|
851
|
+
|
|
852
|
+
```vue
|
|
853
|
+
<template>
|
|
854
|
+
<CanvasLayout>
|
|
855
|
+
<template #sidebar>
|
|
856
|
+
<div class="my-sidebar">
|
|
857
|
+
<h3>节点库</h3>
|
|
858
|
+
<div v-for="item in nodeItems" :key="item.type" ref="dndRefs" class="my-sidebar__item" :data-type="item.type">
|
|
859
|
+
{{ item.label }}
|
|
860
|
+
</div>
|
|
861
|
+
</div>
|
|
862
|
+
</template>
|
|
863
|
+
<CanvasRuntime :editor="editor" />
|
|
864
|
+
</CanvasLayout>
|
|
865
|
+
</template>
|
|
866
|
+
|
|
867
|
+
<script setup lang="ts">
|
|
868
|
+
import { ref, watch } from 'vue';
|
|
869
|
+
import { useCanvasEditor, CanvasRuntime, CanvasLayout, generateId } from '@blueking/flow-canvas';
|
|
870
|
+
|
|
871
|
+
const nodeItems = [
|
|
872
|
+
{ type: 'task', label: '任务' },
|
|
873
|
+
{ type: 'approval', label: '审批' },
|
|
874
|
+
];
|
|
875
|
+
|
|
876
|
+
// 通过 api.registerDndSource 注册拖拽源
|
|
877
|
+
watch(
|
|
878
|
+
() => editor.api.value,
|
|
879
|
+
(api) => {
|
|
880
|
+
if (!api) return;
|
|
881
|
+
for (const item of nodeItems) {
|
|
882
|
+
const el = document.querySelector(`[data-type="${item.type}"]`);
|
|
883
|
+
if (el) {
|
|
884
|
+
api.registerDndSource(el as HTMLElement, () => ({
|
|
885
|
+
id: generateId(),
|
|
886
|
+
type: item.type,
|
|
887
|
+
label: item.label,
|
|
888
|
+
position: { x: 0, y: 0 },
|
|
889
|
+
}));
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
},
|
|
893
|
+
);
|
|
894
|
+
</script>
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
**方式三:隐藏侧边栏**
|
|
898
|
+
|
|
899
|
+
```vue
|
|
900
|
+
<CanvasLayout hide-sidebar>
|
|
901
|
+
<CanvasRuntime :editor="editor" />
|
|
902
|
+
</CanvasLayout>
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
### CanvasNodePalette
|
|
906
|
+
|
|
907
|
+
内置的节点面板组件,支持拖拽节点到画布(DnD)。通常由 `CanvasLayout` 自动渲染,也可以单独使用。
|
|
908
|
+
|
|
909
|
+
| Prop | 类型 | 必填 | 说明 |
|
|
910
|
+
| ------ | --------------------- | ---- | ---------------------------------------- |
|
|
911
|
+
| editor | `CanvasEditorContext` | 是 | 编辑器实例 |
|
|
912
|
+
| items | `NodePaletteItem[]` | 否 | 节点列表,不传时从 schema.nodeTypes 生成 |
|
|
913
|
+
|
|
914
|
+
```typescript
|
|
915
|
+
interface NodePaletteItem {
|
|
916
|
+
type: string; // 节点类型,对应 schema.nodeTypes 的 key
|
|
917
|
+
label: string; // 显示名称
|
|
918
|
+
icon?: string; // CSS 图标类名
|
|
919
|
+
}
|
|
920
|
+
```
|
|
392
921
|
|
|
393
922
|
### CanvasToolbar
|
|
394
923
|
|
|
@@ -404,12 +933,20 @@ hover 节点时,右侧端口显示为"+"按钮,支持点击弹出面板和
|
|
|
404
933
|
|
|
405
934
|
工厂函数,用于获取默认工具栏项列表,便于自定义组合。
|
|
406
935
|
|
|
936
|
+
撤销/重做(`undo` / `redo`)默认隐藏,可通过 `include` 恢复显示。
|
|
937
|
+
|
|
407
938
|
```typescript
|
|
408
939
|
import { createDefaultToolbarItems } from '@blueking/flow-canvas';
|
|
409
940
|
|
|
410
|
-
//
|
|
411
|
-
const items =
|
|
412
|
-
|
|
941
|
+
// 默认不含撤销/重做
|
|
942
|
+
const items = createDefaultToolbarItems();
|
|
943
|
+
|
|
944
|
+
// 恢复显示撤销/重做
|
|
945
|
+
const itemsWithHistory = createDefaultToolbarItems({ include: ['undo', 'redo'] });
|
|
946
|
+
|
|
947
|
+
// 恢复撤销/重做,同时排除搜索,追加自定义项
|
|
948
|
+
const customItems = [
|
|
949
|
+
...createDefaultToolbarItems({ include: ['undo', 'redo'], exclude: ['search'] }),
|
|
413
950
|
{ id: 'my-tool', type: 'custom', icon: 'my-icon-class', onClick: handleClick },
|
|
414
951
|
];
|
|
415
952
|
```
|
|
@@ -426,7 +963,115 @@ const items = [
|
|
|
426
963
|
| description | `string` | 操作说明,有值时 hover 显示 tooltip 气泡 |
|
|
427
964
|
| onClick | `(ctx: CanvasCallbackContext) => void` | 点击回调 |
|
|
428
965
|
|
|
429
|
-
|
|
966
|
+
<br>
|
|
967
|
+
|
|
968
|
+
## 自定义节点组件
|
|
969
|
+
|
|
970
|
+
节点的渲染由 `CanvasNodeDefinition.component` 指定的 Vue 组件控制。组件内可通过 `inject('getNode')` 获取 X6 Node 实例,读取 FlowNodeModel 数据。
|
|
971
|
+
|
|
972
|
+
### 基础节点组件
|
|
973
|
+
|
|
974
|
+
```vue
|
|
975
|
+
<!-- my-task-node.vue -->
|
|
976
|
+
<template>
|
|
977
|
+
<div class="my-task-node" :class="{ 'is-selected': selected }">
|
|
978
|
+
<i v-if="icon" :class="icon" class="my-task-node__icon" />
|
|
979
|
+
<span class="my-task-node__label">{{ label }}</span>
|
|
980
|
+
</div>
|
|
981
|
+
</template>
|
|
982
|
+
|
|
983
|
+
<script setup lang="ts">
|
|
984
|
+
import { inject, ref, onMounted, onBeforeUnmount, computed } from 'vue';
|
|
985
|
+
import type { FlowNodeModel } from '@blueking/flow-canvas';
|
|
986
|
+
|
|
987
|
+
const getNode = inject<() => any>('getNode')!;
|
|
988
|
+
|
|
989
|
+
const nodeModel = ref<FlowNodeModel>();
|
|
990
|
+
const selected = ref(false);
|
|
991
|
+
|
|
992
|
+
const label = computed(() => nodeModel.value?.label ?? '');
|
|
993
|
+
const icon = computed(() => (nodeModel.value?.extensions as any)?.icon ?? '');
|
|
994
|
+
|
|
995
|
+
onMounted(() => {
|
|
996
|
+
const node = getNode();
|
|
997
|
+
nodeModel.value = node.getData() as FlowNodeModel;
|
|
998
|
+
|
|
999
|
+
node.on('change:data', ({ current }: { current: FlowNodeModel }) => {
|
|
1000
|
+
nodeModel.value = current;
|
|
1001
|
+
});
|
|
1002
|
+
});
|
|
1003
|
+
</script>
|
|
1004
|
+
|
|
1005
|
+
<style scoped>
|
|
1006
|
+
.my-task-node {
|
|
1007
|
+
display: flex;
|
|
1008
|
+
align-items: center;
|
|
1009
|
+
gap: 8px;
|
|
1010
|
+
width: 100%;
|
|
1011
|
+
height: 100%;
|
|
1012
|
+
padding: 0 16px;
|
|
1013
|
+
background: #fff;
|
|
1014
|
+
border: 1px solid #dcdee5;
|
|
1015
|
+
border-radius: 4px;
|
|
1016
|
+
box-sizing: border-box;
|
|
1017
|
+
cursor: pointer;
|
|
1018
|
+
}
|
|
1019
|
+
.my-task-node.is-selected {
|
|
1020
|
+
border-color: #3a84ff;
|
|
1021
|
+
}
|
|
1022
|
+
</style>
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
### 在 Schema 中注册节点组件
|
|
1026
|
+
|
|
1027
|
+
```typescript
|
|
1028
|
+
import MyTaskNode from './components/my-task-node.vue';
|
|
1029
|
+
import MyGatewayNode from './components/my-gateway-node.vue';
|
|
1030
|
+
|
|
1031
|
+
const schema: CanvasSchema = {
|
|
1032
|
+
nodeTypes: {
|
|
1033
|
+
task: {
|
|
1034
|
+
component: MyTaskNode,
|
|
1035
|
+
getSize: () => ({ width: 180, height: 60 }),
|
|
1036
|
+
getPorts: () => [
|
|
1037
|
+
{ id: 'left', group: 'left' },
|
|
1038
|
+
{ id: 'right', group: 'right' },
|
|
1039
|
+
],
|
|
1040
|
+
getBehavior: (node, ctx) => ({
|
|
1041
|
+
deletable: true,
|
|
1042
|
+
copyable: true,
|
|
1043
|
+
quickAddEnabled: true,
|
|
1044
|
+
}),
|
|
1045
|
+
},
|
|
1046
|
+
gateway: {
|
|
1047
|
+
component: MyGatewayNode,
|
|
1048
|
+
getSize: () => ({ width: 64, height: 64 }),
|
|
1049
|
+
getPorts: () => [
|
|
1050
|
+
{ id: 'top', group: 'top' },
|
|
1051
|
+
{ id: 'right', group: 'right' },
|
|
1052
|
+
{ id: 'bottom', group: 'bottom' },
|
|
1053
|
+
{ id: 'left', group: 'left' },
|
|
1054
|
+
],
|
|
1055
|
+
getBehavior: () => ({
|
|
1056
|
+
copyable: false,
|
|
1057
|
+
showActions: true,
|
|
1058
|
+
}),
|
|
1059
|
+
},
|
|
1060
|
+
},
|
|
1061
|
+
edgeTypes: {
|
|
1062
|
+
default: {
|
|
1063
|
+
connector: { name: 'smooth' },
|
|
1064
|
+
style: (_edge, state) => ({
|
|
1065
|
+
stroke: state.hovered ? '#3a84ff' : '#abb5cc',
|
|
1066
|
+
strokeWidth: 2,
|
|
1067
|
+
}),
|
|
1068
|
+
},
|
|
1069
|
+
},
|
|
1070
|
+
defaultEdgeType: 'default',
|
|
1071
|
+
};
|
|
1072
|
+
```
|
|
1073
|
+
|
|
1074
|
+
<br>
|
|
430
1075
|
|
|
431
1076
|
## CanvasApi
|
|
432
1077
|
|
|
@@ -456,7 +1101,7 @@ const items = [
|
|
|
456
1101
|
| onGraphEvent(event, handler) | 监听 X6 底层事件,返回取消函数 |
|
|
457
1102
|
| unsafeGetGraph() | 获取 X6 Graph 实例(谨慎使用) |
|
|
458
1103
|
|
|
459
|
-
|
|
1104
|
+
<br>
|
|
460
1105
|
|
|
461
1106
|
## 内置插件
|
|
462
1107
|
|
|
@@ -512,7 +1157,7 @@ minimapPlugin({
|
|
|
512
1157
|
|
|
513
1158
|
Cmd/Ctrl+C 复制选中节点/边,Cmd/Ctrl+V 粘贴(生成新 ID、偏移位置)。
|
|
514
1159
|
|
|
515
|
-
|
|
1160
|
+
<br>
|
|
516
1161
|
|
|
517
1162
|
## 自定义插件
|
|
518
1163
|
|
|
@@ -574,7 +1219,7 @@ const myPlugin: CanvasPlugin = {
|
|
|
574
1219
|
};
|
|
575
1220
|
```
|
|
576
1221
|
|
|
577
|
-
|
|
1222
|
+
<br>
|
|
578
1223
|
|
|
579
1224
|
## 工具函数与底层 API
|
|
580
1225
|
|
|
@@ -594,7 +1239,7 @@ const emptyModel = createEmptyFlowModel();
|
|
|
594
1239
|
// { version: '1.0', nodes: {}, edges: {} }
|
|
595
1240
|
```
|
|
596
1241
|
|
|
597
|
-
|
|
1242
|
+
<br>
|
|
598
1243
|
|
|
599
1244
|
## 撤销/重做
|
|
600
1245
|
|
|
@@ -606,7 +1251,7 @@ editor.history.canRedo.value; // boolean
|
|
|
606
1251
|
editor.history.clear();
|
|
607
1252
|
```
|
|
608
1253
|
|
|
609
|
-
|
|
1254
|
+
<br>
|
|
610
1255
|
|
|
611
1256
|
## 事件类型 (CanvasUiEvent)
|
|
612
1257
|
|
|
@@ -628,7 +1273,7 @@ editor.history.clear();
|
|
|
628
1273
|
| node.quick-add | nodeId, position | 快捷添加弹层打开 |
|
|
629
1274
|
| node.action.quick-insert | sourceNodeId, newNodeId | 快捷插入节点 |
|
|
630
1275
|
|
|
631
|
-
|
|
1276
|
+
<br>
|
|
632
1277
|
|
|
633
1278
|
## 公开类型参考
|
|
634
1279
|
|
|
@@ -649,7 +1294,7 @@ editor.history.clear();
|
|
|
649
1294
|
| 类型 | 说明 |
|
|
650
1295
|
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
651
1296
|
| `CanvasSchema` | 画布配置(nodeTypes / edgeTypes) |
|
|
652
|
-
| `CanvasNodeDefinition` | 节点类型定义(component / getSize / getPorts / getBehavior
|
|
1297
|
+
| `CanvasNodeDefinition` | 节点类型定义(component / getSize / getPorts / getBehavior) |
|
|
653
1298
|
| `CanvasEdgeDefinition` | 边类型定义(router / connector / style / labelDraggable)。`labelRenderer` 字段为 `@experimental`,当前未实现 |
|
|
654
1299
|
| `CanvasCallbackContext` | 运行时上下文(api / flowModel / history / mode) |
|
|
655
1300
|
| `CanvasMode` | 模式:`'edit'` / `'readonly'` / `'thumbnail'` |
|
|
@@ -698,6 +1343,16 @@ editor.history.clear();
|
|
|
698
1343
|
| `ConnectionValidator` | 连接校验函数类型 |
|
|
699
1344
|
| `ConnectionValidateContext` | 连接校验上下文 |
|
|
700
1345
|
| `ConnectionValidateResult` | 连接校验结果 |
|
|
1346
|
+
| `NodePaletteItem` | 节点面板项(type / label / icon) |
|
|
1347
|
+
|
|
1348
|
+
### 默认 Schema
|
|
1349
|
+
|
|
1350
|
+
| 类型 | 说明 |
|
|
1351
|
+
| ---------------------------- | ---------------------------------- |
|
|
1352
|
+
| `DefaultNodeTypeConfig` | `createDefaultSchema` 的节点配置项 |
|
|
1353
|
+
| `DefaultSchemaOptions` | `createDefaultSchema` 的选项 |
|
|
1354
|
+
| `DefaultSchemaResult` | `createDefaultSchema` 的返回值 |
|
|
1355
|
+
| `DefaultToolbarItemsOptions` | `createDefaultToolbarItems` 的选项 |
|
|
701
1356
|
|
|
702
1357
|
### 历史与 Overlay
|
|
703
1358
|
|
|
@@ -706,8 +1361,6 @@ editor.history.clear();
|
|
|
706
1361
|
| `CanvasHistory` | 历史管理器接口 |
|
|
707
1362
|
| `CanvasHistoryOptions` | 历史配置(maxHistorySize) |
|
|
708
1363
|
| `OverlayManager` | Overlay 管理器接口 |
|
|
709
|
-
| `NodeOverlayAnchors` | 节点 Overlay 锚点定义 |
|
|
710
|
-
| `OverlayAnchor` | 单个锚点坐标 |
|
|
711
1364
|
|
|
712
1365
|
### 编辑器
|
|
713
1366
|
|