@xxrandr/conecta-diagram 0.0.0-stage → 0.1.4
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/LICENSE +21 -0
- package/README.md +319 -2
- package/dist/chunk-3QGSCPWL.cjs +663 -0
- package/dist/chunk-43VYPB4U.js +2136 -0
- package/dist/chunk-6ADTOXBT.cjs +626 -0
- package/dist/chunk-B2RLLFGC.js +0 -0
- package/dist/chunk-GXOBW2BK.js +290 -0
- package/dist/chunk-HZER5BPR.js +1122 -0
- package/dist/chunk-IT5H6WO2.js +626 -0
- package/dist/chunk-LKOWNTPR.cjs +1 -0
- package/dist/chunk-Q62JPMJH.js +663 -0
- package/dist/chunk-QI4NNFRQ.cjs +290 -0
- package/dist/chunk-VD32JNDO.cjs +2136 -0
- package/dist/chunk-ZMSQTBVW.cjs +1122 -0
- package/dist/core/index.cjs +56 -0
- package/dist/core/index.d.cts +65 -0
- package/dist/core/index.d.ts +65 -0
- package/dist/core/index.js +56 -0
- package/dist/d3/index.cjs +8 -0
- package/dist/d3/index.d.cts +46 -0
- package/dist/d3/index.d.ts +46 -0
- package/dist/d3/index.js +8 -0
- package/dist/index.cjs +71 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +71 -0
- package/dist/photon.css +339 -0
- package/dist/runner-display-BkBJpBY-.d.ts +151 -0
- package/dist/runner-display-DHHtavSX.d.cts +151 -0
- package/dist/store-CtOInpPu.d.cts +242 -0
- package/dist/store-CtOInpPu.d.ts +242 -0
- package/dist/svg/index.cjs +15 -0
- package/dist/svg/index.d.cts +172 -0
- package/dist/svg/index.d.ts +172 -0
- package/dist/svg/index.js +15 -0
- package/docs/devtools-refactor.md +93 -0
- package/docs/java-runtime-integration.md +268 -0
- package/docs/photon-template.html +547 -0
- package/docs/presentation-architecture.md +30 -0
- package/docs/runner-display.md +109 -0
- package/package.json +130 -4
|
@@ -0,0 +1,2136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
simulationOverlay,
|
|
3
|
+
visibleElements
|
|
4
|
+
} from "./chunk-GXOBW2BK.js";
|
|
5
|
+
import {
|
|
6
|
+
ForcePlacement,
|
|
7
|
+
nodeDimensions,
|
|
8
|
+
timer
|
|
9
|
+
} from "./chunk-HZER5BPR.js";
|
|
10
|
+
import {
|
|
11
|
+
FlowError,
|
|
12
|
+
actionPresentation,
|
|
13
|
+
assertJson,
|
|
14
|
+
capabilityState,
|
|
15
|
+
clone,
|
|
16
|
+
formatCondition
|
|
17
|
+
} from "./chunk-Q62JPMJH.js";
|
|
18
|
+
|
|
19
|
+
// src/svg/icons.ts
|
|
20
|
+
var iconPaths = {
|
|
21
|
+
workflow: ["M4 4h6v6H4zM14 14h6v6h-6zM7 10v7h7M10 7h7v7"],
|
|
22
|
+
code: ["m8 7-5 5 5 5m8-10 5 5-5 5m-3-13-2 16"],
|
|
23
|
+
api: [
|
|
24
|
+
"M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0ZM3 12h18M12 3c4 4 4 14 0 18-4-4-4-14 0-18Z"
|
|
25
|
+
],
|
|
26
|
+
database: [
|
|
27
|
+
"M20 6c0 2-16 2-16 0s16-2 16 0ZM4 6v12c0 3 16 3 16 0V6M4 12c0 3 16 3 16 0"
|
|
28
|
+
],
|
|
29
|
+
file: ["M13 3H6a1 1 0 0 0-1 1v16h14V9l-6-6Zm0 0v6h6M9 13h6m-6 4h4"],
|
|
30
|
+
transfer: ["M4 4h9l4 4v3M13 4v4h4M4 4v16h6m3-4 3-3 3 3m-3-3v8m-3-12H8m2 4H8"],
|
|
31
|
+
terminal: ["M3 5h18v14H3zM7 9l3 3-3 3m6 0h4"],
|
|
32
|
+
sftp: ["M4 7h15m-4-4 4 4-4 4M20 17H5m4-4-4 4 4 4"],
|
|
33
|
+
mail: ["M3 5h18v14H3zM3 6l9 7 9-7"],
|
|
34
|
+
messaging: ["M3 4h14v11H9l-4 4v-4H3zM17 8h4v12h-4l-3 3v-4"],
|
|
35
|
+
event: ["m13 2-8 12h6l-1 8 9-13h-7l1-7Z"],
|
|
36
|
+
decision: ["m12 3 9 9-9 9-9-9 9-9ZM9 9h3v6m0-3h4"],
|
|
37
|
+
wait: ["M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0ZM12 7v5l3 2"],
|
|
38
|
+
cancel: ["M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0ZM8 8l8 8m0-8-8 8"],
|
|
39
|
+
extension: ["M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM17 14v6m-3-3h6"],
|
|
40
|
+
play: ["m9 5 10 7-10 7V5Z"],
|
|
41
|
+
stop: ["M7 7h10v10H7z"],
|
|
42
|
+
pause: ["M8 5v14m8-14v14"],
|
|
43
|
+
next: ["m5 5 10 7-10 7V5Zm14 0v14"],
|
|
44
|
+
reset: ["M4 10a8 8 0 1 1 1 7M4 4v6h6"],
|
|
45
|
+
check: ["m5 12 4 4L19 6"],
|
|
46
|
+
error: ["M12 3 2 21h20L12 3Zm0 6v5m0 3v.2"],
|
|
47
|
+
in: ["M3 12h14m-5-5 5 5-5 5m6-14h3v18h-3"],
|
|
48
|
+
out: ["M3 12h14m-5-5 5 5-5 5M6 3H3v18h3"],
|
|
49
|
+
fork: ["M12 20v-8M6 4v5l6 3 6-3V4M4 4h4m8 0h4"],
|
|
50
|
+
join: ["M6 4v5l6 5 6-5V4m-6 10v6m-3-3 3 3 3-3"],
|
|
51
|
+
fit: ["M3 9V3h6m6 0h6v6M3 15v6h6m6 0h6v-6M8 8h8v8H8z"],
|
|
52
|
+
plus: ["M12 5v14M5 12h14"],
|
|
53
|
+
minus: ["M5 12h14"],
|
|
54
|
+
chevron: ["m9 5 7 7-7 7"],
|
|
55
|
+
search: ["M18 10a8 8 0 1 1-16 0 8 8 0 0 1 16 0Zm-2 6 6 6"],
|
|
56
|
+
download: ["M12 3v12m-5-5 5 5 5-5M4 16v5h16v-5"],
|
|
57
|
+
copy: ["M8 8h12v13H8zM15 8V3H3v13h5"],
|
|
58
|
+
locate: ["M12 2v4m0 12v4M2 12h4m12 0h4M19 12a7 7 0 1 1-14 0 7 7 0 0 1 14 0Z"],
|
|
59
|
+
undo: ["m7 4-4 5 4 5M3 9h10a7 7 0 0 1 7 7v4"],
|
|
60
|
+
redo: ["m17 4 4 5-4 5m4-5H11a7 7 0 0 0-7 7v4"],
|
|
61
|
+
more: ["M5 11v2m7-2v2m7-2v2"],
|
|
62
|
+
info: ["M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0ZM12 11v6m0-10v.1"]
|
|
63
|
+
};
|
|
64
|
+
function createFlowIcon(document2, name, size = 20) {
|
|
65
|
+
const svg = document2.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
66
|
+
for (const [key, value] of Object.entries({
|
|
67
|
+
viewBox: "0 0 24 24",
|
|
68
|
+
width: String(size),
|
|
69
|
+
height: String(size),
|
|
70
|
+
fill: "none",
|
|
71
|
+
stroke: "currentColor",
|
|
72
|
+
"stroke-width": "1.65",
|
|
73
|
+
"stroke-linecap": "round",
|
|
74
|
+
"stroke-linejoin": "round",
|
|
75
|
+
"aria-hidden": "true",
|
|
76
|
+
focusable: "false",
|
|
77
|
+
"data-icon": name
|
|
78
|
+
}))
|
|
79
|
+
svg.setAttribute(key, value);
|
|
80
|
+
for (const d of Object.hasOwn(iconPaths, name) ? iconPaths[name] : iconPaths.extension) {
|
|
81
|
+
const path = document2.createElementNS(svg.namespaceURI, "path");
|
|
82
|
+
path.setAttribute("d", d);
|
|
83
|
+
svg.append(path);
|
|
84
|
+
}
|
|
85
|
+
return svg;
|
|
86
|
+
}
|
|
87
|
+
function operationIcon(kind) {
|
|
88
|
+
const icons = {
|
|
89
|
+
process: "code",
|
|
90
|
+
api: "api",
|
|
91
|
+
database: "database",
|
|
92
|
+
file: "transfer",
|
|
93
|
+
ssh: "terminal",
|
|
94
|
+
sftp: "sftp",
|
|
95
|
+
mail: "mail",
|
|
96
|
+
messaging: "messaging",
|
|
97
|
+
event: "event",
|
|
98
|
+
cancel: "cancel",
|
|
99
|
+
generic: "extension",
|
|
100
|
+
task: "terminal",
|
|
101
|
+
decision: "decision",
|
|
102
|
+
wait: "wait",
|
|
103
|
+
fork: "fork",
|
|
104
|
+
join: "join",
|
|
105
|
+
start: "play",
|
|
106
|
+
end: "stop"
|
|
107
|
+
};
|
|
108
|
+
return Object.hasOwn(icons, kind) ? icons[kind] : "extension";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/svg/PhotonCard.ts
|
|
112
|
+
function renderPhotonCard(document2, node, flow, observation, overlay, selected, capabilities) {
|
|
113
|
+
const size = nodeDimensions(node);
|
|
114
|
+
const object = document2.createElementNS(
|
|
115
|
+
"http://www.w3.org/2000/svg",
|
|
116
|
+
"foreignObject"
|
|
117
|
+
);
|
|
118
|
+
object.setAttribute("x", String(-size.width / 2 - 4));
|
|
119
|
+
object.setAttribute("y", String(-size.height / 2 - 4));
|
|
120
|
+
object.setAttribute("width", String(size.width + 8));
|
|
121
|
+
object.setAttribute("height", String(size.height + 8));
|
|
122
|
+
object.setAttribute("overflow", "visible");
|
|
123
|
+
const el = (tag, text, parent, className) => {
|
|
124
|
+
const element = document2.createElementNS(
|
|
125
|
+
"http://www.w3.org/1999/xhtml",
|
|
126
|
+
tag
|
|
127
|
+
);
|
|
128
|
+
element.textContent = text;
|
|
129
|
+
element.className = className;
|
|
130
|
+
parent.append(element);
|
|
131
|
+
return element;
|
|
132
|
+
};
|
|
133
|
+
const action = "action" in node ? node.action : void 0;
|
|
134
|
+
const presentation = action ? actionPresentation(action) : void 0;
|
|
135
|
+
const state = observation?.status ?? "idle";
|
|
136
|
+
const article = el(
|
|
137
|
+
"article",
|
|
138
|
+
"",
|
|
139
|
+
object,
|
|
140
|
+
`flow-node flow-node--embedded${selected ? " selected" : ""}`
|
|
141
|
+
);
|
|
142
|
+
article.dataset.kind = action?.body.kind === "api" ? "service" : action?.body.kind ?? node.type;
|
|
143
|
+
article.dataset.state = state;
|
|
144
|
+
const header = el("header", "", article, "node-header");
|
|
145
|
+
el("div", "", header, "node-icon").append(
|
|
146
|
+
createFlowIcon(document2, operationIcon(action?.body.kind ?? node.type), 18)
|
|
147
|
+
);
|
|
148
|
+
const labels = el("div", "", header, "");
|
|
149
|
+
const title = el("div", node.label, labels, "node-title");
|
|
150
|
+
title.title = node.label;
|
|
151
|
+
el(
|
|
152
|
+
"div",
|
|
153
|
+
presentation?.title ?? (node.type === "decision" ? "Conditional \xB7 Decision" : node.type === "wait" ? "External response \xB7 Wait" : `${node.type} \xB7 Plan`),
|
|
154
|
+
labels,
|
|
155
|
+
"node-subtitle"
|
|
156
|
+
);
|
|
157
|
+
const signals = el("div", "", article, "signals");
|
|
158
|
+
const observations = overlay?.signals?.filter((signal) => signal.nodeId === node.id) ?? [];
|
|
159
|
+
const inputs = node.signals?.inputs ?? (node.type === "wait" ? [node.signal] : []);
|
|
160
|
+
const outputs = node.signals?.outputs ?? [];
|
|
161
|
+
for (const [direction, names] of [
|
|
162
|
+
["in", inputs],
|
|
163
|
+
["out", outputs]
|
|
164
|
+
]) {
|
|
165
|
+
for (const name of names.length ? names : ["\u2014"]) {
|
|
166
|
+
const observed = observations.some(
|
|
167
|
+
(signal) => signal.name === name && signal.direction === direction
|
|
168
|
+
);
|
|
169
|
+
const chip = el("span", "", signals, "signal");
|
|
170
|
+
chip.dataset.field = `signals-${direction}`;
|
|
171
|
+
chip.dataset.observed = String(observed);
|
|
172
|
+
chip.title = `${direction === "in" ? "Input" : "Output"}: ${name}${observed ? " \xB7 observed" : ""}`;
|
|
173
|
+
chip.append(createFlowIcon(document2, observed ? "check" : direction, 12));
|
|
174
|
+
el("span", name, chip, "");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
let label = "Handler", preview = node.type;
|
|
178
|
+
if (action) {
|
|
179
|
+
const body = action.body;
|
|
180
|
+
switch (body.kind) {
|
|
181
|
+
case "process":
|
|
182
|
+
label = "Profile";
|
|
183
|
+
preview = body.profile;
|
|
184
|
+
break;
|
|
185
|
+
case "api":
|
|
186
|
+
label = "Endpoint";
|
|
187
|
+
preview = `${body.method} ${presentation.lines[0]}`;
|
|
188
|
+
break;
|
|
189
|
+
case "database":
|
|
190
|
+
label = "Datasource";
|
|
191
|
+
preview = body.datasource;
|
|
192
|
+
break;
|
|
193
|
+
case "file":
|
|
194
|
+
label = "Path";
|
|
195
|
+
preview = body.path;
|
|
196
|
+
break;
|
|
197
|
+
case "ssh":
|
|
198
|
+
case "sftp":
|
|
199
|
+
case "mail":
|
|
200
|
+
case "messaging":
|
|
201
|
+
label = "Connection";
|
|
202
|
+
preview = body.connectionId;
|
|
203
|
+
break;
|
|
204
|
+
case "event":
|
|
205
|
+
label = "Topic";
|
|
206
|
+
preview = body.topic;
|
|
207
|
+
break;
|
|
208
|
+
case "cancel":
|
|
209
|
+
label = "Target";
|
|
210
|
+
preview = body.targetCommandId;
|
|
211
|
+
break;
|
|
212
|
+
case "generic":
|
|
213
|
+
label = "Extension";
|
|
214
|
+
preview = body.name;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
} else if (node.type === "wait") {
|
|
218
|
+
label = "Signal";
|
|
219
|
+
preview = node.signal;
|
|
220
|
+
} else if (node.type === "decision") {
|
|
221
|
+
label = "Condition";
|
|
222
|
+
const branch = flow.edges.find(
|
|
223
|
+
(edge2) => edge2.source === node.id && edge2.condition
|
|
224
|
+
);
|
|
225
|
+
preview = branch?.condition ? formatCondition(branch.condition) : "Not configured";
|
|
226
|
+
} else if (node.type === "task") preview = node.handler ?? "Not configured";
|
|
227
|
+
const row = el("div", "", article, "action-preview");
|
|
228
|
+
el("span", label, row, "preview-label");
|
|
229
|
+
const value = el("code", preview, row, "preview-value");
|
|
230
|
+
value.title = preview;
|
|
231
|
+
value.dataset.field = "action-preview";
|
|
232
|
+
el("div", "", article, "node-divider");
|
|
233
|
+
const footer = el("div", "", article, "node-footer");
|
|
234
|
+
const execution = el("span", "", footer, "execution");
|
|
235
|
+
el("span", "", execution, "status-dot");
|
|
236
|
+
const choice = overlay?.decisions && Object.hasOwn(overlay.decisions, node.id) ? overlay.decisions[node.id] : void 0;
|
|
237
|
+
const edge = choice ? flow.edges.find((edge2) => edge2.id === choice.edgeId) : void 0;
|
|
238
|
+
const status = choice ? `Selected: ${edge?.label ?? choice.edgeId}` : state.replaceAll("_", " ").replace(/^./, (letter) => letter.toUpperCase());
|
|
239
|
+
const statusText = el("span", status, execution, "");
|
|
240
|
+
statusText.dataset.field = "execution-status";
|
|
241
|
+
const progress = observation?.progress;
|
|
242
|
+
const detail = action && capabilityState(action.type, capabilities) === "unsupported" ? "Not advertised / unsupported by runner" : choice?.reason ?? (progress ? `${progress.current}${progress.total ? ` / ${progress.total}` : ""} ${progress.unit}` : observation?.detail ?? "Display only");
|
|
243
|
+
execution.title = detail;
|
|
244
|
+
const accessible = el("span", detail, execution, "execution-detail");
|
|
245
|
+
accessible.dataset.field = "execution-detail";
|
|
246
|
+
const type = el("code", action?.type ?? node.type, footer, "action-type");
|
|
247
|
+
type.title = type.textContent ?? "";
|
|
248
|
+
type.dataset.field = "action-type";
|
|
249
|
+
return object;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/svg/NodeTooltip.ts
|
|
253
|
+
var NodeTooltip = class {
|
|
254
|
+
constructor(document2, id) {
|
|
255
|
+
this.document = document2;
|
|
256
|
+
this.element = document2.createElement("div");
|
|
257
|
+
this.element.id = id;
|
|
258
|
+
this.element.setAttribute("role", "tooltip");
|
|
259
|
+
this.element.hidden = true;
|
|
260
|
+
this.element.style.cssText = "position:fixed;z-index:10000;pointer-events:none;width:312px;max-width:calc(100vw - 24px);padding:16px;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:var(--text);box-shadow:var(--shadow-card-hover);font:12px/1.6 var(--font-sans)";
|
|
261
|
+
(document2.body ?? document2.documentElement).append(this.element);
|
|
262
|
+
}
|
|
263
|
+
document;
|
|
264
|
+
element;
|
|
265
|
+
target = null;
|
|
266
|
+
show(node, flow, observation, capabilities, target, anchor) {
|
|
267
|
+
this.hide();
|
|
268
|
+
this.target = target;
|
|
269
|
+
this.element.replaceChildren();
|
|
270
|
+
const action = "action" in node ? node.action : void 0;
|
|
271
|
+
const preview = action ? actionPresentation(action) : void 0;
|
|
272
|
+
const heading = this.document.createElement("div");
|
|
273
|
+
heading.style.cssText = "display:flex;align-items:center;gap:9px;font-weight:600;color:var(--text);margin-bottom:8px";
|
|
274
|
+
heading.append(
|
|
275
|
+
createFlowIcon(
|
|
276
|
+
this.document,
|
|
277
|
+
operationIcon(action?.body.kind ?? node.type),
|
|
278
|
+
18
|
|
279
|
+
)
|
|
280
|
+
);
|
|
281
|
+
const title = this.document.createElement("span");
|
|
282
|
+
title.textContent = node.label;
|
|
283
|
+
heading.append(title);
|
|
284
|
+
this.element.append(heading);
|
|
285
|
+
const meta = this.document.createElement("div");
|
|
286
|
+
meta.style.cssText = "color:var(--accent);font:11px var(--font-mono);margin-bottom:10px";
|
|
287
|
+
meta.textContent = action ? `${action.type} \xB7 ${capabilityState(action.type, capabilities)}` : node.type === "decision" ? "Decision \xB7 observed routing" : node.type === "wait" ? `Waiting for ${node.signal}` : node.type;
|
|
288
|
+
this.element.append(meta);
|
|
289
|
+
const code = node.type === "decision" ? node.decision?.expression : preview?.code;
|
|
290
|
+
const content = this.document.createElement("pre");
|
|
291
|
+
content.style.cssText = "margin:0;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/1.65 var(--font-mono);color:var(--text-secondary)";
|
|
292
|
+
const lines = code?.source.split(/\r?\n/) ?? preview?.lines ?? (node.type === "decision" ? flow.edges.filter((edge) => edge.source === node.id).map(
|
|
293
|
+
(edge) => `${edge.label ?? edge.target}: ${edge.default ? "otherwise" : edge.condition ? formatCondition(edge.condition) : "unconfigured"}`
|
|
294
|
+
) : []);
|
|
295
|
+
content.textContent = (code ? `${code.language}
|
|
296
|
+
` : "") + lines.slice(0, 5).join("\n").slice(0, 480) + (lines.length > 5 ? "\n\u2026" : "");
|
|
297
|
+
this.element.append(content);
|
|
298
|
+
if (observation?.detail) {
|
|
299
|
+
const detail = this.document.createElement("p");
|
|
300
|
+
detail.style.cssText = "margin:10px 0 0;color:var(--text-secondary)";
|
|
301
|
+
detail.textContent = observation.detail.slice(0, 160);
|
|
302
|
+
this.element.append(detail);
|
|
303
|
+
}
|
|
304
|
+
const hint = this.document.createElement("div");
|
|
305
|
+
hint.style.cssText = "margin-top:12px;padding-top:10px;border-top:1px solid var(--border);color:var(--text-muted);font-size:10px;letter-spacing:.04em";
|
|
306
|
+
hint.textContent = "SELECT TO ASSEMBLE \xB7 DISPLAY ONLY";
|
|
307
|
+
this.element.append(hint);
|
|
308
|
+
target.setAttribute("aria-describedby", this.element.id);
|
|
309
|
+
this.element.hidden = false;
|
|
310
|
+
const bounds = this.element.getBoundingClientRect();
|
|
311
|
+
const viewport = this.document.defaultView;
|
|
312
|
+
const width = viewport?.innerWidth ?? 1024, height = viewport?.innerHeight ?? 768;
|
|
313
|
+
this.element.style.left = `${Math.max(12, Math.min(anchor.x + 16, width - bounds.width - 12))}px`;
|
|
314
|
+
this.element.style.top = `${Math.max(12, Math.min(anchor.y + 14, height - bounds.height - 12))}px`;
|
|
315
|
+
}
|
|
316
|
+
hide() {
|
|
317
|
+
this.target?.removeAttribute("aria-describedby");
|
|
318
|
+
this.target = null;
|
|
319
|
+
this.element.hidden = true;
|
|
320
|
+
}
|
|
321
|
+
destroy() {
|
|
322
|
+
this.hide();
|
|
323
|
+
this.element.remove();
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// node_modules/d3-selection/src/namespaces.js
|
|
328
|
+
var xhtml = "http://www.w3.org/1999/xhtml";
|
|
329
|
+
var namespaces_default = {
|
|
330
|
+
svg: "http://www.w3.org/2000/svg",
|
|
331
|
+
xhtml,
|
|
332
|
+
xlink: "http://www.w3.org/1999/xlink",
|
|
333
|
+
xml: "http://www.w3.org/XML/1998/namespace",
|
|
334
|
+
xmlns: "http://www.w3.org/2000/xmlns/"
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// node_modules/d3-selection/src/namespace.js
|
|
338
|
+
function namespace_default(name) {
|
|
339
|
+
var prefix = name += "", i = prefix.indexOf(":");
|
|
340
|
+
if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
|
|
341
|
+
return namespaces_default.hasOwnProperty(prefix) ? { space: namespaces_default[prefix], local: name } : name;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// node_modules/d3-selection/src/creator.js
|
|
345
|
+
function creatorInherit(name) {
|
|
346
|
+
return function() {
|
|
347
|
+
var document2 = this.ownerDocument, uri = this.namespaceURI;
|
|
348
|
+
return uri === xhtml && document2.documentElement.namespaceURI === xhtml ? document2.createElement(name) : document2.createElementNS(uri, name);
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
function creatorFixed(fullname) {
|
|
352
|
+
return function() {
|
|
353
|
+
return this.ownerDocument.createElementNS(fullname.space, fullname.local);
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function creator_default(name) {
|
|
357
|
+
var fullname = namespace_default(name);
|
|
358
|
+
return (fullname.local ? creatorFixed : creatorInherit)(fullname);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// node_modules/d3-selection/src/selector.js
|
|
362
|
+
function none() {
|
|
363
|
+
}
|
|
364
|
+
function selector_default(selector) {
|
|
365
|
+
return selector == null ? none : function() {
|
|
366
|
+
return this.querySelector(selector);
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// node_modules/d3-selection/src/selection/select.js
|
|
371
|
+
function select_default(select) {
|
|
372
|
+
if (typeof select !== "function") select = selector_default(select);
|
|
373
|
+
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
|
|
374
|
+
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
|
|
375
|
+
if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
|
|
376
|
+
if ("__data__" in node) subnode.__data__ = node.__data__;
|
|
377
|
+
subgroup[i] = subnode;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return new Selection(subgroups, this._parents);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// node_modules/d3-selection/src/array.js
|
|
385
|
+
function array(x) {
|
|
386
|
+
return x == null ? [] : Array.isArray(x) ? x : Array.from(x);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// node_modules/d3-selection/src/selectorAll.js
|
|
390
|
+
function empty() {
|
|
391
|
+
return [];
|
|
392
|
+
}
|
|
393
|
+
function selectorAll_default(selector) {
|
|
394
|
+
return selector == null ? empty : function() {
|
|
395
|
+
return this.querySelectorAll(selector);
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// node_modules/d3-selection/src/selection/selectAll.js
|
|
400
|
+
function arrayAll(select) {
|
|
401
|
+
return function() {
|
|
402
|
+
return array(select.apply(this, arguments));
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function selectAll_default(select) {
|
|
406
|
+
if (typeof select === "function") select = arrayAll(select);
|
|
407
|
+
else select = selectorAll_default(select);
|
|
408
|
+
for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
|
|
409
|
+
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
|
|
410
|
+
if (node = group[i]) {
|
|
411
|
+
subgroups.push(select.call(node, node.__data__, i, group));
|
|
412
|
+
parents.push(node);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return new Selection(subgroups, parents);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// node_modules/d3-selection/src/matcher.js
|
|
420
|
+
function matcher_default(selector) {
|
|
421
|
+
return function() {
|
|
422
|
+
return this.matches(selector);
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
function childMatcher(selector) {
|
|
426
|
+
return function(node) {
|
|
427
|
+
return node.matches(selector);
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// node_modules/d3-selection/src/selection/selectChild.js
|
|
432
|
+
var find = Array.prototype.find;
|
|
433
|
+
function childFind(match) {
|
|
434
|
+
return function() {
|
|
435
|
+
return find.call(this.children, match);
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
function childFirst() {
|
|
439
|
+
return this.firstElementChild;
|
|
440
|
+
}
|
|
441
|
+
function selectChild_default(match) {
|
|
442
|
+
return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match)));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// node_modules/d3-selection/src/selection/selectChildren.js
|
|
446
|
+
var filter = Array.prototype.filter;
|
|
447
|
+
function children() {
|
|
448
|
+
return Array.from(this.children);
|
|
449
|
+
}
|
|
450
|
+
function childrenFilter(match) {
|
|
451
|
+
return function() {
|
|
452
|
+
return filter.call(this.children, match);
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
function selectChildren_default(match) {
|
|
456
|
+
return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// node_modules/d3-selection/src/selection/filter.js
|
|
460
|
+
function filter_default(match) {
|
|
461
|
+
if (typeof match !== "function") match = matcher_default(match);
|
|
462
|
+
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
|
|
463
|
+
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
|
|
464
|
+
if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
|
|
465
|
+
subgroup.push(node);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return new Selection(subgroups, this._parents);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// node_modules/d3-selection/src/selection/sparse.js
|
|
473
|
+
function sparse_default(update) {
|
|
474
|
+
return new Array(update.length);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// node_modules/d3-selection/src/selection/enter.js
|
|
478
|
+
function enter_default() {
|
|
479
|
+
return new Selection(this._enter || this._groups.map(sparse_default), this._parents);
|
|
480
|
+
}
|
|
481
|
+
function EnterNode(parent, datum2) {
|
|
482
|
+
this.ownerDocument = parent.ownerDocument;
|
|
483
|
+
this.namespaceURI = parent.namespaceURI;
|
|
484
|
+
this._next = null;
|
|
485
|
+
this._parent = parent;
|
|
486
|
+
this.__data__ = datum2;
|
|
487
|
+
}
|
|
488
|
+
EnterNode.prototype = {
|
|
489
|
+
constructor: EnterNode,
|
|
490
|
+
appendChild: function(child) {
|
|
491
|
+
return this._parent.insertBefore(child, this._next);
|
|
492
|
+
},
|
|
493
|
+
insertBefore: function(child, next) {
|
|
494
|
+
return this._parent.insertBefore(child, next);
|
|
495
|
+
},
|
|
496
|
+
querySelector: function(selector) {
|
|
497
|
+
return this._parent.querySelector(selector);
|
|
498
|
+
},
|
|
499
|
+
querySelectorAll: function(selector) {
|
|
500
|
+
return this._parent.querySelectorAll(selector);
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
// node_modules/d3-selection/src/constant.js
|
|
505
|
+
function constant_default(x) {
|
|
506
|
+
return function() {
|
|
507
|
+
return x;
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// node_modules/d3-selection/src/selection/data.js
|
|
512
|
+
function bindIndex(parent, group, enter, update, exit, data) {
|
|
513
|
+
var i = 0, node, groupLength = group.length, dataLength = data.length;
|
|
514
|
+
for (; i < dataLength; ++i) {
|
|
515
|
+
if (node = group[i]) {
|
|
516
|
+
node.__data__ = data[i];
|
|
517
|
+
update[i] = node;
|
|
518
|
+
} else {
|
|
519
|
+
enter[i] = new EnterNode(parent, data[i]);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
for (; i < groupLength; ++i) {
|
|
523
|
+
if (node = group[i]) {
|
|
524
|
+
exit[i] = node;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function bindKey(parent, group, enter, update, exit, data, key) {
|
|
529
|
+
var i, node, nodeByKeyValue = /* @__PURE__ */ new Map(), groupLength = group.length, dataLength = data.length, keyValues = new Array(groupLength), keyValue;
|
|
530
|
+
for (i = 0; i < groupLength; ++i) {
|
|
531
|
+
if (node = group[i]) {
|
|
532
|
+
keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
|
|
533
|
+
if (nodeByKeyValue.has(keyValue)) {
|
|
534
|
+
exit[i] = node;
|
|
535
|
+
} else {
|
|
536
|
+
nodeByKeyValue.set(keyValue, node);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
for (i = 0; i < dataLength; ++i) {
|
|
541
|
+
keyValue = key.call(parent, data[i], i, data) + "";
|
|
542
|
+
if (node = nodeByKeyValue.get(keyValue)) {
|
|
543
|
+
update[i] = node;
|
|
544
|
+
node.__data__ = data[i];
|
|
545
|
+
nodeByKeyValue.delete(keyValue);
|
|
546
|
+
} else {
|
|
547
|
+
enter[i] = new EnterNode(parent, data[i]);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
for (i = 0; i < groupLength; ++i) {
|
|
551
|
+
if ((node = group[i]) && nodeByKeyValue.get(keyValues[i]) === node) {
|
|
552
|
+
exit[i] = node;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function datum(node) {
|
|
557
|
+
return node.__data__;
|
|
558
|
+
}
|
|
559
|
+
function data_default(value, key) {
|
|
560
|
+
if (!arguments.length) return Array.from(this, datum);
|
|
561
|
+
var bind = key ? bindKey : bindIndex, parents = this._parents, groups = this._groups;
|
|
562
|
+
if (typeof value !== "function") value = constant_default(value);
|
|
563
|
+
for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
|
|
564
|
+
var parent = parents[j], group = groups[j], groupLength = group.length, data = arraylike(value.call(parent, parent && parent.__data__, j, parents)), dataLength = data.length, enterGroup = enter[j] = new Array(dataLength), updateGroup = update[j] = new Array(dataLength), exitGroup = exit[j] = new Array(groupLength);
|
|
565
|
+
bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
|
|
566
|
+
for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
|
|
567
|
+
if (previous = enterGroup[i0]) {
|
|
568
|
+
if (i0 >= i1) i1 = i0 + 1;
|
|
569
|
+
while (!(next = updateGroup[i1]) && ++i1 < dataLength) ;
|
|
570
|
+
previous._next = next || null;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
update = new Selection(update, parents);
|
|
575
|
+
update._enter = enter;
|
|
576
|
+
update._exit = exit;
|
|
577
|
+
return update;
|
|
578
|
+
}
|
|
579
|
+
function arraylike(data) {
|
|
580
|
+
return typeof data === "object" && "length" in data ? data : Array.from(data);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// node_modules/d3-selection/src/selection/exit.js
|
|
584
|
+
function exit_default() {
|
|
585
|
+
return new Selection(this._exit || this._groups.map(sparse_default), this._parents);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// node_modules/d3-selection/src/selection/join.js
|
|
589
|
+
function join_default(onenter, onupdate, onexit) {
|
|
590
|
+
var enter = this.enter(), update = this, exit = this.exit();
|
|
591
|
+
if (typeof onenter === "function") {
|
|
592
|
+
enter = onenter(enter);
|
|
593
|
+
if (enter) enter = enter.selection();
|
|
594
|
+
} else {
|
|
595
|
+
enter = enter.append(onenter + "");
|
|
596
|
+
}
|
|
597
|
+
if (onupdate != null) {
|
|
598
|
+
update = onupdate(update);
|
|
599
|
+
if (update) update = update.selection();
|
|
600
|
+
}
|
|
601
|
+
if (onexit == null) exit.remove();
|
|
602
|
+
else onexit(exit);
|
|
603
|
+
return enter && update ? enter.merge(update).order() : update;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// node_modules/d3-selection/src/selection/merge.js
|
|
607
|
+
function merge_default(context) {
|
|
608
|
+
var selection2 = context.selection ? context.selection() : context;
|
|
609
|
+
for (var groups0 = this._groups, groups1 = selection2._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
|
|
610
|
+
for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
|
|
611
|
+
if (node = group0[i] || group1[i]) {
|
|
612
|
+
merge[i] = node;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
for (; j < m0; ++j) {
|
|
617
|
+
merges[j] = groups0[j];
|
|
618
|
+
}
|
|
619
|
+
return new Selection(merges, this._parents);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// node_modules/d3-selection/src/selection/order.js
|
|
623
|
+
function order_default() {
|
|
624
|
+
for (var groups = this._groups, j = -1, m = groups.length; ++j < m; ) {
|
|
625
|
+
for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
|
|
626
|
+
if (node = group[i]) {
|
|
627
|
+
if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
|
|
628
|
+
next = node;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return this;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// node_modules/d3-selection/src/selection/sort.js
|
|
636
|
+
function sort_default(compare) {
|
|
637
|
+
if (!compare) compare = ascending;
|
|
638
|
+
function compareNode(a, b) {
|
|
639
|
+
return a && b ? compare(a.__data__, b.__data__) : !a - !b;
|
|
640
|
+
}
|
|
641
|
+
for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
|
|
642
|
+
for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
|
|
643
|
+
if (node = group[i]) {
|
|
644
|
+
sortgroup[i] = node;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
sortgroup.sort(compareNode);
|
|
648
|
+
}
|
|
649
|
+
return new Selection(sortgroups, this._parents).order();
|
|
650
|
+
}
|
|
651
|
+
function ascending(a, b) {
|
|
652
|
+
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// node_modules/d3-selection/src/selection/call.js
|
|
656
|
+
function call_default() {
|
|
657
|
+
var callback = arguments[0];
|
|
658
|
+
arguments[0] = this;
|
|
659
|
+
callback.apply(null, arguments);
|
|
660
|
+
return this;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// node_modules/d3-selection/src/selection/nodes.js
|
|
664
|
+
function nodes_default() {
|
|
665
|
+
return Array.from(this);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// node_modules/d3-selection/src/selection/node.js
|
|
669
|
+
function node_default() {
|
|
670
|
+
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
|
|
671
|
+
for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
|
|
672
|
+
var node = group[i];
|
|
673
|
+
if (node) return node;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// node_modules/d3-selection/src/selection/size.js
|
|
680
|
+
function size_default() {
|
|
681
|
+
let size = 0;
|
|
682
|
+
for (const node of this) ++size;
|
|
683
|
+
return size;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// node_modules/d3-selection/src/selection/empty.js
|
|
687
|
+
function empty_default() {
|
|
688
|
+
return !this.node();
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// node_modules/d3-selection/src/selection/each.js
|
|
692
|
+
function each_default(callback) {
|
|
693
|
+
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
|
|
694
|
+
for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
|
|
695
|
+
if (node = group[i]) callback.call(node, node.__data__, i, group);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return this;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// node_modules/d3-selection/src/selection/attr.js
|
|
702
|
+
function attrRemove(name) {
|
|
703
|
+
return function() {
|
|
704
|
+
this.removeAttribute(name);
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
function attrRemoveNS(fullname) {
|
|
708
|
+
return function() {
|
|
709
|
+
this.removeAttributeNS(fullname.space, fullname.local);
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
function attrConstant(name, value) {
|
|
713
|
+
return function() {
|
|
714
|
+
this.setAttribute(name, value);
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
function attrConstantNS(fullname, value) {
|
|
718
|
+
return function() {
|
|
719
|
+
this.setAttributeNS(fullname.space, fullname.local, value);
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
function attrFunction(name, value) {
|
|
723
|
+
return function() {
|
|
724
|
+
var v = value.apply(this, arguments);
|
|
725
|
+
if (v == null) this.removeAttribute(name);
|
|
726
|
+
else this.setAttribute(name, v);
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
function attrFunctionNS(fullname, value) {
|
|
730
|
+
return function() {
|
|
731
|
+
var v = value.apply(this, arguments);
|
|
732
|
+
if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
|
|
733
|
+
else this.setAttributeNS(fullname.space, fullname.local, v);
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
function attr_default(name, value) {
|
|
737
|
+
var fullname = namespace_default(name);
|
|
738
|
+
if (arguments.length < 2) {
|
|
739
|
+
var node = this.node();
|
|
740
|
+
return fullname.local ? node.getAttributeNS(fullname.space, fullname.local) : node.getAttribute(fullname);
|
|
741
|
+
}
|
|
742
|
+
return this.each((value == null ? fullname.local ? attrRemoveNS : attrRemove : typeof value === "function" ? fullname.local ? attrFunctionNS : attrFunction : fullname.local ? attrConstantNS : attrConstant)(fullname, value));
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// node_modules/d3-selection/src/window.js
|
|
746
|
+
function window_default(node) {
|
|
747
|
+
return node.ownerDocument && node.ownerDocument.defaultView || node.document && node || node.defaultView;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// node_modules/d3-selection/src/selection/style.js
|
|
751
|
+
function styleRemove(name) {
|
|
752
|
+
return function() {
|
|
753
|
+
this.style.removeProperty(name);
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
function styleConstant(name, value, priority) {
|
|
757
|
+
return function() {
|
|
758
|
+
this.style.setProperty(name, value, priority);
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
function styleFunction(name, value, priority) {
|
|
762
|
+
return function() {
|
|
763
|
+
var v = value.apply(this, arguments);
|
|
764
|
+
if (v == null) this.style.removeProperty(name);
|
|
765
|
+
else this.style.setProperty(name, v, priority);
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
function style_default(name, value, priority) {
|
|
769
|
+
return arguments.length > 1 ? this.each((value == null ? styleRemove : typeof value === "function" ? styleFunction : styleConstant)(name, value, priority == null ? "" : priority)) : styleValue(this.node(), name);
|
|
770
|
+
}
|
|
771
|
+
function styleValue(node, name) {
|
|
772
|
+
return node.style.getPropertyValue(name) || window_default(node).getComputedStyle(node, null).getPropertyValue(name);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// node_modules/d3-selection/src/selection/property.js
|
|
776
|
+
function propertyRemove(name) {
|
|
777
|
+
return function() {
|
|
778
|
+
delete this[name];
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
function propertyConstant(name, value) {
|
|
782
|
+
return function() {
|
|
783
|
+
this[name] = value;
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
function propertyFunction(name, value) {
|
|
787
|
+
return function() {
|
|
788
|
+
var v = value.apply(this, arguments);
|
|
789
|
+
if (v == null) delete this[name];
|
|
790
|
+
else this[name] = v;
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
function property_default(name, value) {
|
|
794
|
+
return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name, value)) : this.node()[name];
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// node_modules/d3-selection/src/selection/classed.js
|
|
798
|
+
function classArray(string) {
|
|
799
|
+
return string.trim().split(/^|\s+/);
|
|
800
|
+
}
|
|
801
|
+
function classList(node) {
|
|
802
|
+
return node.classList || new ClassList(node);
|
|
803
|
+
}
|
|
804
|
+
function ClassList(node) {
|
|
805
|
+
this._node = node;
|
|
806
|
+
this._names = classArray(node.getAttribute("class") || "");
|
|
807
|
+
}
|
|
808
|
+
ClassList.prototype = {
|
|
809
|
+
add: function(name) {
|
|
810
|
+
var i = this._names.indexOf(name);
|
|
811
|
+
if (i < 0) {
|
|
812
|
+
this._names.push(name);
|
|
813
|
+
this._node.setAttribute("class", this._names.join(" "));
|
|
814
|
+
}
|
|
815
|
+
},
|
|
816
|
+
remove: function(name) {
|
|
817
|
+
var i = this._names.indexOf(name);
|
|
818
|
+
if (i >= 0) {
|
|
819
|
+
this._names.splice(i, 1);
|
|
820
|
+
this._node.setAttribute("class", this._names.join(" "));
|
|
821
|
+
}
|
|
822
|
+
},
|
|
823
|
+
contains: function(name) {
|
|
824
|
+
return this._names.indexOf(name) >= 0;
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
function classedAdd(node, names) {
|
|
828
|
+
var list = classList(node), i = -1, n = names.length;
|
|
829
|
+
while (++i < n) list.add(names[i]);
|
|
830
|
+
}
|
|
831
|
+
function classedRemove(node, names) {
|
|
832
|
+
var list = classList(node), i = -1, n = names.length;
|
|
833
|
+
while (++i < n) list.remove(names[i]);
|
|
834
|
+
}
|
|
835
|
+
function classedTrue(names) {
|
|
836
|
+
return function() {
|
|
837
|
+
classedAdd(this, names);
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
function classedFalse(names) {
|
|
841
|
+
return function() {
|
|
842
|
+
classedRemove(this, names);
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
function classedFunction(names, value) {
|
|
846
|
+
return function() {
|
|
847
|
+
(value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
function classed_default(name, value) {
|
|
851
|
+
var names = classArray(name + "");
|
|
852
|
+
if (arguments.length < 2) {
|
|
853
|
+
var list = classList(this.node()), i = -1, n = names.length;
|
|
854
|
+
while (++i < n) if (!list.contains(names[i])) return false;
|
|
855
|
+
return true;
|
|
856
|
+
}
|
|
857
|
+
return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// node_modules/d3-selection/src/selection/text.js
|
|
861
|
+
function textRemove() {
|
|
862
|
+
this.textContent = "";
|
|
863
|
+
}
|
|
864
|
+
function textConstant(value) {
|
|
865
|
+
return function() {
|
|
866
|
+
this.textContent = value;
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
function textFunction(value) {
|
|
870
|
+
return function() {
|
|
871
|
+
var v = value.apply(this, arguments);
|
|
872
|
+
this.textContent = v == null ? "" : v;
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
function text_default(value) {
|
|
876
|
+
return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction : textConstant)(value)) : this.node().textContent;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// node_modules/d3-selection/src/selection/html.js
|
|
880
|
+
function htmlRemove() {
|
|
881
|
+
this.innerHTML = "";
|
|
882
|
+
}
|
|
883
|
+
function htmlConstant(value) {
|
|
884
|
+
return function() {
|
|
885
|
+
this.innerHTML = value;
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
function htmlFunction(value) {
|
|
889
|
+
return function() {
|
|
890
|
+
var v = value.apply(this, arguments);
|
|
891
|
+
this.innerHTML = v == null ? "" : v;
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
function html_default(value) {
|
|
895
|
+
return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// node_modules/d3-selection/src/selection/raise.js
|
|
899
|
+
function raise() {
|
|
900
|
+
if (this.nextSibling) this.parentNode.appendChild(this);
|
|
901
|
+
}
|
|
902
|
+
function raise_default() {
|
|
903
|
+
return this.each(raise);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// node_modules/d3-selection/src/selection/lower.js
|
|
907
|
+
function lower() {
|
|
908
|
+
if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
|
|
909
|
+
}
|
|
910
|
+
function lower_default() {
|
|
911
|
+
return this.each(lower);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// node_modules/d3-selection/src/selection/append.js
|
|
915
|
+
function append_default(name) {
|
|
916
|
+
var create = typeof name === "function" ? name : creator_default(name);
|
|
917
|
+
return this.select(function() {
|
|
918
|
+
return this.appendChild(create.apply(this, arguments));
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// node_modules/d3-selection/src/selection/insert.js
|
|
923
|
+
function constantNull() {
|
|
924
|
+
return null;
|
|
925
|
+
}
|
|
926
|
+
function insert_default(name, before) {
|
|
927
|
+
var create = typeof name === "function" ? name : creator_default(name), select = before == null ? constantNull : typeof before === "function" ? before : selector_default(before);
|
|
928
|
+
return this.select(function() {
|
|
929
|
+
return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// node_modules/d3-selection/src/selection/remove.js
|
|
934
|
+
function remove() {
|
|
935
|
+
var parent = this.parentNode;
|
|
936
|
+
if (parent) parent.removeChild(this);
|
|
937
|
+
}
|
|
938
|
+
function remove_default() {
|
|
939
|
+
return this.each(remove);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// node_modules/d3-selection/src/selection/clone.js
|
|
943
|
+
function selection_cloneShallow() {
|
|
944
|
+
var clone2 = this.cloneNode(false), parent = this.parentNode;
|
|
945
|
+
return parent ? parent.insertBefore(clone2, this.nextSibling) : clone2;
|
|
946
|
+
}
|
|
947
|
+
function selection_cloneDeep() {
|
|
948
|
+
var clone2 = this.cloneNode(true), parent = this.parentNode;
|
|
949
|
+
return parent ? parent.insertBefore(clone2, this.nextSibling) : clone2;
|
|
950
|
+
}
|
|
951
|
+
function clone_default(deep) {
|
|
952
|
+
return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// node_modules/d3-selection/src/selection/datum.js
|
|
956
|
+
function datum_default(value) {
|
|
957
|
+
return arguments.length ? this.property("__data__", value) : this.node().__data__;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// node_modules/d3-selection/src/selection/on.js
|
|
961
|
+
function contextListener(listener) {
|
|
962
|
+
return function(event) {
|
|
963
|
+
listener.call(this, event, this.__data__);
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
function parseTypenames(typenames) {
|
|
967
|
+
return typenames.trim().split(/^|\s+/).map(function(t) {
|
|
968
|
+
var name = "", i = t.indexOf(".");
|
|
969
|
+
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
|
|
970
|
+
return { type: t, name };
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
function onRemove(typename) {
|
|
974
|
+
return function() {
|
|
975
|
+
var on = this.__on;
|
|
976
|
+
if (!on) return;
|
|
977
|
+
for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
|
|
978
|
+
if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
|
|
979
|
+
this.removeEventListener(o.type, o.listener, o.options);
|
|
980
|
+
} else {
|
|
981
|
+
on[++i] = o;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
if (++i) on.length = i;
|
|
985
|
+
else delete this.__on;
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
function onAdd(typename, value, options) {
|
|
989
|
+
return function() {
|
|
990
|
+
var on = this.__on, o, listener = contextListener(value);
|
|
991
|
+
if (on) for (var j = 0, m = on.length; j < m; ++j) {
|
|
992
|
+
if ((o = on[j]).type === typename.type && o.name === typename.name) {
|
|
993
|
+
this.removeEventListener(o.type, o.listener, o.options);
|
|
994
|
+
this.addEventListener(o.type, o.listener = listener, o.options = options);
|
|
995
|
+
o.value = value;
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
this.addEventListener(typename.type, listener, options);
|
|
1000
|
+
o = { type: typename.type, name: typename.name, value, listener, options };
|
|
1001
|
+
if (!on) this.__on = [o];
|
|
1002
|
+
else on.push(o);
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
function on_default(typename, value, options) {
|
|
1006
|
+
var typenames = parseTypenames(typename + ""), i, n = typenames.length, t;
|
|
1007
|
+
if (arguments.length < 2) {
|
|
1008
|
+
var on = this.node().__on;
|
|
1009
|
+
if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
|
|
1010
|
+
for (i = 0, o = on[j]; i < n; ++i) {
|
|
1011
|
+
if ((t = typenames[i]).type === o.type && t.name === o.name) {
|
|
1012
|
+
return o.value;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
on = value ? onAdd : onRemove;
|
|
1019
|
+
for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options));
|
|
1020
|
+
return this;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// node_modules/d3-selection/src/selection/dispatch.js
|
|
1024
|
+
function dispatchEvent(node, type, params) {
|
|
1025
|
+
var window = window_default(node), event = window.CustomEvent;
|
|
1026
|
+
if (typeof event === "function") {
|
|
1027
|
+
event = new event(type, params);
|
|
1028
|
+
} else {
|
|
1029
|
+
event = window.document.createEvent("Event");
|
|
1030
|
+
if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
|
|
1031
|
+
else event.initEvent(type, false, false);
|
|
1032
|
+
}
|
|
1033
|
+
node.dispatchEvent(event);
|
|
1034
|
+
}
|
|
1035
|
+
function dispatchConstant(type, params) {
|
|
1036
|
+
return function() {
|
|
1037
|
+
return dispatchEvent(this, type, params);
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
function dispatchFunction(type, params) {
|
|
1041
|
+
return function() {
|
|
1042
|
+
return dispatchEvent(this, type, params.apply(this, arguments));
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
function dispatch_default(type, params) {
|
|
1046
|
+
return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type, params));
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// node_modules/d3-selection/src/selection/iterator.js
|
|
1050
|
+
function* iterator_default() {
|
|
1051
|
+
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
|
|
1052
|
+
for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
|
|
1053
|
+
if (node = group[i]) yield node;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// node_modules/d3-selection/src/selection/index.js
|
|
1059
|
+
var root = [null];
|
|
1060
|
+
function Selection(groups, parents) {
|
|
1061
|
+
this._groups = groups;
|
|
1062
|
+
this._parents = parents;
|
|
1063
|
+
}
|
|
1064
|
+
function selection() {
|
|
1065
|
+
return new Selection([[document.documentElement]], root);
|
|
1066
|
+
}
|
|
1067
|
+
function selection_selection() {
|
|
1068
|
+
return this;
|
|
1069
|
+
}
|
|
1070
|
+
Selection.prototype = selection.prototype = {
|
|
1071
|
+
constructor: Selection,
|
|
1072
|
+
select: select_default,
|
|
1073
|
+
selectAll: selectAll_default,
|
|
1074
|
+
selectChild: selectChild_default,
|
|
1075
|
+
selectChildren: selectChildren_default,
|
|
1076
|
+
filter: filter_default,
|
|
1077
|
+
data: data_default,
|
|
1078
|
+
enter: enter_default,
|
|
1079
|
+
exit: exit_default,
|
|
1080
|
+
join: join_default,
|
|
1081
|
+
merge: merge_default,
|
|
1082
|
+
selection: selection_selection,
|
|
1083
|
+
order: order_default,
|
|
1084
|
+
sort: sort_default,
|
|
1085
|
+
call: call_default,
|
|
1086
|
+
nodes: nodes_default,
|
|
1087
|
+
node: node_default,
|
|
1088
|
+
size: size_default,
|
|
1089
|
+
empty: empty_default,
|
|
1090
|
+
each: each_default,
|
|
1091
|
+
attr: attr_default,
|
|
1092
|
+
style: style_default,
|
|
1093
|
+
property: property_default,
|
|
1094
|
+
classed: classed_default,
|
|
1095
|
+
text: text_default,
|
|
1096
|
+
html: html_default,
|
|
1097
|
+
raise: raise_default,
|
|
1098
|
+
lower: lower_default,
|
|
1099
|
+
append: append_default,
|
|
1100
|
+
insert: insert_default,
|
|
1101
|
+
remove: remove_default,
|
|
1102
|
+
clone: clone_default,
|
|
1103
|
+
datum: datum_default,
|
|
1104
|
+
on: on_default,
|
|
1105
|
+
dispatch: dispatch_default,
|
|
1106
|
+
[Symbol.iterator]: iterator_default
|
|
1107
|
+
};
|
|
1108
|
+
|
|
1109
|
+
// node_modules/d3-selection/src/select.js
|
|
1110
|
+
function select_default2(selector) {
|
|
1111
|
+
return typeof selector === "string" ? new Selection([[document.querySelector(selector)]], [document.documentElement]) : new Selection([[selector]], root);
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// node_modules/d3-interpolate/src/number.js
|
|
1115
|
+
function number_default(a, b) {
|
|
1116
|
+
return a = +a, b = +b, function(t) {
|
|
1117
|
+
return a * (1 - t) + b * t;
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// node_modules/d3-ease/src/cubic.js
|
|
1122
|
+
function cubicOut(t) {
|
|
1123
|
+
return --t * t * t + 1;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// src/svg/SvgFlowEditor.ts
|
|
1127
|
+
var NS = "http://www.w3.org/2000/svg";
|
|
1128
|
+
var instances = 0;
|
|
1129
|
+
var SvgFlowEditor = class {
|
|
1130
|
+
constructor(svg, store, options = {}) {
|
|
1131
|
+
this.svg = svg;
|
|
1132
|
+
this.store = store;
|
|
1133
|
+
this.options = options;
|
|
1134
|
+
if (!svg || svg.namespaceURI !== NS || svg.tagName.toLowerCase() !== "svg")
|
|
1135
|
+
throw new FlowError("INVALID_SVG", "Expected an SVG root element.");
|
|
1136
|
+
this.width = options.width ?? 1e3;
|
|
1137
|
+
this.height = options.height ?? 600;
|
|
1138
|
+
this.checkSize(this.width, this.height);
|
|
1139
|
+
this.animationDuration = options.animationDuration ?? 180;
|
|
1140
|
+
if (!Number.isFinite(this.animationDuration) || this.animationDuration < 0 || this.animationDuration > 5e3)
|
|
1141
|
+
throw new FlowError(
|
|
1142
|
+
"INVALID_DURATION",
|
|
1143
|
+
"animationDuration must be between 0 and 5000 milliseconds."
|
|
1144
|
+
);
|
|
1145
|
+
if (options.force !== false)
|
|
1146
|
+
this.placement = new ForcePlacement(
|
|
1147
|
+
store.getSnapshot(),
|
|
1148
|
+
typeof options.force === "object" ? options.force : {}
|
|
1149
|
+
);
|
|
1150
|
+
this.capabilities = options.capabilities ? [...options.capabilities] : void 0;
|
|
1151
|
+
const instance = `flow-${++instances}-${Math.random().toString(36).slice(2)}`;
|
|
1152
|
+
this.markerId = `${instance}-arrow`;
|
|
1153
|
+
this.tooltip = options.tooltips === false ? null : new NodeTooltip(svg.ownerDocument, `${instance}-tooltip`);
|
|
1154
|
+
this.root = this.element("g", {
|
|
1155
|
+
"data-flow-root": instance,
|
|
1156
|
+
role: "group",
|
|
1157
|
+
"aria-label": options.ariaLabel ?? "Flow editor",
|
|
1158
|
+
tabindex: "0",
|
|
1159
|
+
style: "touch-action: none; user-select: none"
|
|
1160
|
+
});
|
|
1161
|
+
const defs = this.element("defs");
|
|
1162
|
+
const marker = this.element("marker", {
|
|
1163
|
+
id: this.markerId,
|
|
1164
|
+
viewBox: "0 -5 10 10",
|
|
1165
|
+
refX: "9",
|
|
1166
|
+
refY: "0",
|
|
1167
|
+
markerWidth: "7",
|
|
1168
|
+
markerHeight: "7",
|
|
1169
|
+
orient: "auto-start-reverse"
|
|
1170
|
+
});
|
|
1171
|
+
marker.append(
|
|
1172
|
+
this.element("path", { d: "M0,-5L10,0L0,5", fill: "context-stroke" })
|
|
1173
|
+
);
|
|
1174
|
+
defs.append(marker);
|
|
1175
|
+
this.background = this.element("rect", {
|
|
1176
|
+
x: "0",
|
|
1177
|
+
y: "0",
|
|
1178
|
+
width: String(this.width),
|
|
1179
|
+
height: String(this.height),
|
|
1180
|
+
fill: "transparent"
|
|
1181
|
+
});
|
|
1182
|
+
this.viewportGroup = this.element("g");
|
|
1183
|
+
this.edgesGroup = this.element("g", { "data-layer": "edges" });
|
|
1184
|
+
this.nodesGroup = this.element("g", { "data-layer": "nodes" });
|
|
1185
|
+
this.viewportGroup.append(this.edgesGroup, this.nodesGroup);
|
|
1186
|
+
this.root.append(defs, this.background, this.viewportGroup);
|
|
1187
|
+
svg.append(this.root);
|
|
1188
|
+
this.listen(
|
|
1189
|
+
this.root,
|
|
1190
|
+
"pointerover",
|
|
1191
|
+
(event) => this.hover(event)
|
|
1192
|
+
);
|
|
1193
|
+
this.listen(this.root, "pointerout", (event) => {
|
|
1194
|
+
const related = event.relatedTarget;
|
|
1195
|
+
if (!related || !this.target(event)?.contains(related)) {
|
|
1196
|
+
this.suppressedTooltipId = null;
|
|
1197
|
+
this.clearHover();
|
|
1198
|
+
}
|
|
1199
|
+
});
|
|
1200
|
+
this.listen(this.root, "focusin", (event) => this.hover(event));
|
|
1201
|
+
this.listen(this.root, "focusout", () => {
|
|
1202
|
+
this.suppressedTooltipId = null;
|
|
1203
|
+
this.clearHover();
|
|
1204
|
+
});
|
|
1205
|
+
this.listen(this.root, "click", (event) => this.click(event));
|
|
1206
|
+
this.listen(this.root, "dblclick", (event) => {
|
|
1207
|
+
const id = this.target(event)?.getAttribute("data-node-id");
|
|
1208
|
+
const node = this.store.getSnapshot().nodes.find((item) => item.id === id);
|
|
1209
|
+
if (node) this.options.onNodeActivate?.(node);
|
|
1210
|
+
});
|
|
1211
|
+
this.listen(
|
|
1212
|
+
this.root,
|
|
1213
|
+
"keydown",
|
|
1214
|
+
(event) => this.keydown(event)
|
|
1215
|
+
);
|
|
1216
|
+
this.listen(
|
|
1217
|
+
this.root,
|
|
1218
|
+
"pointerdown",
|
|
1219
|
+
(event) => this.pointerdown(event)
|
|
1220
|
+
);
|
|
1221
|
+
const window = svg.ownerDocument.defaultView;
|
|
1222
|
+
const media = window?.matchMedia?.("(prefers-reduced-motion: reduce)");
|
|
1223
|
+
this.reducedMotion = options.motion === "reduced" || options.motion !== "full" && Boolean(media?.matches);
|
|
1224
|
+
if (media && (!options.motion || options.motion === "auto")) {
|
|
1225
|
+
this.listen(media, "change", (event) => {
|
|
1226
|
+
this.reducedMotion = event.matches;
|
|
1227
|
+
if (this.reducedMotion) {
|
|
1228
|
+
this.viewportTimer?.stop();
|
|
1229
|
+
this.viewportTimer = null;
|
|
1230
|
+
this.placement?.stop();
|
|
1231
|
+
this.render();
|
|
1232
|
+
}
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
if (window) {
|
|
1236
|
+
this.listen(
|
|
1237
|
+
window,
|
|
1238
|
+
"pointermove",
|
|
1239
|
+
(event) => this.pointermove(event)
|
|
1240
|
+
);
|
|
1241
|
+
this.listen(
|
|
1242
|
+
window,
|
|
1243
|
+
"pointerup",
|
|
1244
|
+
(event) => this.pointerup(event)
|
|
1245
|
+
);
|
|
1246
|
+
this.listen(window, "pointercancel", () => this.cancelDrag());
|
|
1247
|
+
this.listen(window, "blur", () => {
|
|
1248
|
+
this.clearHover();
|
|
1249
|
+
this.cancelDrag();
|
|
1250
|
+
});
|
|
1251
|
+
this.listen(window, "scroll", () => this.clearHover(), { capture: true });
|
|
1252
|
+
this.listen(window, "resize", () => this.clearHover());
|
|
1253
|
+
}
|
|
1254
|
+
this.listen(
|
|
1255
|
+
this.root,
|
|
1256
|
+
"wheel",
|
|
1257
|
+
(event) => {
|
|
1258
|
+
const wheel = event;
|
|
1259
|
+
wheel.preventDefault();
|
|
1260
|
+
this.zoomBy(wheel.deltaY < 0 ? 1.1 : 1 / 1.1, this.point(wheel));
|
|
1261
|
+
},
|
|
1262
|
+
{ passive: false }
|
|
1263
|
+
);
|
|
1264
|
+
this.unsubscribe = store.subscribe(() => {
|
|
1265
|
+
if (this.drag?.kind === "node" && !store.getSnapshot().nodes.some((node) => node.id === this.drag.id))
|
|
1266
|
+
this.drag = null;
|
|
1267
|
+
const changed = this.placement?.update(store.getSnapshot());
|
|
1268
|
+
if (this.selected && !(this.selected.type === "node" ? store.getSnapshot().nodes : this.selected.type === "global" ? store.getSnapshot().globals ?? [] : store.getSnapshot().edges).some((item) => item.id === this.selected.id))
|
|
1269
|
+
this.select(null);
|
|
1270
|
+
if (this.connection && !store.getSnapshot().nodes.some((node) => node.id === this.connection))
|
|
1271
|
+
this.connection = null;
|
|
1272
|
+
if (this.reconnection && !store.getSnapshot().edges.some((edge) => edge.id === this.reconnection.edgeId)) {
|
|
1273
|
+
this.reconnection = null;
|
|
1274
|
+
this.connection = null;
|
|
1275
|
+
}
|
|
1276
|
+
this.render();
|
|
1277
|
+
if (changed) this.relax();
|
|
1278
|
+
});
|
|
1279
|
+
if (this.placement) this.observePlacement();
|
|
1280
|
+
this.render();
|
|
1281
|
+
if (this.placement) this.relax();
|
|
1282
|
+
}
|
|
1283
|
+
svg;
|
|
1284
|
+
store;
|
|
1285
|
+
options;
|
|
1286
|
+
root;
|
|
1287
|
+
background;
|
|
1288
|
+
viewportGroup;
|
|
1289
|
+
edgesGroup;
|
|
1290
|
+
nodesGroup;
|
|
1291
|
+
markerId;
|
|
1292
|
+
cleanup = [];
|
|
1293
|
+
unsubscribe;
|
|
1294
|
+
context = {};
|
|
1295
|
+
execution = null;
|
|
1296
|
+
capabilities;
|
|
1297
|
+
viewOverrides = /* @__PURE__ */ new Map();
|
|
1298
|
+
selected = null;
|
|
1299
|
+
connection = null;
|
|
1300
|
+
reconnection = null;
|
|
1301
|
+
viewport = { x: 0, y: 0, scale: 1 };
|
|
1302
|
+
drag = null;
|
|
1303
|
+
destroyed = false;
|
|
1304
|
+
suppressClick = false;
|
|
1305
|
+
width;
|
|
1306
|
+
height;
|
|
1307
|
+
placement = null;
|
|
1308
|
+
positions = /* @__PURE__ */ new Map();
|
|
1309
|
+
positionTimer = null;
|
|
1310
|
+
viewportTimer = null;
|
|
1311
|
+
reducedMotion = false;
|
|
1312
|
+
animationDuration;
|
|
1313
|
+
tooltip;
|
|
1314
|
+
hovered = null;
|
|
1315
|
+
suppressedTooltipId = null;
|
|
1316
|
+
getSelection() {
|
|
1317
|
+
return this.selected ? { ...this.selected } : null;
|
|
1318
|
+
}
|
|
1319
|
+
getViewport() {
|
|
1320
|
+
return { ...this.viewport };
|
|
1321
|
+
}
|
|
1322
|
+
select(selection2) {
|
|
1323
|
+
this.alive();
|
|
1324
|
+
if (selection2) {
|
|
1325
|
+
const items = selection2.type === "node" ? this.store.getSnapshot().nodes : selection2.type === "global" ? this.store.getSnapshot().globals ?? [] : this.store.getSnapshot().edges;
|
|
1326
|
+
if (!items.some((item) => item.id === selection2.id))
|
|
1327
|
+
throw new FlowError(
|
|
1328
|
+
"SELECTION_NOT_FOUND",
|
|
1329
|
+
`Unknown ${selection2.type} ${selection2.id}.`
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
this.selected = selection2 ? { ...selection2 } : null;
|
|
1333
|
+
this.render();
|
|
1334
|
+
this.options.onSelect?.(this.getSelection());
|
|
1335
|
+
}
|
|
1336
|
+
setContext(context) {
|
|
1337
|
+
this.alive();
|
|
1338
|
+
assertJson(context);
|
|
1339
|
+
if (!context || typeof context !== "object" || Array.isArray(context))
|
|
1340
|
+
throw new FlowError("INVALID_CONTEXT", "Context must be a JSON object.");
|
|
1341
|
+
this.context = clone(context);
|
|
1342
|
+
this.render();
|
|
1343
|
+
}
|
|
1344
|
+
/** Display state supplied by a simulator or mapped from a real external runtime. */
|
|
1345
|
+
setExecution(snapshot) {
|
|
1346
|
+
this.alive();
|
|
1347
|
+
if (snapshot) assertJson(snapshot);
|
|
1348
|
+
this.execution = snapshot ? clone("nodes" in snapshot ? snapshot : simulationOverlay(snapshot)) : null;
|
|
1349
|
+
this.render();
|
|
1350
|
+
}
|
|
1351
|
+
setCapabilities(types) {
|
|
1352
|
+
this.alive();
|
|
1353
|
+
if (!Array.isArray(types) || !types.every((type) => typeof type === "string"))
|
|
1354
|
+
throw new FlowError(
|
|
1355
|
+
"INVALID_CAPABILITIES",
|
|
1356
|
+
"Expected advertised command type names."
|
|
1357
|
+
);
|
|
1358
|
+
this.capabilities = [...types];
|
|
1359
|
+
this.render();
|
|
1360
|
+
}
|
|
1361
|
+
beginConnection(source) {
|
|
1362
|
+
this.editable();
|
|
1363
|
+
if (!this.store.getSnapshot().nodes.some((node) => node.id === source))
|
|
1364
|
+
throw new FlowError("NODE_NOT_FOUND", `Unknown node ${source}.`);
|
|
1365
|
+
this.connection = source;
|
|
1366
|
+
this.reconnection = null;
|
|
1367
|
+
this.suppressClick = false;
|
|
1368
|
+
this.render();
|
|
1369
|
+
}
|
|
1370
|
+
/** Rewire an existing edge without losing its id, condition or signal metadata. */
|
|
1371
|
+
beginReconnection(edgeId, endpoint = "target") {
|
|
1372
|
+
this.editable();
|
|
1373
|
+
if (endpoint !== "source" && endpoint !== "target")
|
|
1374
|
+
throw new FlowError("INVALID_ENDPOINT", "Expected source or target.");
|
|
1375
|
+
const edge = this.store.getSnapshot().edges.find((edge2) => edge2.id === edgeId);
|
|
1376
|
+
if (!edge) throw new FlowError("EDGE_NOT_FOUND", `Unknown edge ${edgeId}.`);
|
|
1377
|
+
this.reconnection = { edgeId, endpoint };
|
|
1378
|
+
this.connection = endpoint === "target" ? edge.source : edge.target;
|
|
1379
|
+
this.suppressClick = false;
|
|
1380
|
+
this.render();
|
|
1381
|
+
}
|
|
1382
|
+
cancelConnection() {
|
|
1383
|
+
this.alive();
|
|
1384
|
+
this.connection = null;
|
|
1385
|
+
this.reconnection = null;
|
|
1386
|
+
this.render();
|
|
1387
|
+
}
|
|
1388
|
+
setViewport(viewport) {
|
|
1389
|
+
this.alive();
|
|
1390
|
+
if (![viewport.x, viewport.y, viewport.scale].every(Number.isFinite) || viewport.scale <= 0)
|
|
1391
|
+
throw new FlowError(
|
|
1392
|
+
"INVALID_VIEWPORT",
|
|
1393
|
+
"Expected finite coordinates and positive scale."
|
|
1394
|
+
);
|
|
1395
|
+
this.viewportTimer?.stop();
|
|
1396
|
+
this.viewportTimer = null;
|
|
1397
|
+
this.applyViewport(viewport);
|
|
1398
|
+
}
|
|
1399
|
+
applyViewport(viewport) {
|
|
1400
|
+
this.viewport = {
|
|
1401
|
+
...viewport,
|
|
1402
|
+
scale: Math.max(0.1, Math.min(4, viewport.scale))
|
|
1403
|
+
};
|
|
1404
|
+
this.viewportGroup.setAttribute(
|
|
1405
|
+
"transform",
|
|
1406
|
+
`translate(${this.viewport.x} ${this.viewport.y}) scale(${this.viewport.scale})`
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
animateViewport(viewport, duration = this.animationDuration) {
|
|
1410
|
+
this.alive();
|
|
1411
|
+
if (![viewport.x, viewport.y, viewport.scale, duration].every(
|
|
1412
|
+
Number.isFinite
|
|
1413
|
+
) || viewport.scale <= 0 || duration < 0 || duration > 5e3)
|
|
1414
|
+
throw new FlowError(
|
|
1415
|
+
"INVALID_VIEWPORT",
|
|
1416
|
+
"Expected a valid viewport and a duration between 0 and 5000 milliseconds."
|
|
1417
|
+
);
|
|
1418
|
+
this.viewportTimer?.stop();
|
|
1419
|
+
this.viewportTimer = null;
|
|
1420
|
+
if (this.reducedMotion || duration === 0) {
|
|
1421
|
+
this.setViewport(viewport);
|
|
1422
|
+
return;
|
|
1423
|
+
}
|
|
1424
|
+
const x = number_default(this.viewport.x, viewport.x);
|
|
1425
|
+
const y = number_default(this.viewport.y, viewport.y);
|
|
1426
|
+
const scale = number_default(
|
|
1427
|
+
this.viewport.scale,
|
|
1428
|
+
Math.max(0.1, Math.min(4, viewport.scale))
|
|
1429
|
+
);
|
|
1430
|
+
this.viewportTimer = timer((elapsed) => {
|
|
1431
|
+
const progress = Math.min(1, elapsed / duration);
|
|
1432
|
+
const eased = cubicOut(progress);
|
|
1433
|
+
this.applyViewport({ x: x(eased), y: y(eased), scale: scale(eased) });
|
|
1434
|
+
if (progress === 1) {
|
|
1435
|
+
this.viewportTimer?.stop();
|
|
1436
|
+
this.viewportTimer = null;
|
|
1437
|
+
}
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
zoomBy(factor, anchor = { x: this.width / 2, y: this.height / 2 }) {
|
|
1441
|
+
if (!Number.isFinite(factor) || factor <= 0)
|
|
1442
|
+
throw new FlowError("INVALID_ZOOM", "Zoom factor must be positive.");
|
|
1443
|
+
const previous = this.viewport;
|
|
1444
|
+
const scale = Math.max(0.1, Math.min(4, previous.scale * factor));
|
|
1445
|
+
this.setViewport({
|
|
1446
|
+
x: anchor.x - (anchor.x - previous.x) * scale / previous.scale,
|
|
1447
|
+
y: anchor.y - (anchor.y - previous.y) * scale / previous.scale,
|
|
1448
|
+
scale
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
fitToView(padding = 50, animate = false) {
|
|
1452
|
+
this.alive();
|
|
1453
|
+
if (!Number.isFinite(padding) || padding < 0 || padding * 2 >= Math.min(this.width, this.height))
|
|
1454
|
+
throw new FlowError(
|
|
1455
|
+
"INVALID_PADDING",
|
|
1456
|
+
"Padding must fit inside the viewport."
|
|
1457
|
+
);
|
|
1458
|
+
const nodes = visibleElements(this.store.getSnapshot(), this.context).nodes;
|
|
1459
|
+
if (!nodes.length) {
|
|
1460
|
+
this.setViewport({ x: 0, y: 0, scale: 1 });
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
const bounds = nodes.map((node) => ({
|
|
1464
|
+
point: this.positions.get(node.id) ?? node.position,
|
|
1465
|
+
size: nodeDimensions(node)
|
|
1466
|
+
}));
|
|
1467
|
+
const minX = Math.min(
|
|
1468
|
+
...bounds.map(({ point, size }) => point.x - size.width / 2)
|
|
1469
|
+
);
|
|
1470
|
+
const maxX = Math.max(
|
|
1471
|
+
...bounds.map(({ point, size }) => point.x + size.width / 2)
|
|
1472
|
+
);
|
|
1473
|
+
const minY = Math.min(
|
|
1474
|
+
...bounds.map(({ point, size }) => point.y - size.height / 2)
|
|
1475
|
+
);
|
|
1476
|
+
const maxY = Math.max(
|
|
1477
|
+
...bounds.map(
|
|
1478
|
+
({ point, size }) => point.y + size.height / 2 + (size.card ? 0 : 24)
|
|
1479
|
+
)
|
|
1480
|
+
);
|
|
1481
|
+
const scale = Math.max(
|
|
1482
|
+
0.1,
|
|
1483
|
+
Math.min(
|
|
1484
|
+
4,
|
|
1485
|
+
(this.width - padding * 2) / (maxX - minX),
|
|
1486
|
+
(this.height - padding * 2) / (maxY - minY)
|
|
1487
|
+
)
|
|
1488
|
+
);
|
|
1489
|
+
const viewport = {
|
|
1490
|
+
x: this.width / 2 - (minX + maxX) / 2 * scale,
|
|
1491
|
+
y: this.height / 2 - (minY + maxY) / 2 * scale,
|
|
1492
|
+
scale
|
|
1493
|
+
};
|
|
1494
|
+
if (animate) this.animateViewport(viewport);
|
|
1495
|
+
else this.setViewport(viewport);
|
|
1496
|
+
}
|
|
1497
|
+
/** Rendered coordinates are detached from the authored plan. */
|
|
1498
|
+
getNodePositions() {
|
|
1499
|
+
this.alive();
|
|
1500
|
+
return new Map(
|
|
1501
|
+
[...this.positions].map(([id, point]) => [id, { ...point }])
|
|
1502
|
+
);
|
|
1503
|
+
}
|
|
1504
|
+
relax() {
|
|
1505
|
+
this.alive();
|
|
1506
|
+
const placement = this.ensurePlacement();
|
|
1507
|
+
if (this.reducedMotion) {
|
|
1508
|
+
placement.stop();
|
|
1509
|
+
placement.tick(120);
|
|
1510
|
+
} else placement.restart();
|
|
1511
|
+
}
|
|
1512
|
+
stopForce() {
|
|
1513
|
+
this.alive();
|
|
1514
|
+
this.placement?.stop();
|
|
1515
|
+
}
|
|
1516
|
+
settlePlacement(iterations = 120) {
|
|
1517
|
+
this.alive();
|
|
1518
|
+
const placement = this.ensurePlacement();
|
|
1519
|
+
placement.stop();
|
|
1520
|
+
return placement.tick(iterations);
|
|
1521
|
+
}
|
|
1522
|
+
resetPlacement() {
|
|
1523
|
+
this.alive();
|
|
1524
|
+
this.placement?.destroy();
|
|
1525
|
+
this.placement = null;
|
|
1526
|
+
this.viewOverrides.clear();
|
|
1527
|
+
if (this.options.force !== false) {
|
|
1528
|
+
this.ensurePlacement();
|
|
1529
|
+
this.relax();
|
|
1530
|
+
}
|
|
1531
|
+
this.render();
|
|
1532
|
+
}
|
|
1533
|
+
/** Move/pin a node for this view only, including in read-only monitoring views. */
|
|
1534
|
+
moveNodeView(id, position) {
|
|
1535
|
+
this.alive();
|
|
1536
|
+
if (!this.store.getSnapshot().nodes.some((node) => node.id === id) || ![position.x, position.y].every(Number.isFinite))
|
|
1537
|
+
throw new FlowError(
|
|
1538
|
+
"INVALID_POSITION",
|
|
1539
|
+
"Expected an existing node and finite display coordinates."
|
|
1540
|
+
);
|
|
1541
|
+
this.viewOverrides.set(id, { ...position });
|
|
1542
|
+
this.placement?.pin(id, position);
|
|
1543
|
+
this.drawPositions(new Map(this.positions).set(id, { ...position }));
|
|
1544
|
+
if (!this.reducedMotion) this.placement?.restart();
|
|
1545
|
+
}
|
|
1546
|
+
resize(width, height) {
|
|
1547
|
+
this.alive();
|
|
1548
|
+
this.checkSize(width, height);
|
|
1549
|
+
this.width = width;
|
|
1550
|
+
this.height = height;
|
|
1551
|
+
this.background.setAttribute("width", String(width));
|
|
1552
|
+
this.background.setAttribute("height", String(height));
|
|
1553
|
+
}
|
|
1554
|
+
exportSvg() {
|
|
1555
|
+
this.alive();
|
|
1556
|
+
const output = this.element("svg", {
|
|
1557
|
+
xmlns: NS,
|
|
1558
|
+
width: String(this.width),
|
|
1559
|
+
height: String(this.height),
|
|
1560
|
+
viewBox: `0 0 ${this.width} ${this.height}`
|
|
1561
|
+
});
|
|
1562
|
+
output.append(this.root.cloneNode(true));
|
|
1563
|
+
return output.outerHTML;
|
|
1564
|
+
}
|
|
1565
|
+
destroy() {
|
|
1566
|
+
if (this.destroyed) return;
|
|
1567
|
+
this.unsubscribe();
|
|
1568
|
+
this.placement?.destroy();
|
|
1569
|
+
this.tooltip?.destroy();
|
|
1570
|
+
this.positionTimer?.stop();
|
|
1571
|
+
this.viewportTimer?.stop();
|
|
1572
|
+
for (const cleanup of this.cleanup) cleanup();
|
|
1573
|
+
this.root.remove();
|
|
1574
|
+
this.drag = null;
|
|
1575
|
+
this.destroyed = true;
|
|
1576
|
+
}
|
|
1577
|
+
render() {
|
|
1578
|
+
if (this.destroyed) return;
|
|
1579
|
+
const { nodes, edges } = visibleElements(
|
|
1580
|
+
this.store.getSnapshot(),
|
|
1581
|
+
this.context
|
|
1582
|
+
);
|
|
1583
|
+
const models = new Map(nodes.map((node) => [node.id, node]));
|
|
1584
|
+
const physics = this.placement?.getPositions();
|
|
1585
|
+
const targets = new Map(
|
|
1586
|
+
this.store.getSnapshot().nodes.map((node) => [
|
|
1587
|
+
node.id,
|
|
1588
|
+
this.drag?.kind === "node" && this.drag.id === node.id ? this.drag.preview : physics?.get(node.id) ?? this.viewOverrides.get(node.id) ?? node.position
|
|
1589
|
+
])
|
|
1590
|
+
);
|
|
1591
|
+
const positions = new Map(
|
|
1592
|
+
[...targets].map(([id, target]) => [
|
|
1593
|
+
id,
|
|
1594
|
+
this.positions.get(id) ?? target
|
|
1595
|
+
])
|
|
1596
|
+
);
|
|
1597
|
+
const editor = this;
|
|
1598
|
+
select_default2(this.edgesGroup).selectAll("g[data-edge-id]").data(edges, (edge) => edge.id).join("g").each(function(edge) {
|
|
1599
|
+
editor.patchGroup(this, editor.renderEdge(edge, positions, models));
|
|
1600
|
+
});
|
|
1601
|
+
select_default2(this.nodesGroup).selectAll("g[data-node-id]").data(nodes, (node) => node.id).join("g").each(function(node) {
|
|
1602
|
+
editor.patchGroup(
|
|
1603
|
+
this,
|
|
1604
|
+
editor.renderNode(node, positions.get(node.id))
|
|
1605
|
+
);
|
|
1606
|
+
});
|
|
1607
|
+
this.applyViewport(this.viewport);
|
|
1608
|
+
this.animatePositions(targets);
|
|
1609
|
+
this.refreshTooltip();
|
|
1610
|
+
}
|
|
1611
|
+
hover(event) {
|
|
1612
|
+
if (!this.tooltip || this.drag) return;
|
|
1613
|
+
const target = this.target(event);
|
|
1614
|
+
const id = target?.getAttribute("data-node-id");
|
|
1615
|
+
if (!id || !target) return;
|
|
1616
|
+
if (id === this.suppressedTooltipId) return;
|
|
1617
|
+
this.suppressedTooltipId = null;
|
|
1618
|
+
if (this.hovered?.id === id) return;
|
|
1619
|
+
const bounds = target.getBoundingClientRect();
|
|
1620
|
+
this.hovered = {
|
|
1621
|
+
id,
|
|
1622
|
+
x: event.type === "focusin" ? bounds.right : event.clientX,
|
|
1623
|
+
y: event.type === "focusin" ? bounds.top : event.clientY
|
|
1624
|
+
};
|
|
1625
|
+
this.refreshTooltip();
|
|
1626
|
+
}
|
|
1627
|
+
refreshTooltip() {
|
|
1628
|
+
if (!this.hovered || !this.tooltip) return;
|
|
1629
|
+
const node = this.store.getSnapshot().nodes.find((node2) => node2.id === this.hovered.id);
|
|
1630
|
+
const target = [...this.nodesGroup.children].find(
|
|
1631
|
+
(node2) => node2.getAttribute("data-node-id") === this.hovered.id
|
|
1632
|
+
);
|
|
1633
|
+
if (!node || !target) {
|
|
1634
|
+
this.clearHover();
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
const observation = this.execution && Object.hasOwn(this.execution.nodes, node.id) ? this.execution.nodes[node.id] : void 0;
|
|
1638
|
+
this.tooltip.show(
|
|
1639
|
+
node,
|
|
1640
|
+
this.store.getSnapshot(),
|
|
1641
|
+
observation,
|
|
1642
|
+
this.capabilities,
|
|
1643
|
+
target,
|
|
1644
|
+
this.hovered
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1647
|
+
clearHover(suppress = false) {
|
|
1648
|
+
if (suppress) this.suppressedTooltipId = this.hovered?.id ?? null;
|
|
1649
|
+
this.hovered = null;
|
|
1650
|
+
this.tooltip?.hide();
|
|
1651
|
+
}
|
|
1652
|
+
ensurePlacement() {
|
|
1653
|
+
if (!this.placement) {
|
|
1654
|
+
this.placement = new ForcePlacement(
|
|
1655
|
+
this.store.getSnapshot(),
|
|
1656
|
+
typeof this.options.force === "object" ? this.options.force : {}
|
|
1657
|
+
);
|
|
1658
|
+
this.observePlacement();
|
|
1659
|
+
}
|
|
1660
|
+
return this.placement;
|
|
1661
|
+
}
|
|
1662
|
+
observePlacement() {
|
|
1663
|
+
this.placement.subscribe((positions) => {
|
|
1664
|
+
if (this.destroyed) return;
|
|
1665
|
+
this.positionTimer?.stop();
|
|
1666
|
+
this.positionTimer = null;
|
|
1667
|
+
const next = new Map(positions);
|
|
1668
|
+
if (this.drag?.kind === "node")
|
|
1669
|
+
next.set(this.drag.id, this.drag.preview);
|
|
1670
|
+
this.drawPositions(next);
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
animatePositions(targets) {
|
|
1674
|
+
this.positionTimer?.stop();
|
|
1675
|
+
this.positionTimer = null;
|
|
1676
|
+
const moved = [...targets].some(([id, point]) => {
|
|
1677
|
+
const current = this.positions.get(id);
|
|
1678
|
+
return current && (point.x !== current.x || point.y !== current.y);
|
|
1679
|
+
});
|
|
1680
|
+
if (!moved || this.placement || this.drag || this.reducedMotion || this.animationDuration === 0) {
|
|
1681
|
+
this.drawPositions(targets);
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
const interpolators = [...targets].map(([id, end]) => {
|
|
1685
|
+
const start = this.positions.get(id) ?? end;
|
|
1686
|
+
return {
|
|
1687
|
+
id,
|
|
1688
|
+
x: number_default(start.x, end.x),
|
|
1689
|
+
y: number_default(start.y, end.y)
|
|
1690
|
+
};
|
|
1691
|
+
});
|
|
1692
|
+
this.drawPositions(
|
|
1693
|
+
new Map(
|
|
1694
|
+
interpolators.map((item) => [item.id, { x: item.x(0), y: item.y(0) }])
|
|
1695
|
+
)
|
|
1696
|
+
);
|
|
1697
|
+
this.positionTimer = timer((elapsed) => {
|
|
1698
|
+
const progress = Math.min(1, elapsed / this.animationDuration);
|
|
1699
|
+
const eased = cubicOut(progress);
|
|
1700
|
+
this.drawPositions(
|
|
1701
|
+
new Map(
|
|
1702
|
+
interpolators.map((item) => [
|
|
1703
|
+
item.id,
|
|
1704
|
+
{ x: item.x(eased), y: item.y(eased) }
|
|
1705
|
+
])
|
|
1706
|
+
)
|
|
1707
|
+
);
|
|
1708
|
+
if (progress === 1) {
|
|
1709
|
+
this.positionTimer?.stop();
|
|
1710
|
+
this.positionTimer = null;
|
|
1711
|
+
}
|
|
1712
|
+
});
|
|
1713
|
+
}
|
|
1714
|
+
drawPositions(positions) {
|
|
1715
|
+
this.positions = new Map(positions);
|
|
1716
|
+
const models = new Map(
|
|
1717
|
+
this.store.getSnapshot().nodes.map((node) => [node.id, node])
|
|
1718
|
+
);
|
|
1719
|
+
const editor = this;
|
|
1720
|
+
select_default2(this.nodesGroup).selectAll("g[data-node-id]").each(function(node) {
|
|
1721
|
+
const point = positions.get(node.id);
|
|
1722
|
+
this.setAttribute("transform", `translate(${point.x} ${point.y})`);
|
|
1723
|
+
});
|
|
1724
|
+
select_default2(this.edgesGroup).selectAll("g[data-edge-id]").each(function(edge) {
|
|
1725
|
+
const geometry = editor.edgeGeometry(edge, positions, models);
|
|
1726
|
+
for (const path of this.querySelectorAll("path"))
|
|
1727
|
+
path.setAttribute("d", geometry.path);
|
|
1728
|
+
const label = this.querySelector("text");
|
|
1729
|
+
label?.setAttribute("x", String(geometry.label.x));
|
|
1730
|
+
label?.setAttribute("y", String(geometry.label.y));
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
patchGroup(target, source) {
|
|
1734
|
+
for (const attribute of [...target.attributes])
|
|
1735
|
+
if (!source.hasAttribute(attribute.name))
|
|
1736
|
+
target.removeAttribute(attribute.name);
|
|
1737
|
+
for (const attribute of [...source.attributes])
|
|
1738
|
+
target.setAttribute(attribute.name, attribute.value);
|
|
1739
|
+
target.replaceChildren(...source.childNodes);
|
|
1740
|
+
}
|
|
1741
|
+
edgeGeometry(edge, positions, models) {
|
|
1742
|
+
const source = positions.get(edge.source);
|
|
1743
|
+
const target = positions.get(edge.target);
|
|
1744
|
+
const { x: x1, y: y1 } = this.boundary(
|
|
1745
|
+
models.get(edge.source),
|
|
1746
|
+
source,
|
|
1747
|
+
target
|
|
1748
|
+
);
|
|
1749
|
+
const { x: x2, y: y2 } = this.boundary(
|
|
1750
|
+
models.get(edge.target),
|
|
1751
|
+
target,
|
|
1752
|
+
source
|
|
1753
|
+
);
|
|
1754
|
+
const bend = Math.max(60, Math.abs(x2 - x1) / 2);
|
|
1755
|
+
const horizontal = Math.abs(x2 - x1) >= Math.abs(y2 - y1);
|
|
1756
|
+
const direction = horizontal ? Math.sign(x2 - x1) || 1 : Math.sign(y2 - y1) || 1;
|
|
1757
|
+
const verticalBend = Math.max(60, Math.abs(y2 - y1) / 2);
|
|
1758
|
+
const path = edge.source === edge.target ? `M${source.x - 20},${source.y - 25} C${source.x - 100},${source.y - 140} ${source.x + 100},${source.y - 140} ${source.x + 20},${source.y - 25}` : horizontal ? `M${x1},${y1} C${x1 + bend * direction},${y1} ${x2 - bend * direction},${y2} ${x2},${y2}` : `M${x1},${y1} C${x1},${y1 + verticalBend * direction} ${x2},${y2 - verticalBend * direction} ${x2},${y2}`;
|
|
1759
|
+
return {
|
|
1760
|
+
path,
|
|
1761
|
+
label: { x: (source.x + target.x) / 2, y: (source.y + target.y) / 2 - 9 }
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
renderEdge(edge, positions, models) {
|
|
1765
|
+
const selected = this.selected?.type === "edge" && this.selected.id === edge.id;
|
|
1766
|
+
const traversed = this.execution?.edges?.[edge.id] === "taken";
|
|
1767
|
+
const skipped = this.execution?.edges?.[edge.id] === "skipped";
|
|
1768
|
+
const group = this.element("g", {
|
|
1769
|
+
"data-edge-id": edge.id,
|
|
1770
|
+
role: "button",
|
|
1771
|
+
tabindex: "0",
|
|
1772
|
+
"aria-label": edge.label ?? `Connection ${edge.source} to ${edge.target}`,
|
|
1773
|
+
"aria-pressed": String(selected),
|
|
1774
|
+
"data-state": traversed ? "taken" : skipped ? "skipped" : "idle"
|
|
1775
|
+
});
|
|
1776
|
+
const { path, label: labelPosition } = this.edgeGeometry(
|
|
1777
|
+
edge,
|
|
1778
|
+
positions,
|
|
1779
|
+
models
|
|
1780
|
+
);
|
|
1781
|
+
group.append(
|
|
1782
|
+
this.element("path", {
|
|
1783
|
+
d: path,
|
|
1784
|
+
fill: "none",
|
|
1785
|
+
stroke: "transparent",
|
|
1786
|
+
"stroke-width": "16"
|
|
1787
|
+
})
|
|
1788
|
+
);
|
|
1789
|
+
group.append(
|
|
1790
|
+
this.element("path", {
|
|
1791
|
+
d: path,
|
|
1792
|
+
fill: "none",
|
|
1793
|
+
stroke: selected ? "var(--accent)" : traversed ? "var(--accent)" : "var(--border-strong)",
|
|
1794
|
+
"stroke-width": selected ? "3" : "2",
|
|
1795
|
+
"marker-end": `url(#${this.markerId})`,
|
|
1796
|
+
"pointer-events": "none",
|
|
1797
|
+
"stroke-dasharray": skipped ? "5 5" : "none",
|
|
1798
|
+
opacity: skipped ? "0.4" : "1"
|
|
1799
|
+
})
|
|
1800
|
+
);
|
|
1801
|
+
const caption = edge.label ?? (edge.default ? "otherwise" : edge.condition ? formatCondition(edge.condition) : "");
|
|
1802
|
+
if (caption) {
|
|
1803
|
+
const label = this.element("text", {
|
|
1804
|
+
x: String(labelPosition.x),
|
|
1805
|
+
y: String(labelPosition.y),
|
|
1806
|
+
"text-anchor": "middle",
|
|
1807
|
+
"font-size": "12",
|
|
1808
|
+
fill: "var(--text-secondary)"
|
|
1809
|
+
});
|
|
1810
|
+
label.textContent = caption.length > 55 ? `${caption.slice(0, 54)}\u2026` : caption;
|
|
1811
|
+
group.append(label);
|
|
1812
|
+
}
|
|
1813
|
+
return group;
|
|
1814
|
+
}
|
|
1815
|
+
cardIcon(group, name, x, y, size, color) {
|
|
1816
|
+
const icon = createFlowIcon(this.svg.ownerDocument, name, size);
|
|
1817
|
+
icon.setAttribute("x", String(x));
|
|
1818
|
+
icon.setAttribute("y", String(y));
|
|
1819
|
+
icon.setAttribute("color", color);
|
|
1820
|
+
icon.setAttribute("pointer-events", "none");
|
|
1821
|
+
group.append(icon);
|
|
1822
|
+
}
|
|
1823
|
+
renderCard(group, node, observation, stroke) {
|
|
1824
|
+
const selected = this.selected?.type === "node" && this.selected.id === node.id || this.connection === node.id;
|
|
1825
|
+
group.append(
|
|
1826
|
+
renderPhotonCard(
|
|
1827
|
+
this.svg.ownerDocument,
|
|
1828
|
+
node,
|
|
1829
|
+
this.store.getSnapshot(),
|
|
1830
|
+
observation,
|
|
1831
|
+
this.execution,
|
|
1832
|
+
selected,
|
|
1833
|
+
this.capabilities
|
|
1834
|
+
)
|
|
1835
|
+
);
|
|
1836
|
+
}
|
|
1837
|
+
boundary(node, center, toward) {
|
|
1838
|
+
const dx = toward.x - center.x || (toward.y === center.y ? 1 : 0);
|
|
1839
|
+
const dy = toward.y - center.y;
|
|
1840
|
+
const length = Math.hypot(dx, dy);
|
|
1841
|
+
const size = nodeDimensions(node);
|
|
1842
|
+
const factor = size.card ? 1 / Math.max(
|
|
1843
|
+
Math.abs(dx) / (size.width / 2),
|
|
1844
|
+
Math.abs(dy) / (size.height / 2)
|
|
1845
|
+
) : node.type === "start" || node.type === "end" ? 28 / length : ["decision", "fork", "join"].includes(node.type) ? 1 / (Math.abs(dx) / 44 + Math.abs(dy) / 34) : 1 / Math.max(Math.abs(dx) / 75, Math.abs(dy) / 28);
|
|
1846
|
+
return {
|
|
1847
|
+
x: center.x + dx * factor + dx / length * 3,
|
|
1848
|
+
y: center.y + dy * factor + dy / length * 3
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1851
|
+
renderNode(node, position) {
|
|
1852
|
+
const selected = this.selected?.type === "node" && this.selected.id === node.id;
|
|
1853
|
+
const observation = this.execution && Object.hasOwn(this.execution.nodes, node.id) ? this.execution.nodes[node.id] : void 0;
|
|
1854
|
+
const state = observation?.status ?? "idle";
|
|
1855
|
+
const stroke = selected || this.connection === node.id || state !== "idle" ? "var(--accent)" : "var(--border-strong)";
|
|
1856
|
+
const group = this.element("g", {
|
|
1857
|
+
transform: `translate(${position.x} ${position.y})`,
|
|
1858
|
+
"data-node-id": node.id,
|
|
1859
|
+
"data-state": state,
|
|
1860
|
+
role: "button",
|
|
1861
|
+
tabindex: "0",
|
|
1862
|
+
"aria-label": `${node.label}, ${node.type}, ${state}`,
|
|
1863
|
+
"aria-pressed": String(selected),
|
|
1864
|
+
cursor: "grab"
|
|
1865
|
+
});
|
|
1866
|
+
if (nodeDimensions(node).card) {
|
|
1867
|
+
this.renderCard(group, node, observation, stroke);
|
|
1868
|
+
return group;
|
|
1869
|
+
}
|
|
1870
|
+
const attributes = {
|
|
1871
|
+
fill: "var(--surface)",
|
|
1872
|
+
stroke,
|
|
1873
|
+
"stroke-width": selected ? "3" : "2"
|
|
1874
|
+
};
|
|
1875
|
+
if (["decision", "fork", "join"].includes(node.type))
|
|
1876
|
+
group.append(
|
|
1877
|
+
this.element("path", {
|
|
1878
|
+
...attributes,
|
|
1879
|
+
d: "M0,-34 L44,0 L0,34 L-44,0 Z"
|
|
1880
|
+
})
|
|
1881
|
+
);
|
|
1882
|
+
else if (node.type === "start" || node.type === "end")
|
|
1883
|
+
group.append(
|
|
1884
|
+
this.element("circle", {
|
|
1885
|
+
...attributes,
|
|
1886
|
+
r: "25",
|
|
1887
|
+
"stroke-width": node.type === "end" ? "5" : "2"
|
|
1888
|
+
})
|
|
1889
|
+
);
|
|
1890
|
+
else
|
|
1891
|
+
group.append(
|
|
1892
|
+
this.element("rect", {
|
|
1893
|
+
...attributes,
|
|
1894
|
+
x: "-75",
|
|
1895
|
+
y: "-28",
|
|
1896
|
+
width: "150",
|
|
1897
|
+
height: "56",
|
|
1898
|
+
rx: node.type === "wait" ? "24" : "8",
|
|
1899
|
+
"stroke-dasharray": node.type === "task" && node.mode === "async" ? "6 3" : "none"
|
|
1900
|
+
})
|
|
1901
|
+
);
|
|
1902
|
+
const symbol = node.type === "task" && node.mode === "async" ? "async" : "";
|
|
1903
|
+
if (node.type !== "task")
|
|
1904
|
+
this.cardIcon(group, operationIcon(node.type), -10, -10, 20, stroke);
|
|
1905
|
+
const text = this.element("text", {
|
|
1906
|
+
"text-anchor": "middle",
|
|
1907
|
+
y: ["task", "wait"].includes(node.type) ? "4" : "5",
|
|
1908
|
+
"font-size": "13",
|
|
1909
|
+
"font-family": "var(--font-sans)",
|
|
1910
|
+
fill: "var(--text)",
|
|
1911
|
+
"pointer-events": "none"
|
|
1912
|
+
});
|
|
1913
|
+
text.textContent = ["task", "wait"].includes(node.type) ? node.label.length > 20 ? `${node.label.slice(0, 19)}\u2026` : node.label : symbol;
|
|
1914
|
+
group.append(text);
|
|
1915
|
+
const label = this.element("text", {
|
|
1916
|
+
"text-anchor": "middle",
|
|
1917
|
+
y: "48",
|
|
1918
|
+
"font-size": "12",
|
|
1919
|
+
"font-family": "var(--font-sans)",
|
|
1920
|
+
fill: "var(--text-secondary)",
|
|
1921
|
+
"pointer-events": "none"
|
|
1922
|
+
});
|
|
1923
|
+
label.textContent = ["task", "wait"].includes(node.type) ? `${node.type}${symbol ? ` \xB7 ${symbol}` : ""}` : node.label;
|
|
1924
|
+
const title = this.element("title");
|
|
1925
|
+
title.textContent = `${node.label} (${node.type})`;
|
|
1926
|
+
group.append(label, title);
|
|
1927
|
+
return group;
|
|
1928
|
+
}
|
|
1929
|
+
click(event) {
|
|
1930
|
+
if (this.suppressClick) {
|
|
1931
|
+
this.suppressClick = false;
|
|
1932
|
+
return;
|
|
1933
|
+
}
|
|
1934
|
+
this.attempt(() => {
|
|
1935
|
+
const target = this.target(event);
|
|
1936
|
+
const id = target?.getAttribute("data-node-id");
|
|
1937
|
+
if (id && this.connection) {
|
|
1938
|
+
if (this.reconnection) {
|
|
1939
|
+
const { edgeId, endpoint } = this.reconnection;
|
|
1940
|
+
this.store.updateEdge(edgeId, (edge) => ({
|
|
1941
|
+
...edge,
|
|
1942
|
+
[endpoint]: id
|
|
1943
|
+
}));
|
|
1944
|
+
} else {
|
|
1945
|
+
const source = this.connection;
|
|
1946
|
+
const edgeId = this.options.createEdgeId?.() ?? `edge-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
1947
|
+
this.store.addEdge({ id: edgeId, source, target: id });
|
|
1948
|
+
}
|
|
1949
|
+
this.connection = null;
|
|
1950
|
+
this.reconnection = null;
|
|
1951
|
+
this.render();
|
|
1952
|
+
} else if (id) this.select({ type: "node", id });
|
|
1953
|
+
else {
|
|
1954
|
+
const edge = target?.getAttribute("data-edge-id");
|
|
1955
|
+
this.select(edge ? { type: "edge", id: edge } : null);
|
|
1956
|
+
}
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
keydown(event) {
|
|
1960
|
+
this.attempt(() => {
|
|
1961
|
+
if (event.key === "Escape") {
|
|
1962
|
+
this.clearHover(true);
|
|
1963
|
+
this.cancelDrag();
|
|
1964
|
+
this.cancelConnection();
|
|
1965
|
+
this.select(null);
|
|
1966
|
+
return;
|
|
1967
|
+
}
|
|
1968
|
+
const target = this.target(event);
|
|
1969
|
+
const nodeId = target?.getAttribute("data-node-id");
|
|
1970
|
+
const edgeId = target?.getAttribute("data-edge-id");
|
|
1971
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
1972
|
+
event.preventDefault();
|
|
1973
|
+
if (nodeId && this.connection)
|
|
1974
|
+
this.click(event);
|
|
1975
|
+
else if (nodeId) this.select({ type: "node", id: nodeId });
|
|
1976
|
+
else if (edgeId) this.select({ type: "edge", id: edgeId });
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1979
|
+
if (this.selected?.type === "node" && ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(event.key)) {
|
|
1980
|
+
event.preventDefault();
|
|
1981
|
+
const point = this.positions.get(this.selected.id);
|
|
1982
|
+
const amount = event.shiftKey ? 50 : 10;
|
|
1983
|
+
this.moveNodeView(this.selected.id, {
|
|
1984
|
+
x: point.x + (event.key === "ArrowLeft" ? -amount : event.key === "ArrowRight" ? amount : 0),
|
|
1985
|
+
y: point.y + (event.key === "ArrowUp" ? -amount : event.key === "ArrowDown" ? amount : 0)
|
|
1986
|
+
});
|
|
1987
|
+
return;
|
|
1988
|
+
}
|
|
1989
|
+
if (this.options.readOnly) return;
|
|
1990
|
+
if ((event.ctrlKey || event.metaKey) && ["z", "y"].includes(event.key.toLowerCase())) {
|
|
1991
|
+
event.preventDefault();
|
|
1992
|
+
if (event.key.toLowerCase() === "y" || event.shiftKey)
|
|
1993
|
+
this.store.redo();
|
|
1994
|
+
else this.store.undo();
|
|
1995
|
+
} else if (this.selected?.type === "edge" && event.key.toLowerCase() === "r") {
|
|
1996
|
+
this.beginReconnection(
|
|
1997
|
+
this.selected.id,
|
|
1998
|
+
event.shiftKey ? "source" : "target"
|
|
1999
|
+
);
|
|
2000
|
+
} else if (this.selected && (event.key === "Delete" || event.key === "Backspace")) {
|
|
2001
|
+
event.preventDefault();
|
|
2002
|
+
if (this.selected.type === "node")
|
|
2003
|
+
this.store.removeNode(this.selected.id);
|
|
2004
|
+
else if (this.selected.type === "global")
|
|
2005
|
+
this.store.removeGlobal(this.selected.id);
|
|
2006
|
+
else this.store.removeEdge(this.selected.id);
|
|
2007
|
+
} else if (this.selected?.type === "node" && event.key.toLowerCase() === "c")
|
|
2008
|
+
this.beginConnection(this.selected.id);
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
pointerdown(event) {
|
|
2012
|
+
if (event.button !== 0 || this.drag) return;
|
|
2013
|
+
this.clearHover();
|
|
2014
|
+
this.suppressClick = false;
|
|
2015
|
+
const target = this.target(event);
|
|
2016
|
+
const id = target?.getAttribute("data-node-id");
|
|
2017
|
+
if (this.connection || target?.hasAttribute("data-edge-id")) return;
|
|
2018
|
+
this.positionTimer?.stop();
|
|
2019
|
+
this.positionTimer = null;
|
|
2020
|
+
const origin = id ? this.positions.get(id) : this.viewport;
|
|
2021
|
+
this.drag = {
|
|
2022
|
+
pointerId: event.pointerId,
|
|
2023
|
+
kind: id ? "node" : "pan",
|
|
2024
|
+
...id ? { id } : {},
|
|
2025
|
+
start: this.point(event),
|
|
2026
|
+
origin: { x: origin.x, y: origin.y },
|
|
2027
|
+
preview: { x: origin.x, y: origin.y },
|
|
2028
|
+
moved: false
|
|
2029
|
+
};
|
|
2030
|
+
if (id) this.placement?.pin(id, origin);
|
|
2031
|
+
}
|
|
2032
|
+
pointermove(event) {
|
|
2033
|
+
const drag = this.drag;
|
|
2034
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
2035
|
+
const current = this.point(event);
|
|
2036
|
+
const dx = current.x - drag.start.x;
|
|
2037
|
+
const dy = current.y - drag.start.y;
|
|
2038
|
+
if (Math.hypot(dx, dy) < 3 && !drag.moved) return;
|
|
2039
|
+
event.preventDefault();
|
|
2040
|
+
drag.moved = true;
|
|
2041
|
+
const scale = drag.kind === "node" ? this.viewport.scale : 1;
|
|
2042
|
+
drag.preview = {
|
|
2043
|
+
x: drag.origin.x + dx / scale,
|
|
2044
|
+
y: drag.origin.y + dy / scale
|
|
2045
|
+
};
|
|
2046
|
+
if (drag.kind === "node") {
|
|
2047
|
+
this.placement?.pin(drag.id, drag.preview);
|
|
2048
|
+
if (!this.reducedMotion) this.placement?.restart();
|
|
2049
|
+
this.drawPositions(new Map(this.positions).set(drag.id, drag.preview));
|
|
2050
|
+
} else this.setViewport({ ...drag.preview, scale: this.viewport.scale });
|
|
2051
|
+
}
|
|
2052
|
+
pointerup(event) {
|
|
2053
|
+
const drag = this.drag;
|
|
2054
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
2055
|
+
this.drag = null;
|
|
2056
|
+
this.suppressClick = drag.moved;
|
|
2057
|
+
if (drag.kind === "node")
|
|
2058
|
+
this.attempt(() => {
|
|
2059
|
+
if (drag.moved) this.moveNodeView(drag.id, drag.preview);
|
|
2060
|
+
else
|
|
2061
|
+
this.placement?.pin(
|
|
2062
|
+
drag.id,
|
|
2063
|
+
this.viewOverrides.get(drag.id) ?? null
|
|
2064
|
+
);
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
cancelDrag() {
|
|
2068
|
+
if (this.drag?.kind === "node" && this.placement) {
|
|
2069
|
+
this.placement.pin(this.drag.id, this.drag.origin);
|
|
2070
|
+
if (!this.viewOverrides.has(this.drag.id))
|
|
2071
|
+
this.placement.pin(this.drag.id, null);
|
|
2072
|
+
}
|
|
2073
|
+
this.drag = null;
|
|
2074
|
+
this.render();
|
|
2075
|
+
}
|
|
2076
|
+
point(event) {
|
|
2077
|
+
const matrix = this.svg.getScreenCTM?.();
|
|
2078
|
+
if (matrix && this.svg.createSVGPoint) {
|
|
2079
|
+
const point = this.svg.createSVGPoint();
|
|
2080
|
+
point.x = event.clientX;
|
|
2081
|
+
point.y = event.clientY;
|
|
2082
|
+
const local = point.matrixTransform(matrix.inverse());
|
|
2083
|
+
return { x: local.x, y: local.y };
|
|
2084
|
+
}
|
|
2085
|
+
const bounds = this.svg.getBoundingClientRect();
|
|
2086
|
+
return { x: event.clientX - bounds.left, y: event.clientY - bounds.top };
|
|
2087
|
+
}
|
|
2088
|
+
target(event) {
|
|
2089
|
+
const target = event.target;
|
|
2090
|
+
const element = target?.closest?.("[data-node-id], [data-edge-id]") ?? null;
|
|
2091
|
+
return element && this.root.contains(element) ? element : null;
|
|
2092
|
+
}
|
|
2093
|
+
element(tag, attributes = {}) {
|
|
2094
|
+
const element = this.svg.ownerDocument.createElementNS(NS, tag);
|
|
2095
|
+
for (const [name, value] of Object.entries(attributes))
|
|
2096
|
+
element.setAttribute(name, value);
|
|
2097
|
+
return element;
|
|
2098
|
+
}
|
|
2099
|
+
listen(target, name, handler, options) {
|
|
2100
|
+
target.addEventListener(name, handler, options);
|
|
2101
|
+
this.cleanup.push(() => target.removeEventListener(name, handler, options));
|
|
2102
|
+
}
|
|
2103
|
+
attempt(action) {
|
|
2104
|
+
try {
|
|
2105
|
+
action();
|
|
2106
|
+
} catch (error) {
|
|
2107
|
+
this.options.onError?.(error);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
alive() {
|
|
2111
|
+
if (this.destroyed)
|
|
2112
|
+
throw new FlowError(
|
|
2113
|
+
"EDITOR_DESTROYED",
|
|
2114
|
+
"This editor has been destroyed."
|
|
2115
|
+
);
|
|
2116
|
+
}
|
|
2117
|
+
editable() {
|
|
2118
|
+
this.alive();
|
|
2119
|
+
if (this.options.readOnly)
|
|
2120
|
+
throw new FlowError("READ_ONLY", "This editor is read-only.");
|
|
2121
|
+
}
|
|
2122
|
+
checkSize(width, height) {
|
|
2123
|
+
if (![width, height].every((value) => Number.isFinite(value) && value > 0))
|
|
2124
|
+
throw new FlowError(
|
|
2125
|
+
"INVALID_SIZE",
|
|
2126
|
+
"Dimensions must be positive finite numbers."
|
|
2127
|
+
);
|
|
2128
|
+
}
|
|
2129
|
+
};
|
|
2130
|
+
|
|
2131
|
+
export {
|
|
2132
|
+
iconPaths,
|
|
2133
|
+
createFlowIcon,
|
|
2134
|
+
operationIcon,
|
|
2135
|
+
SvgFlowEditor
|
|
2136
|
+
};
|