@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
@@ -0,0 +1,11 @@
1
+ import type { FlowModel } from '../types/flow-model';
2
+ import type { CanvasCommand } from '../types/command';
3
+ /**
4
+ * 纯函数 reducer:将一条原子命令应用到 FlowModel 上,返回新 FlowModel(不可变)。
5
+ * 所有 FlowModel 不变量在此处保证:
6
+ * - 节点/边 id 唯一性
7
+ * - 边端点必须指向存在的节点(及可选的 port)
8
+ * - 删除节点时级联清理关联边
9
+ * - label id 在同一条边内唯一
10
+ */
11
+ export declare function applyCanvasCommand(model: FlowModel, cmd: CanvasCommand): FlowModel;
@@ -0,0 +1,50 @@
1
+ import { type Ref } from 'vue';
2
+ import type { FlowModel } from '../types/flow-model';
3
+ import type { CanvasSchema, CanvasMode } from '../types/schema';
4
+ import type { CanvasPlugin } from '../types/plugin';
5
+ import type { CanvasApi, CanvasToolbarItem } from '../types/api';
6
+ import type { CanvasHistory, CanvasHistoryOptions } from '../types/history';
7
+ import type { CommandEnvelope, CommandExecutionResult, FlowModelChangeEvent } from '../types/command';
8
+ import { PluginManager } from './plugin-manager';
9
+ export interface CanvasEditorOptions {
10
+ initialFlowModel: FlowModel;
11
+ schema: CanvasSchema;
12
+ plugins?: CanvasPlugin[];
13
+ mode?: CanvasMode;
14
+ historyOptions?: CanvasHistoryOptions;
15
+ onCommandResult?(result: CommandExecutionResult): void;
16
+ onFlowModelChange?(event: FlowModelChangeEvent): void;
17
+ }
18
+ export interface CanvasEditorContext {
19
+ flowModel: Readonly<Ref<FlowModel>>;
20
+ history: CanvasHistory;
21
+ schema: CanvasSchema;
22
+ mode: Ref<CanvasMode>;
23
+ executeCommand(envelope: CommandEnvelope): CommandExecutionResult;
24
+ replaceFlowModel(model: FlowModel): void;
25
+ setMode(mode: CanvasMode): void;
26
+ /** 框选模式:开启后左键拖拽画布空白区域为框选,关闭时为画布平移 */
27
+ selectionMode: Ref<boolean>;
28
+ setSelectionMode(enabled: boolean): void;
29
+ api: Ref<CanvasApi | null>;
30
+ toolbarItems: Readonly<Ref<CanvasToolbarItem[]>>;
31
+ extendedApi: Record<string, Function>;
32
+ /** @internal used by CanvasRuntime */
33
+ _pluginManager: PluginManager;
34
+ }
35
+ /**
36
+ * 画布编辑引擎的核心 composable。
37
+ *
38
+ * 初始化时完成:
39
+ * 1. 创建 CanvasHistory(快照栈)
40
+ * 2. 安装插件(editor-stage)
41
+ * 3. 暴露 executeCommand / replaceFlowModel / setMode 等 API
42
+ *
43
+ * api(CanvasApi)在 CanvasRuntime mount 后才由 runtime 注入。
44
+ * 在此之前 api.value === null,工具栏等依赖 api 的功能默认禁用。
45
+ *
46
+ * executeCommand 的完整管道:
47
+ * pluginManager.transformCommand → history.execute → applyCanvasCommand
48
+ * → pluginManager.afterCommand → onCommandResult → onFlowModelChange
49
+ */
50
+ export declare function useCanvasEditor(options: CanvasEditorOptions): CanvasEditorContext;
@@ -0,0 +1,6 @@
1
+ export declare class CanvasConstraintError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare class CanvasSchemaError extends Error {
5
+ constructor(message: string);
6
+ }
@@ -0,0 +1,15 @@
1
+ import { type Ref } from 'vue';
2
+ import type { FlowModel } from '../types/flow-model';
3
+ import type { CanvasHistory, CanvasHistoryOptions } from '../types/history';
4
+ /**
5
+ * 基于快照栈的历史系统。
6
+ *
7
+ * 每次 execute 时在 undo 栈中保存执行前的 FlowModel 快照,同时清空 redo 栈。
8
+ * undo 弹出上一个快照恢复 FlowModel;redo 重新执行对应 envelope 的命令序列。
9
+ *
10
+ * 注意:当前实现为完整快照,适用于中小规模 FlowModel。
11
+ * 若 payload 增长导致性能问题,后续可引入结构共享或 checkpoint + patch 混合模式。
12
+ */
13
+ export declare function createCanvasHistory(initialFlowModel: FlowModel, options?: CanvasHistoryOptions): CanvasHistory & {
14
+ currentFlowModel: Ref<FlowModel>;
15
+ };
@@ -0,0 +1,58 @@
1
+ import type { CanvasPlugin, EditorPluginContext, RuntimePluginContext, CanvasSelection, NodeDecoration, EdgeDecoration } from '../types/plugin';
2
+ import type { CommandEnvelope, CanvasUiEvent, ScreenPosition, CommandExecutionError } from '../types/command';
3
+ import type { CanvasToolbarItem } from '../types/api';
4
+ import type { FlowModel, FlowNodeModel, FlowEdgeModel } from '../types/flow-model';
5
+ /**
6
+ * 管理插件的安装、运行时挂载、命令管道和事件分发。
7
+ *
8
+ * 生命周期分两阶段:
9
+ * 1. install(editor 级):在 useCanvasEditor 初始化时调用,此时只有 flowModel/history/schema 可用
10
+ * 2. attachRuntime(runtime 级):在 CanvasRuntime mount 后调用,此时 api/graph/overlay 已就绪
11
+ *
12
+ * 命令管道(transformCommand)为不可变管道:
13
+ * - 插件按 priority 升序执行
14
+ * - 每个插件返回新 envelope 或 null(拒绝)或 CommandRejection
15
+ * - 前一个插件的输出是下一个插件的输入
16
+ */
17
+ export declare class PluginManager {
18
+ private plugins;
19
+ private editorContext;
20
+ private runtimeCtx;
21
+ /** 每次 attachRuntime 递增,detachRuntime 时旧 generation 的异步调用自动作废 */
22
+ private runtimeVersion;
23
+ install(plugins: CanvasPlugin[], ctx: EditorPluginContext): void;
24
+ /**
25
+ * 挂载运行时上下文并调用各插件的 attachRuntime。
26
+ * 异步插件(如动态 import X6 插件)在 await 返回后会检查 generation,
27
+ * 若 detachRuntime 已被调用(generation 已变),则跳过 graph.use() 等操作。
28
+ */
29
+ attachRuntime(ctx: RuntimePluginContext): void;
30
+ /** 按安装的逆序 detach,保证后安装的插件先释放运行时资源 */
31
+ detachRuntime(): void;
32
+ /**
33
+ * 为 attachRuntime 创建保护代理:graph.use() 等可能在异步回调中调用,
34
+ * 如果在 await 期间 detachRuntime 已执行,代理会将 graph 操作变为 no-op。
35
+ */
36
+ private createSafeRuntimeContext;
37
+ dispose(): void;
38
+ transformCommand(envelope: Readonly<CommandEnvelope>): {
39
+ envelope: CommandEnvelope;
40
+ } | {
41
+ rejected: true;
42
+ error: CommandExecutionError;
43
+ };
44
+ afterCommand(envelope: Readonly<CommandEnvelope>, prevModel: Readonly<FlowModel>, newModel: Readonly<FlowModel>): void;
45
+ dispatchUiEvent(event: CanvasUiEvent): void;
46
+ dispatchSelectionChange(selection: CanvasSelection): void;
47
+ dispatchKeyboardShortcut(event: KeyboardEvent): boolean;
48
+ collectContextMenuItems(position: ScreenPosition): import('../types/plugin').ContextMenuItem[];
49
+ /** 汇聚所有插件的工具栏项,相同 id 的后注册覆盖先注册,最终按 order 排序 */
50
+ collectToolbarItems(): CanvasToolbarItem[];
51
+ /** 合并所有插件对某节点的装饰(className / borderColor / badge),后注册覆盖先注册 */
52
+ collectNodeDecorations(node: FlowNodeModel): NodeDecoration | undefined;
53
+ /** 合并所有插件对某边的装饰(className / strokeColor),后注册覆盖先注册 */
54
+ collectEdgeDecorations(edge: FlowEdgeModel): EdgeDecoration | undefined;
55
+ collectExtendedApi(): Record<string, Function>;
56
+ /** 基于当前 FlowModel 和待执行命令序列,生成预览 FlowModel 供 transformCommand 使用 */
57
+ private createPreview;
58
+ }
@@ -0,0 +1,236 @@
1
+ import { View as x, CssLoader as u, Dom as l, Graph as y, FunctionExt as f, Rectangle as E, GeometryUtil as m } from "@antv/x6";
2
+ const G = `.x6-widget-dnd {
3
+ position: absolute;
4
+ top: -10000px;
5
+ left: -10000px;
6
+ z-index: 999999;
7
+ display: none;
8
+ cursor: move;
9
+ opacity: 0.7;
10
+ pointer-events: 'cursor';
11
+ }
12
+ .x6-widget-dnd.dragging {
13
+ display: inline-block;
14
+ }
15
+ .x6-widget-dnd.dragging * {
16
+ pointer-events: none !important;
17
+ }
18
+ .x6-widget-dnd .x6-graph {
19
+ background: transparent;
20
+ box-shadow: none;
21
+ }
22
+ `;
23
+ var v = function(c, e, n, t) {
24
+ var i = arguments.length, s = i < 3 ? e : t === null ? t = Object.getOwnPropertyDescriptor(e, n) : t, a;
25
+ if (typeof Reflect == "object" && typeof Reflect.decorate == "function") s = Reflect.decorate(c, e, n, t);
26
+ else for (var o = c.length - 1; o >= 0; o--) (a = c[o]) && (s = (i < 3 ? a(s) : i > 3 ? a(e, n, s) : a(e, n)) || s);
27
+ return i > 3 && s && Object.defineProperty(e, n, s), s;
28
+ };
29
+ class p extends x {
30
+ get targetScroller() {
31
+ return this.options.target.getPlugin("scroller");
32
+ }
33
+ get targetGraph() {
34
+ return this.options.target;
35
+ }
36
+ get targetModel() {
37
+ return this.targetGraph.model;
38
+ }
39
+ get snapline() {
40
+ return this.options.target.getPlugin("snapline");
41
+ }
42
+ constructor(e) {
43
+ super(), this.name = "dnd", this.options = Object.assign(Object.assign({}, p.defaults), e), this.init();
44
+ }
45
+ init() {
46
+ u.ensure(this.name, G), this.container = document.createElement("div"), l.addClass(this.container, this.prefixClassName("widget-dnd")), this.draggingGraph = new y(Object.assign(Object.assign({}, this.options.delegateGraphOptions), { container: document.createElement("div"), width: 1, height: 1, async: !1 })), l.append(this.container, this.draggingGraph.container);
47
+ }
48
+ start(e, n) {
49
+ const t = n;
50
+ t.preventDefault(), this.targetModel.startBatch("dnd"), l.addClass(this.container, "dragging"), l.appendTo(this.container, this.options.draggingContainer || document.body), this.sourceNode = e, this.prepareDragging(e, t.clientX, t.clientY);
51
+ const i = this.updateNodePosition(t.clientX, t.clientY);
52
+ this.isSnaplineEnabled() && (this.snapline.captureCursorOffset({
53
+ e: t,
54
+ node: e,
55
+ cell: e,
56
+ view: this.draggingView,
57
+ x: i.x,
58
+ y: i.y
59
+ }), this.draggingNode.on("change:position", this.snap, this)), this.delegateDocumentEvents(p.documentEvents, t.data);
60
+ }
61
+ isSnaplineEnabled() {
62
+ return this.snapline && this.snapline.isEnabled();
63
+ }
64
+ prepareDragging(e, n, t) {
65
+ const i = this.draggingGraph, s = i.model, a = this.options.getDragNode(e, {
66
+ sourceNode: e,
67
+ draggingGraph: i,
68
+ targetGraph: this.targetGraph
69
+ });
70
+ a.position(0, 0);
71
+ let o = 5;
72
+ if (this.isSnaplineEnabled() && (o += this.snapline.options.tolerance || 0), this.isSnaplineEnabled() || this.options.scaled) {
73
+ const g = this.targetGraph.transform.getScale();
74
+ i.scale(g.sx, g.sy), o *= Math.max(g.sx, g.sy);
75
+ } else
76
+ i.scale(1, 1);
77
+ this.clearDragging(), s.resetCells([a]);
78
+ const r = i.findViewByCell(a);
79
+ r.undelegateEvents(), r.cell.off("changed"), i.fitToContent({
80
+ padding: o,
81
+ allowNewOrigin: "any",
82
+ useCellGeometry: !1
83
+ });
84
+ const d = r.getBBox();
85
+ this.geometryBBox = r.getBBox({ useCellGeometry: !0 }), this.delta = this.geometryBBox.getTopLeft().diff(d.getTopLeft()), this.draggingNode = a, this.draggingView = r, this.draggingBBox = a.getBBox(), this.padding = o, this.originOffset = this.updateGraphPosition(n, t);
86
+ }
87
+ updateGraphPosition(e, n) {
88
+ const t = document.body.scrollTop || document.documentElement.scrollTop, i = document.body.scrollLeft || document.documentElement.scrollLeft, s = this.delta, a = this.geometryBBox, o = this.padding || 5, r = {
89
+ left: e - s.x - a.width / 2 - o + i,
90
+ top: n - s.y - a.height / 2 - o + t
91
+ };
92
+ return this.draggingGraph && l.css(this.container, {
93
+ left: `${r.left}px`,
94
+ top: `${r.top}px`
95
+ }), r;
96
+ }
97
+ updateNodePosition(e, n) {
98
+ const t = this.targetGraph.clientToLocal(e, n), i = this.draggingBBox;
99
+ return t.x -= i.width / 2, t.y -= i.height / 2, this.draggingNode.position(t.x, t.y), t;
100
+ }
101
+ snap({ cell: e, current: n, options: t }) {
102
+ const i = e;
103
+ if (t.snapped) {
104
+ const s = this.draggingBBox;
105
+ i.position(s.x + t.tx, s.y + t.ty, { silent: !0 }), this.draggingView.translate(), i.position(n.x, n.y, { silent: !0 }), this.snapOffset = {
106
+ x: t.tx,
107
+ y: t.ty
108
+ };
109
+ } else
110
+ this.snapOffset = null;
111
+ }
112
+ onDragging(e) {
113
+ const n = this.draggingView;
114
+ if (n) {
115
+ e.preventDefault();
116
+ const t = this.normalizeEvent(e), i = t.clientX, s = t.clientY;
117
+ this.updateGraphPosition(i, s);
118
+ const a = this.updateNodePosition(i, s), o = this.targetGraph.options.embedding.enabled, r = (o || this.isSnaplineEnabled()) && this.isInsideValidArea({
119
+ x: i,
120
+ y: s
121
+ });
122
+ if (o) {
123
+ n.setEventData(t, {
124
+ graph: this.targetGraph,
125
+ candidateEmbedView: this.candidateEmbedView
126
+ });
127
+ const d = n.getEventData(t);
128
+ r ? n.processEmbedding(t, d) : n.clearEmbedding(d), this.candidateEmbedView = d.candidateEmbedView;
129
+ }
130
+ this.isSnaplineEnabled() && (r ? this.snapline.snapOnMoving({
131
+ e: t,
132
+ view: n,
133
+ x: a.x,
134
+ y: a.y
135
+ }) : this.snapline.hide());
136
+ }
137
+ }
138
+ onDragEnd(e) {
139
+ const n = this.draggingNode;
140
+ if (n) {
141
+ const t = this.normalizeEvent(e), i = this.draggingView, s = this.draggingBBox, a = this.snapOffset;
142
+ let o = s.x, r = s.y;
143
+ a && (o += a.x, r += a.y), n.position(o, r, { silent: !0 });
144
+ const d = this.drop(n, { x: t.clientX, y: t.clientY }), g = (h) => {
145
+ h ? (this.onDropped(n), this.targetGraph.options.embedding.enabled && i && (i.setEventData(t, {
146
+ cell: h,
147
+ graph: this.targetGraph,
148
+ candidateEmbedView: this.candidateEmbedView
149
+ }), i.finalizeEmbedding(t, i.getEventData(t)))) : this.onDropInvalid(), this.candidateEmbedView = null, this.targetModel.stopBatch("dnd");
150
+ };
151
+ f.isAsync(d) ? (this.undelegateDocumentEvents(), d.then(g)) : g(d);
152
+ }
153
+ }
154
+ clearDragging() {
155
+ this.draggingNode && (this.sourceNode = null, this.draggingNode.remove(), this.draggingNode = null, this.draggingView = null, this.delta = null, this.padding = null, this.snapOffset = null, this.originOffset = null, this.undelegateDocumentEvents());
156
+ }
157
+ onDropped(e) {
158
+ this.draggingNode === e && (this.clearDragging(), l.removeClass(this.container, "dragging"), l.remove(this.container));
159
+ }
160
+ onDropInvalid() {
161
+ const e = this.draggingNode;
162
+ e && this.onDropped(e);
163
+ }
164
+ isInsideValidArea(e) {
165
+ let n, t = null;
166
+ const i = this.targetGraph, s = this.targetScroller;
167
+ this.options.dndContainer && (t = this.getDropArea(this.options.dndContainer));
168
+ const a = t && t.containsPoint(e);
169
+ if (s)
170
+ if (s.options.autoResize)
171
+ n = this.getDropArea(s.container);
172
+ else {
173
+ const o = this.getDropArea(s.container);
174
+ n = this.getDropArea(i.container).intersectsWithRect(o);
175
+ }
176
+ else
177
+ n = this.getDropArea(i.container);
178
+ return !a && n && n.containsPoint(e);
179
+ }
180
+ getDropArea(e) {
181
+ const n = l.offset(e), t = document.body.scrollTop || document.documentElement.scrollTop, i = document.body.scrollLeft || document.documentElement.scrollLeft;
182
+ return E.create({
183
+ x: n.left + parseInt(l.css(e, "border-left-width"), 10) - i,
184
+ y: n.top + parseInt(l.css(e, "border-top-width"), 10) - t,
185
+ width: e.clientWidth,
186
+ height: e.clientHeight
187
+ });
188
+ }
189
+ drop(e, n) {
190
+ if (this.isInsideValidArea(n)) {
191
+ const t = this.targetGraph, i = t.model, s = t.clientToLocal(n), a = this.sourceNode, o = this.options.getDropNode(e, {
192
+ sourceNode: a,
193
+ draggingNode: e,
194
+ targetGraph: this.targetGraph,
195
+ draggingGraph: this.draggingGraph
196
+ }), r = o.getBBox();
197
+ s.x += r.x - r.width / 2, s.y += r.y - r.height / 2;
198
+ const d = this.snapOffset ? 1 : t.getGridSize();
199
+ o.position(m.snapToGrid(s.x, d), m.snapToGrid(s.y, d)), o.removeZIndex();
200
+ const g = this.options.validateNode, h = g ? g(o, {
201
+ sourceNode: a,
202
+ draggingNode: e,
203
+ droppingNode: o,
204
+ targetGraph: t,
205
+ draggingGraph: this.draggingGraph
206
+ }) : !0;
207
+ return typeof h == "boolean" ? h ? (i.addCell(o, { stencil: this.cid }), o) : null : f.toDeferredBoolean(h).then((b) => b ? (i.addCell(o, { stencil: this.cid }), o) : null);
208
+ }
209
+ return null;
210
+ }
211
+ onRemove() {
212
+ this.draggingGraph && (this.draggingGraph.view.remove(), this.draggingGraph.dispose());
213
+ }
214
+ dispose() {
215
+ this.remove(), u.clean(this.name);
216
+ }
217
+ }
218
+ v([
219
+ x.dispose()
220
+ ], p.prototype, "dispose", null);
221
+ (function(c) {
222
+ c.defaults = {
223
+ // animation: false,
224
+ getDragNode: (e) => e.clone(),
225
+ getDropNode: (e) => e.clone()
226
+ }, c.documentEvents = {
227
+ mousemove: "onDragging",
228
+ touchmove: "onDragging",
229
+ mouseup: "onDragEnd",
230
+ touchend: "onDragEnd",
231
+ touchcancel: "onDragEnd"
232
+ };
233
+ })(p || (p = {}));
234
+ export {
235
+ p as Dnd
236
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("@antv/x6");a.Graph.prototype.toSVG=function(s,e){const t=this.getPlugin("export");t&&t.toSVG(s,e)};a.Graph.prototype.toPNG=function(s,e){const t=this.getPlugin("export");t&&t.toPNG(s,e)};a.Graph.prototype.toJPEG=function(s,e){const t=this.getPlugin("export");t&&t.toJPEG(s,e)};a.Graph.prototype.exportPNG=function(s,e){const t=this.getPlugin("export");t&&t.exportPNG(s,e)};a.Graph.prototype.exportJPEG=function(s,e){const t=this.getPlugin("export");t&&t.exportJPEG(s,e)};a.Graph.prototype.exportSVG=function(s,e){const t=this.getPlugin("export");t&&t.exportSVG(s,e)};var E=function(s,e,t,r){var i=arguments.length,c=i<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")c=Reflect.decorate(s,e,t,r);else for(var h=s.length-1;h>=0;h--)(d=s[h])&&(c=(i<3?d(c):i>3?d(e,t,c):d(e,t))||c);return i>3&&c&&Object.defineProperty(e,t,c),c};class D extends a.Basecoat{constructor(){super(),this.name="export"}get view(){return this.graph.view}init(e){this.graph=e}exportPNG(e="chart",t={}){this.toPNG(r=>{a.DataUri.downloadDataUri(r,e)},t)}exportJPEG(e="chart",t={}){this.toPNG(r=>{a.DataUri.downloadDataUri(r,e)},t)}exportSVG(e="chart",t={}){this.toSVG(r=>{a.DataUri.downloadDataUri(a.DataUri.svgToDataUrl(r),e)},t)}toSVG(e,t={}){this.notify("before:export",t);const r=this.view.svg,i=a.Vector.create(r).clone();let c=i.node;const d=i.findOne(`.${this.view.prefixClassName("graph-svg-stage")}`),h=t.viewBox||this.graph.graphToLocal(this.graph.getContentBBox()),l=t.preserveDimensions;if(l){const o=typeof l=="boolean"?h:l;i.attr({width:o.width,height:o.height})}if(i.removeAttribute("style").attr("viewBox",[h.x,h.y,h.width,h.height].join(" ")),d.removeAttribute("transform"),t.copyStyles!==!1){const o=r.ownerDocument,f=Array.from(r.querySelectorAll("*")),u=Array.from(c.querySelectorAll("*")),p=o.styleSheets.length,G=[];for(let n=p-1;n>=0;n-=1)G[n]=o.styleSheets[n],o.styleSheets[n].disabled=!0;const x={};f.forEach((n,m)=>{const w=window.getComputedStyle(n,null),P={};Object.keys(w).forEach(S=>{P[S]=w.getPropertyValue(S)}),x[m]=P}),p!==o.styleSheets.length&&G.forEach((n,m)=>{o.styleSheets[m]=n});for(let n=0;n<p;n+=1)o.styleSheets[n].disabled=!1;const v={};f.forEach((n,m)=>{const w=window.getComputedStyle(n,null),P=x[m],S={};Object.keys(w).forEach(b=>{!a.NumberExt.isNumber(b)&&w.getPropertyValue(b)!==P[b]&&(S[b]=w.getPropertyValue(b))}),v[m]=S}),u.forEach((n,m)=>{a.Dom.css(n,v[m])})}const y=t.stylesheet;if(typeof y=="string"){const o=r.ownerDocument.implementation.createDocument(null,"xml",null).createCDATASection(y);i.prepend(a.Vector.create("style",{type:"text/css"},[o]))}const g=()=>{const o=t.beforeSerialize;if(typeof o=="function"){const u=a.FunctionExt.call(o,this.graph,c);u instanceof SVGSVGElement&&(c=u)}const f=new XMLSerializer().serializeToString(c).replace(/&nbsp;/g," ");this.notify("after:export",t),e(f)};if(t.serializeImages){const o=i.find("image").map(f=>new Promise(u=>{const p=f.attr("xlink:href")||f.attr("href");a.DataUri.imageToDataUri(p,(G,x)=>{!G&&x&&f.attr("xlink:href",x),u()})}));Promise.all(o).then(g)}else g()}toDataURL(e,t){let r=t.viewBox||this.graph.getContentBBox();const i=a.NumberExt.normalizeSides(t.padding);t.width&&t.height&&(i.left+i.right>=t.width&&(i.left=i.right=0),i.top+i.bottom>=t.height&&(i.top=i.bottom=0));const c=new a.Rectangle(-i.left,-i.top,i.left+i.right,i.top+i.bottom);if(t.width&&t.height){const g=r.width+i.left+i.right,o=r.height+i.top+i.bottom;c.scale(g/t.width,o/t.height)}r=a.Rectangle.create(r).moveAndExpand(c);const d=typeof t.width=="number"&&typeof t.height=="number"?{width:t.width,height:t.height}:r;let h=t.ratio?parseFloat(t.ratio):1;(!Number.isFinite(h)||h===0)&&(h=1);const l={width:Math.max(Math.round(d.width*h),1),height:Math.max(Math.round(d.height*h),1)};{const g=document.createElement("canvas"),o=g.getContext("2d");g.width=l.width,g.height=l.height;const f=l.width-1,u=l.height-1;o.fillStyle="rgb(1,1,1)",o.fillRect(f,u,1,1);const p=o.getImageData(f,u,1,1).data;if(p[0]!==1||p[1]!==1||p[2]!==1)throw new Error("size exceeded")}const y=new Image;y.onload=()=>{const g=document.createElement("canvas");g.width=l.width,g.height=l.height;const o=g.getContext("2d");o.fillStyle=t.backgroundColor||"white",o.fillRect(0,0,l.width,l.height);try{o.drawImage(y,0,0,l.width,l.height);const f=g.toDataURL(t.type,t.quality);e(f)}catch{}},this.toSVG(g=>{y.src=`data:image/svg+xml,${encodeURIComponent(g)}`},Object.assign(Object.assign({},t),{viewBox:r,serializeImages:!0,preserveDimensions:Object.assign({},l)}))}toPNG(e,t={}){this.toDataURL(e,Object.assign(Object.assign({},t),{type:"image/png"}))}toJPEG(e,t={}){this.toDataURL(e,Object.assign(Object.assign({},t),{type:"image/jpeg"}))}notify(e,t){this.trigger(e,t),this.graph.trigger(e,t)}dispose(){this.off()}}E([a.Basecoat.dispose()],D.prototype,"dispose",null);exports.Export=D;
@@ -0,0 +1,21 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("@antv/x6"),f=`.x6-widget-dnd {
2
+ position: absolute;
3
+ top: -10000px;
4
+ left: -10000px;
5
+ z-index: 999999;
6
+ display: none;
7
+ cursor: move;
8
+ opacity: 0.7;
9
+ pointer-events: 'cursor';
10
+ }
11
+ .x6-widget-dnd.dragging {
12
+ display: inline-block;
13
+ }
14
+ .x6-widget-dnd.dragging * {
15
+ pointer-events: none !important;
16
+ }
17
+ .x6-widget-dnd .x6-graph {
18
+ background: transparent;
19
+ box-shadow: none;
20
+ }
21
+ `;var m=function(h,e,n,t){var i=arguments.length,s=i<3?e:t===null?t=Object.getOwnPropertyDescriptor(e,n):t,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(h,e,n,t);else for(var o=h.length-1;o>=0;o--)(a=h[o])&&(s=(i<3?a(s):i>3?a(e,n,s):a(e,n))||s);return i>3&&s&&Object.defineProperty(e,n,s),s};class c extends d.View{get targetScroller(){return this.options.target.getPlugin("scroller")}get targetGraph(){return this.options.target}get targetModel(){return this.targetGraph.model}get snapline(){return this.options.target.getPlugin("snapline")}constructor(e){super(),this.name="dnd",this.options=Object.assign(Object.assign({},c.defaults),e),this.init()}init(){d.CssLoader.ensure(this.name,f),this.container=document.createElement("div"),d.Dom.addClass(this.container,this.prefixClassName("widget-dnd")),this.draggingGraph=new d.Graph(Object.assign(Object.assign({},this.options.delegateGraphOptions),{container:document.createElement("div"),width:1,height:1,async:!1})),d.Dom.append(this.container,this.draggingGraph.container)}start(e,n){const t=n;t.preventDefault(),this.targetModel.startBatch("dnd"),d.Dom.addClass(this.container,"dragging"),d.Dom.appendTo(this.container,this.options.draggingContainer||document.body),this.sourceNode=e,this.prepareDragging(e,t.clientX,t.clientY);const i=this.updateNodePosition(t.clientX,t.clientY);this.isSnaplineEnabled()&&(this.snapline.captureCursorOffset({e:t,node:e,cell:e,view:this.draggingView,x:i.x,y:i.y}),this.draggingNode.on("change:position",this.snap,this)),this.delegateDocumentEvents(c.documentEvents,t.data)}isSnaplineEnabled(){return this.snapline&&this.snapline.isEnabled()}prepareDragging(e,n,t){const i=this.draggingGraph,s=i.model,a=this.options.getDragNode(e,{sourceNode:e,draggingGraph:i,targetGraph:this.targetGraph});a.position(0,0);let o=5;if(this.isSnaplineEnabled()&&(o+=this.snapline.options.tolerance||0),this.isSnaplineEnabled()||this.options.scaled){const l=this.targetGraph.transform.getScale();i.scale(l.sx,l.sy),o*=Math.max(l.sx,l.sy)}else i.scale(1,1);this.clearDragging(),s.resetCells([a]);const r=i.findViewByCell(a);r.undelegateEvents(),r.cell.off("changed"),i.fitToContent({padding:o,allowNewOrigin:"any",useCellGeometry:!1});const g=r.getBBox();this.geometryBBox=r.getBBox({useCellGeometry:!0}),this.delta=this.geometryBBox.getTopLeft().diff(g.getTopLeft()),this.draggingNode=a,this.draggingView=r,this.draggingBBox=a.getBBox(),this.padding=o,this.originOffset=this.updateGraphPosition(n,t)}updateGraphPosition(e,n){const t=document.body.scrollTop||document.documentElement.scrollTop,i=document.body.scrollLeft||document.documentElement.scrollLeft,s=this.delta,a=this.geometryBBox,o=this.padding||5,r={left:e-s.x-a.width/2-o+i,top:n-s.y-a.height/2-o+t};return this.draggingGraph&&d.Dom.css(this.container,{left:`${r.left}px`,top:`${r.top}px`}),r}updateNodePosition(e,n){const t=this.targetGraph.clientToLocal(e,n),i=this.draggingBBox;return t.x-=i.width/2,t.y-=i.height/2,this.draggingNode.position(t.x,t.y),t}snap({cell:e,current:n,options:t}){const i=e;if(t.snapped){const s=this.draggingBBox;i.position(s.x+t.tx,s.y+t.ty,{silent:!0}),this.draggingView.translate(),i.position(n.x,n.y,{silent:!0}),this.snapOffset={x:t.tx,y:t.ty}}else this.snapOffset=null}onDragging(e){const n=this.draggingView;if(n){e.preventDefault();const t=this.normalizeEvent(e),i=t.clientX,s=t.clientY;this.updateGraphPosition(i,s);const a=this.updateNodePosition(i,s),o=this.targetGraph.options.embedding.enabled,r=(o||this.isSnaplineEnabled())&&this.isInsideValidArea({x:i,y:s});if(o){n.setEventData(t,{graph:this.targetGraph,candidateEmbedView:this.candidateEmbedView});const g=n.getEventData(t);r?n.processEmbedding(t,g):n.clearEmbedding(g),this.candidateEmbedView=g.candidateEmbedView}this.isSnaplineEnabled()&&(r?this.snapline.snapOnMoving({e:t,view:n,x:a.x,y:a.y}):this.snapline.hide())}}onDragEnd(e){const n=this.draggingNode;if(n){const t=this.normalizeEvent(e),i=this.draggingView,s=this.draggingBBox,a=this.snapOffset;let o=s.x,r=s.y;a&&(o+=a.x,r+=a.y),n.position(o,r,{silent:!0});const g=this.drop(n,{x:t.clientX,y:t.clientY}),l=p=>{p?(this.onDropped(n),this.targetGraph.options.embedding.enabled&&i&&(i.setEventData(t,{cell:p,graph:this.targetGraph,candidateEmbedView:this.candidateEmbedView}),i.finalizeEmbedding(t,i.getEventData(t)))):this.onDropInvalid(),this.candidateEmbedView=null,this.targetModel.stopBatch("dnd")};d.FunctionExt.isAsync(g)?(this.undelegateDocumentEvents(),g.then(l)):l(g)}}clearDragging(){this.draggingNode&&(this.sourceNode=null,this.draggingNode.remove(),this.draggingNode=null,this.draggingView=null,this.delta=null,this.padding=null,this.snapOffset=null,this.originOffset=null,this.undelegateDocumentEvents())}onDropped(e){this.draggingNode===e&&(this.clearDragging(),d.Dom.removeClass(this.container,"dragging"),d.Dom.remove(this.container))}onDropInvalid(){const e=this.draggingNode;e&&this.onDropped(e)}isInsideValidArea(e){let n,t=null;const i=this.targetGraph,s=this.targetScroller;this.options.dndContainer&&(t=this.getDropArea(this.options.dndContainer));const a=t&&t.containsPoint(e);if(s)if(s.options.autoResize)n=this.getDropArea(s.container);else{const o=this.getDropArea(s.container);n=this.getDropArea(i.container).intersectsWithRect(o)}else n=this.getDropArea(i.container);return!a&&n&&n.containsPoint(e)}getDropArea(e){const n=d.Dom.offset(e),t=document.body.scrollTop||document.documentElement.scrollTop,i=document.body.scrollLeft||document.documentElement.scrollLeft;return d.Rectangle.create({x:n.left+parseInt(d.Dom.css(e,"border-left-width"),10)-i,y:n.top+parseInt(d.Dom.css(e,"border-top-width"),10)-t,width:e.clientWidth,height:e.clientHeight})}drop(e,n){if(this.isInsideValidArea(n)){const t=this.targetGraph,i=t.model,s=t.clientToLocal(n),a=this.sourceNode,o=this.options.getDropNode(e,{sourceNode:a,draggingNode:e,targetGraph:this.targetGraph,draggingGraph:this.draggingGraph}),r=o.getBBox();s.x+=r.x-r.width/2,s.y+=r.y-r.height/2;const g=this.snapOffset?1:t.getGridSize();o.position(d.GeometryUtil.snapToGrid(s.x,g),d.GeometryUtil.snapToGrid(s.y,g)),o.removeZIndex();const l=this.options.validateNode,p=l?l(o,{sourceNode:a,draggingNode:e,droppingNode:o,targetGraph:t,draggingGraph:this.draggingGraph}):!0;return typeof p=="boolean"?p?(i.addCell(o,{stencil:this.cid}),o):null:d.FunctionExt.toDeferredBoolean(p).then(u=>u?(i.addCell(o,{stencil:this.cid}),o):null)}return null}onRemove(){this.draggingGraph&&(this.draggingGraph.view.remove(),this.draggingGraph.dispose())}dispose(){this.remove(),d.CssLoader.clean(this.name)}}m([d.View.dispose()],c.prototype,"dispose",null);(function(h){h.defaults={getDragNode:e=>e.clone(),getDropNode:e=>e.clone()},h.documentEvents={mousemove:"onDragging",touchmove:"onDragging",mouseup:"onDragEnd",touchend:"onDragEnd",touchcancel:"onDragEnd"}})(c||(c={}));exports.Dnd=c;
@@ -0,0 +1,181 @@
1
+ import { Graph as w, Basecoat as j, DataUri as G, Vector as E, NumberExt as V, Dom as O, Rectangle as C, FunctionExt as N } from "@antv/x6";
2
+ w.prototype.toSVG = function(a, e) {
3
+ const t = this.getPlugin("export");
4
+ t && t.toSVG(a, e);
5
+ };
6
+ w.prototype.toPNG = function(a, e) {
7
+ const t = this.getPlugin("export");
8
+ t && t.toPNG(a, e);
9
+ };
10
+ w.prototype.toJPEG = function(a, e) {
11
+ const t = this.getPlugin("export");
12
+ t && t.toJPEG(a, e);
13
+ };
14
+ w.prototype.exportPNG = function(a, e) {
15
+ const t = this.getPlugin("export");
16
+ t && t.exportPNG(a, e);
17
+ };
18
+ w.prototype.exportJPEG = function(a, e) {
19
+ const t = this.getPlugin("export");
20
+ t && t.exportJPEG(a, e);
21
+ };
22
+ w.prototype.exportSVG = function(a, e) {
23
+ const t = this.getPlugin("export");
24
+ t && t.exportSVG(a, e);
25
+ };
26
+ var U = function(a, e, t, n) {
27
+ var i = arguments.length, s = i < 3 ? e : n === null ? n = Object.getOwnPropertyDescriptor(e, t) : n, f;
28
+ if (typeof Reflect == "object" && typeof Reflect.decorate == "function") s = Reflect.decorate(a, e, t, n);
29
+ else for (var c = a.length - 1; c >= 0; c--) (f = a[c]) && (s = (i < 3 ? f(s) : i > 3 ? f(e, t, s) : f(e, t)) || s);
30
+ return i > 3 && s && Object.defineProperty(e, t, s), s;
31
+ };
32
+ class z extends j {
33
+ constructor() {
34
+ super(), this.name = "export";
35
+ }
36
+ get view() {
37
+ return this.graph.view;
38
+ }
39
+ init(e) {
40
+ this.graph = e;
41
+ }
42
+ exportPNG(e = "chart", t = {}) {
43
+ this.toPNG((n) => {
44
+ G.downloadDataUri(n, e);
45
+ }, t);
46
+ }
47
+ exportJPEG(e = "chart", t = {}) {
48
+ this.toPNG((n) => {
49
+ G.downloadDataUri(n, e);
50
+ }, t);
51
+ }
52
+ exportSVG(e = "chart", t = {}) {
53
+ this.toSVG((n) => {
54
+ G.downloadDataUri(G.svgToDataUrl(n), e);
55
+ }, t);
56
+ }
57
+ toSVG(e, t = {}) {
58
+ this.notify("before:export", t);
59
+ const n = this.view.svg, i = E.create(n).clone();
60
+ let s = i.node;
61
+ const f = i.findOne(`.${this.view.prefixClassName("graph-svg-stage")}`), c = t.viewBox || this.graph.graphToLocal(this.graph.getContentBBox()), h = t.preserveDimensions;
62
+ if (h) {
63
+ const o = typeof h == "boolean" ? c : h;
64
+ i.attr({
65
+ width: o.width,
66
+ height: o.height
67
+ });
68
+ }
69
+ if (i.removeAttribute("style").attr("viewBox", [c.x, c.y, c.width, c.height].join(" ")), f.removeAttribute("transform"), t.copyStyles !== !1) {
70
+ const o = n.ownerDocument, g = Array.from(n.querySelectorAll("*")), d = Array.from(s.querySelectorAll("*")), u = o.styleSheets.length, P = [];
71
+ for (let r = u - 1; r >= 0; r -= 1)
72
+ P[r] = o.styleSheets[r], o.styleSheets[r].disabled = !0;
73
+ const x = {};
74
+ g.forEach((r, m) => {
75
+ const y = window.getComputedStyle(r, null), v = {};
76
+ Object.keys(y).forEach((S) => {
77
+ v[S] = y.getPropertyValue(S);
78
+ }), x[m] = v;
79
+ }), u !== o.styleSheets.length && P.forEach((r, m) => {
80
+ o.styleSheets[m] = r;
81
+ });
82
+ for (let r = 0; r < u; r += 1)
83
+ o.styleSheets[r].disabled = !1;
84
+ const D = {};
85
+ g.forEach((r, m) => {
86
+ const y = window.getComputedStyle(r, null), v = x[m], S = {};
87
+ Object.keys(y).forEach((b) => {
88
+ !V.isNumber(b) && y.getPropertyValue(b) !== v[b] && (S[b] = y.getPropertyValue(b));
89
+ }), D[m] = S;
90
+ }), d.forEach((r, m) => {
91
+ O.css(r, D[m]);
92
+ });
93
+ }
94
+ const p = t.stylesheet;
95
+ if (typeof p == "string") {
96
+ const o = n.ownerDocument.implementation.createDocument(null, "xml", null).createCDATASection(p);
97
+ i.prepend(E.create("style", {
98
+ type: "text/css"
99
+ }, [o]));
100
+ }
101
+ const l = () => {
102
+ const o = t.beforeSerialize;
103
+ if (typeof o == "function") {
104
+ const d = N.call(o, this.graph, s);
105
+ d instanceof SVGSVGElement && (s = d);
106
+ }
107
+ const g = new XMLSerializer().serializeToString(s).replace(/&nbsp;/g, " ");
108
+ this.notify("after:export", t), e(g);
109
+ };
110
+ if (t.serializeImages) {
111
+ const o = i.find("image").map((g) => new Promise((d) => {
112
+ const u = g.attr("xlink:href") || g.attr("href");
113
+ G.imageToDataUri(u, (P, x) => {
114
+ !P && x && g.attr("xlink:href", x), d();
115
+ });
116
+ }));
117
+ Promise.all(o).then(l);
118
+ } else
119
+ l();
120
+ }
121
+ toDataURL(e, t) {
122
+ let n = t.viewBox || this.graph.getContentBBox();
123
+ const i = V.normalizeSides(t.padding);
124
+ t.width && t.height && (i.left + i.right >= t.width && (i.left = i.right = 0), i.top + i.bottom >= t.height && (i.top = i.bottom = 0));
125
+ const s = new C(-i.left, -i.top, i.left + i.right, i.top + i.bottom);
126
+ if (t.width && t.height) {
127
+ const l = n.width + i.left + i.right, o = n.height + i.top + i.bottom;
128
+ s.scale(l / t.width, o / t.height);
129
+ }
130
+ n = C.create(n).moveAndExpand(s);
131
+ const f = typeof t.width == "number" && typeof t.height == "number" ? { width: t.width, height: t.height } : n;
132
+ let c = t.ratio ? parseFloat(t.ratio) : 1;
133
+ (!Number.isFinite(c) || c === 0) && (c = 1);
134
+ const h = {
135
+ width: Math.max(Math.round(f.width * c), 1),
136
+ height: Math.max(Math.round(f.height * c), 1)
137
+ };
138
+ {
139
+ const l = document.createElement("canvas"), o = l.getContext("2d");
140
+ l.width = h.width, l.height = h.height;
141
+ const g = h.width - 1, d = h.height - 1;
142
+ o.fillStyle = "rgb(1,1,1)", o.fillRect(g, d, 1, 1);
143
+ const u = o.getImageData(g, d, 1, 1).data;
144
+ if (u[0] !== 1 || u[1] !== 1 || u[2] !== 1)
145
+ throw new Error("size exceeded");
146
+ }
147
+ const p = new Image();
148
+ p.onload = () => {
149
+ const l = document.createElement("canvas");
150
+ l.width = h.width, l.height = h.height;
151
+ const o = l.getContext("2d");
152
+ o.fillStyle = t.backgroundColor || "white", o.fillRect(0, 0, h.width, h.height);
153
+ try {
154
+ o.drawImage(p, 0, 0, h.width, h.height);
155
+ const g = l.toDataURL(t.type, t.quality);
156
+ e(g);
157
+ } catch {
158
+ }
159
+ }, this.toSVG((l) => {
160
+ p.src = `data:image/svg+xml,${encodeURIComponent(l)}`;
161
+ }, Object.assign(Object.assign({}, t), { viewBox: n, serializeImages: !0, preserveDimensions: Object.assign({}, h) }));
162
+ }
163
+ toPNG(e, t = {}) {
164
+ this.toDataURL(e, Object.assign(Object.assign({}, t), { type: "image/png" }));
165
+ }
166
+ toJPEG(e, t = {}) {
167
+ this.toDataURL(e, Object.assign(Object.assign({}, t), { type: "image/jpeg" }));
168
+ }
169
+ notify(e, t) {
170
+ this.trigger(e, t), this.graph.trigger(e, t);
171
+ }
172
+ dispose() {
173
+ this.off();
174
+ }
175
+ }
176
+ U([
177
+ j.dispose()
178
+ ], z.prototype, "dispose", null);
179
+ export {
180
+ z as Export
181
+ };