@sebastianwessel/isostate 0.4.0 → 0.6.0
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/dist/animation/animation-engine.d.ts +3 -0
- package/dist/animation/animation-engine.d.ts.map +1 -1
- package/dist/animation/controller.d.ts +36 -2
- package/dist/animation/controller.d.ts.map +1 -1
- package/dist/assets/software-architecture/IMAGEGEN-PROMPTS.md +66 -0
- package/dist/assets/software-architecture/LICENSE +21 -0
- package/dist/assets/software-architecture/NOTICE.md +17 -0
- package/dist/assets/software-architecture/README.md +105 -0
- package/dist/assets/software-architecture/agentic/AGENT-VISUAL-PROMPTS.md +42 -0
- package/dist/assets/software-architecture/agentic/HANDOFF-PROMPTS.md +19 -0
- package/dist/assets/software-architecture/agentic/PROCESS-VISUAL-PROMPTS.md +109 -0
- package/dist/assets/software-architecture/agentic/agents-sprites.png +0 -0
- package/dist/assets/software-architecture/agentic/ai-capabilities-sprites.png +0 -0
- package/dist/assets/software-architecture/agentic/ai-to-human-handoff.png +0 -0
- package/dist/assets/software-architecture/agentic/channels-sprites.png +0 -0
- package/dist/assets/software-architecture/agentic/human-to-ai-handoff.png +0 -0
- package/dist/assets/software-architecture/agentic/humans-sprites.png +0 -0
- package/dist/assets/software-architecture/agentic/infrastructure-sprites.png +0 -0
- package/dist/assets/software-architecture/agentic/lifecycle-sprites.png +0 -0
- package/dist/assets/software-architecture/agentic/orchestration-sprites.png +0 -0
- package/dist/assets/software-architecture/agentic/providers-sprites.png +0 -0
- package/dist/assets/software-architecture/agentic/servicenow-sprites.png +0 -0
- package/dist/assets/software-architecture/architecture/architecture-sprites.png +0 -0
- package/dist/assets/software-architecture/manifest.json +2095 -0
- package/dist/assets/software-architecture/workflow/workflow-process-sprites.png +0 -0
- package/dist/browser/isostate.runtime.js +4 -4
- package/dist/browser/isostate.runtime.js.map +12 -10
- package/dist/chunks/errors-2yA81Vfb.js +23 -0
- package/dist/chunks/{errors-DyqEkrm5.js.map → errors-2yA81Vfb.js.map} +1 -1
- package/dist/chunks/index-WmsNtuaZ.js +1685 -0
- package/dist/chunks/index-WmsNtuaZ.js.map +1 -0
- package/dist/chunks/rendering-engine-DLaM1XbU.js +1425 -0
- package/dist/chunks/rendering-engine-DLaM1XbU.js.map +1 -0
- package/dist/chunks/scene-parser-BNXXIAqj.js +3033 -0
- package/dist/chunks/scene-parser-BNXXIAqj.js.map +1 -0
- package/dist/chunks/sha256-BkgWUdh1.js +123 -0
- package/dist/chunks/sha256-BkgWUdh1.js.map +1 -0
- package/dist/dsl/browser.js +3 -3
- package/dist/dsl/index.js +3 -3
- package/dist/dsl/scene-parser.d.ts.map +1 -1
- package/dist/dsl/scene-validator.d.ts.map +1 -1
- package/dist/dsl/workflow-effects-validation.d.ts +8 -0
- package/dist/dsl/workflow-effects-validation.d.ts.map +1 -0
- package/dist/editor-support/adapter.d.ts.map +1 -1
- package/dist/editor-support/index.js +347 -394
- package/dist/editor-support/index.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +438 -40
- package/dist/index.js.map +1 -1
- package/dist/rendering/animation-css.d.ts.map +1 -1
- package/dist/rendering/rendering-engine.d.ts +11 -0
- package/dist/rendering/rendering-engine.d.ts.map +1 -1
- package/dist/rendering/scene-effects.d.ts +15 -0
- package/dist/rendering/scene-effects.d.ts.map +1 -0
- package/dist/rendering/theme.d.ts +4 -0
- package/dist/rendering/theme.d.ts.map +1 -1
- package/dist/runtime/diagnostics-overlay.d.ts +29 -0
- package/dist/runtime/diagnostics-overlay.d.ts.map +1 -0
- package/dist/runtime/export.d.ts +27 -0
- package/dist/runtime/export.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +4 -4
- package/dist/runtime/interactivity.d.ts +56 -0
- package/dist/runtime/interactivity.d.ts.map +1 -0
- package/dist/runtime/mount-scene.d.ts +11 -10
- package/dist/runtime/mount-scene.d.ts.map +1 -1
- package/dist/types/asset-registry.d.ts +1 -0
- package/dist/types/asset-registry.d.ts.map +1 -1
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/node.d.ts +54 -1
- package/dist/types/node.d.ts.map +1 -1
- package/dist/types/runtime-bundle.d.ts +35 -0
- package/dist/types/runtime-bundle.d.ts.map +1 -1
- package/dist/types/scene.d.ts +2 -0
- package/dist/types/scene.d.ts.map +1 -1
- package/package.json +9 -8
- package/dist/chunks/errors-DyqEkrm5.js +0 -29
- package/dist/chunks/index-C3qcXbPI.js +0 -1542
- package/dist/chunks/index-C3qcXbPI.js.map +0 -1
- package/dist/chunks/rendering-engine-BUUV3Qq-.js +0 -1124
- package/dist/chunks/rendering-engine-BUUV3Qq-.js.map +0 -1
- package/dist/chunks/scene-parser-B9SPDLYs.js +0 -2688
- package/dist/chunks/scene-parser-B9SPDLYs.js.map +0 -1
- package/dist/chunks/sha256-4JuurR-b.js +0 -69
- package/dist/chunks/sha256-4JuurR-b.js.map +0 -1
|
@@ -0,0 +1,1425 @@
|
|
|
1
|
+
import { R as RenderError } from './errors-2yA81Vfb.js';
|
|
2
|
+
|
|
3
|
+
const BUILTIN_THEMES = {
|
|
4
|
+
light: {
|
|
5
|
+
"--color-top": "#e2e8f0",
|
|
6
|
+
"--color-front": "#94a3b8",
|
|
7
|
+
"--color-side": "#64748b",
|
|
8
|
+
"--color-back": "#475569",
|
|
9
|
+
"--color-leaf": "#15803d",
|
|
10
|
+
"--color-trunk": "#78350f",
|
|
11
|
+
"--color-accent": "#3b82f6"
|
|
12
|
+
},
|
|
13
|
+
dark: {
|
|
14
|
+
"--color-top": "#334155",
|
|
15
|
+
"--color-front": "#1e293b",
|
|
16
|
+
"--color-side": "#0f172a",
|
|
17
|
+
"--color-back": "#020617",
|
|
18
|
+
"--color-leaf": "#166534",
|
|
19
|
+
"--color-trunk": "#451a03",
|
|
20
|
+
"--color-accent": "#60a5fa"
|
|
21
|
+
},
|
|
22
|
+
brand: {
|
|
23
|
+
"--color-top": "#c7d2fe",
|
|
24
|
+
"--color-front": "#818cf8",
|
|
25
|
+
"--color-side": "#6366f1",
|
|
26
|
+
"--color-back": "#4338ca",
|
|
27
|
+
"--color-leaf": "#22c55e",
|
|
28
|
+
"--color-trunk": "#854d0e",
|
|
29
|
+
"--color-accent": "#f59e0b"
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function resolveTheme(name) {
|
|
33
|
+
return Object.hasOwn(BUILTIN_THEMES, name) ? BUILTIN_THEMES[name] : void 0;
|
|
34
|
+
}
|
|
35
|
+
function composeTheme(baseName, overrides) {
|
|
36
|
+
const base = resolveTheme(baseName);
|
|
37
|
+
if (!base) {
|
|
38
|
+
return { name: baseName, vars: { ...overrides } };
|
|
39
|
+
}
|
|
40
|
+
return { name: baseName, vars: { ...base, ...overrides } };
|
|
41
|
+
}
|
|
42
|
+
class AssetRegistryImpl {
|
|
43
|
+
_assets = /* @__PURE__ */ new Map();
|
|
44
|
+
register(asset) {
|
|
45
|
+
this._assets.set(asset.id, asset);
|
|
46
|
+
}
|
|
47
|
+
get(id) {
|
|
48
|
+
return this._assets.get(id);
|
|
49
|
+
}
|
|
50
|
+
getAll(category) {
|
|
51
|
+
if (category) {
|
|
52
|
+
return [...this._assets.values()].filter((a) => a.category === category);
|
|
53
|
+
}
|
|
54
|
+
return [...this._assets.values()];
|
|
55
|
+
}
|
|
56
|
+
has(id) {
|
|
57
|
+
return this._assets.has(id);
|
|
58
|
+
}
|
|
59
|
+
remove(id) {
|
|
60
|
+
this._assets.delete(id);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function createAssetRegistry(assets = []) {
|
|
64
|
+
const registry = new AssetRegistryImpl();
|
|
65
|
+
for (const asset of assets) {
|
|
66
|
+
registry.register(asset);
|
|
67
|
+
}
|
|
68
|
+
return registry;
|
|
69
|
+
}
|
|
70
|
+
function createDefaultRegistry() {
|
|
71
|
+
return createAssetRegistry([
|
|
72
|
+
{
|
|
73
|
+
id: "iso-platform",
|
|
74
|
+
category: "infrastructure"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "iso-server",
|
|
78
|
+
category: "equipment"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: "iso-database",
|
|
82
|
+
category: "equipment"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: "iso-connector",
|
|
86
|
+
category: "decoration"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "iso-cloud",
|
|
90
|
+
category: "decoration"
|
|
91
|
+
}
|
|
92
|
+
]);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const DEFAULT_CELL_SIZE = 64;
|
|
96
|
+
function projectToRaw(gridX, gridY, cellSize) {
|
|
97
|
+
return {
|
|
98
|
+
rawX: cellSize * (gridX - gridY) * 0.5,
|
|
99
|
+
rawY: cellSize * (gridX + gridY) * 0.25
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function projectToScreen(gridX, gridY, cellSize, boundsMinX = 0, boundsMinY = 0, paddingX = 0, paddingY = 0) {
|
|
103
|
+
const { rawX, rawY } = projectToRaw(gridX, gridY, cellSize);
|
|
104
|
+
return {
|
|
105
|
+
screenX: rawX - boundsMinX + paddingX,
|
|
106
|
+
screenY: rawY - boundsMinY + paddingY
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function calculateVisualSize(gridSize, cellSize) {
|
|
110
|
+
return cellSize * gridSize;
|
|
111
|
+
}
|
|
112
|
+
function calculateTransform(screenX, screenY, visualSize, cellSize) {
|
|
113
|
+
const scale = visualSize / cellSize;
|
|
114
|
+
return `translate(${screenX}px, ${screenY}px) scale(${scale})`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function buildKeyframeCSS() {
|
|
118
|
+
return [
|
|
119
|
+
"@keyframes iso-anim-fade-in{from{opacity:0}to{opacity:1}}",
|
|
120
|
+
"@keyframes iso-anim-fade-in-grow{from{opacity:0;scale:.01}to{opacity:1;scale:1}}",
|
|
121
|
+
"@keyframes iso-anim-fall-in{from{opacity:0;translate:0 -40px}to{opacity:1;translate:0 0}}",
|
|
122
|
+
"@keyframes iso-anim-rise-from-ground{from{opacity:0;translate:0 40px}to{opacity:1;translate:0 0}}",
|
|
123
|
+
"@keyframes iso-anim-slide-in-left{from{opacity:0;translate:-60px 0}to{opacity:1;translate:0 0}}",
|
|
124
|
+
"@keyframes iso-anim-slide-in-right{from{opacity:0;translate:60px 0}to{opacity:1;translate:0 0}}",
|
|
125
|
+
"@keyframes iso-anim-flip-in{from{opacity:1;scale:0 1}to{opacity:1;scale:1 1}}",
|
|
126
|
+
"@keyframes iso-anim-fade-out{from{opacity:1}to{opacity:0}}",
|
|
127
|
+
"@keyframes iso-anim-fade-out-shrink{from{opacity:1;scale:1}to{opacity:0;scale:.01}}",
|
|
128
|
+
"@keyframes iso-anim-fall-through-ground{from{opacity:1;translate:0 0}to{opacity:0;translate:0 40px}}",
|
|
129
|
+
"@keyframes iso-anim-rise-away{from{opacity:1;translate:0 0}to{opacity:0;translate:0 -40px}}",
|
|
130
|
+
"@keyframes iso-anim-slide-out-left{from{opacity:1;translate:0 0}to{opacity:0;translate:-60px 0}}",
|
|
131
|
+
"@keyframes iso-anim-slide-out-right{from{opacity:1;translate:0 0}to{opacity:0;translate:60px 0}}",
|
|
132
|
+
"@keyframes iso-anim-flip-out{from{opacity:1;scale:1 1}to{opacity:0;scale:0 1}}",
|
|
133
|
+
"@keyframes iso-anim-pulse{0%,100%{opacity:.7}50%{opacity:1}}",
|
|
134
|
+
"@keyframes iso-anim-float{0%,100%{translate:0 0}50%{translate:0 -6px}}",
|
|
135
|
+
"@keyframes iso-anim-shake{0%,25%,75%,100%{translate:0 0}50%{translate:3px 0}}",
|
|
136
|
+
"@keyframes iso-anim-glow{0%,100%{filter:drop-shadow(0 0 2px rgba(255,255,255,.5))}50%{filter:drop-shadow(0 0 8px rgba(255,255,255,.9))}}",
|
|
137
|
+
"@keyframes iso-anim-spin{from{rotate:0deg}to{rotate:360deg}}",
|
|
138
|
+
"@keyframes iso-anim-blink{0%,49%{opacity:1}50%,100%{opacity:0}}",
|
|
139
|
+
".iso-ambient-pulse{animation:iso-anim-pulse 2s ease-in-out infinite}",
|
|
140
|
+
".iso-ambient-float{animation:iso-anim-float 3s ease-in-out infinite}",
|
|
141
|
+
".iso-ambient-shake{animation:iso-anim-shake 0.5s ease-in-out infinite}",
|
|
142
|
+
".iso-ambient-glow{animation:iso-anim-glow 2s ease-in-out infinite}",
|
|
143
|
+
".iso-ambient-spin{animation:iso-anim-spin 4s linear infinite}",
|
|
144
|
+
".iso-ambient-blink{animation:iso-anim-blink 1.5s step-end infinite}",
|
|
145
|
+
"@keyframes iso-connector-flow-route{from{stroke-dashoffset:0}to{stroke-dashoffset:calc(-1px * var(--iso-flow-distance,20))}}",
|
|
146
|
+
"@keyframes iso-connector-flow-reverse{from{stroke-dashoffset:0}to{stroke-dashoffset:calc(1px * var(--iso-flow-distance,20))}}",
|
|
147
|
+
".iso-connector-pattern-dashed .iso-connector-shaft,.iso-connector-pattern-dotted .iso-connector-shaft{--iso-flow-distance:20}",
|
|
148
|
+
".iso-connector-direction-route .iso-connector-shaft.iso-ambient-flow{animation:iso-connector-flow-route 900ms linear infinite}",
|
|
149
|
+
".iso-connector-direction-reverse .iso-connector-shaft.iso-ambient-flow{animation:iso-connector-flow-reverse 900ms linear infinite}",
|
|
150
|
+
"@media (prefers-reduced-motion: reduce){.iso-element,.iso-connector{animation-duration:1ms!important}.iso-ambient-pulse,.iso-ambient-float,.iso-ambient-shake,.iso-ambient-glow,.iso-ambient-spin,.iso-ambient-blink,.iso-ambient-flow{animation:none!important}}",
|
|
151
|
+
"@keyframes iso-message-travel{from{offset-distance:0%}to{offset-distance:100%}}",
|
|
152
|
+
".iso-message{offset-anchor:0px 0px;offset-rotate:0deg;animation:iso-message-travel 1800ms linear infinite;pointer-events:none}",
|
|
153
|
+
"@keyframes iso-activity-breathe{0%,100%{opacity:.45}50%{opacity:1}}",
|
|
154
|
+
".iso-activity-processing .iso-activity-ring{animation:iso-activity-breathe 1800ms ease-in-out infinite}",
|
|
155
|
+
".iso-activity-waiting .iso-activity-badge{animation:iso-activity-breathe 2600ms ease-in-out infinite}",
|
|
156
|
+
".iso-motion-paused *{animation-play-state:paused!important}.iso-motion-stopped *{animation:none!important}",
|
|
157
|
+
"@media (prefers-reduced-motion:reduce){.iso-message{animation:none!important;offset-distance:50%}.iso-activity *{animation:none!important}}",
|
|
158
|
+
".iso-interactive g[data-id]{cursor:pointer}"
|
|
159
|
+
].join("\n");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const NS$2 = "http://www.w3.org/2000/svg";
|
|
163
|
+
function createAssetResolver(bundle) {
|
|
164
|
+
const embedded = /* @__PURE__ */ new Map();
|
|
165
|
+
const bundleAssets = bundle?.assets;
|
|
166
|
+
if (bundleAssets && typeof bundleAssets === "object") {
|
|
167
|
+
for (const [name, asset] of Object.entries(bundleAssets)) {
|
|
168
|
+
if (asset && typeof asset === "object" && typeof asset.url === "string") {
|
|
169
|
+
embedded.set(name, { url: asset.url, anchor: asset.anchor, sprite: asset.sprite });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return (name) => embedded.get(name);
|
|
174
|
+
}
|
|
175
|
+
function createAssetNode(asset, assetName, cellSize) {
|
|
176
|
+
if (asset.sprite) {
|
|
177
|
+
return createSpriteAssetNode(asset.url, assetName, cellSize, asset.sprite, asset.anchor);
|
|
178
|
+
}
|
|
179
|
+
return createUrlAssetNode(asset.url, assetName, cellSize, asset.anchor);
|
|
180
|
+
}
|
|
181
|
+
function createTextAssetNode(textContent, assetName, cellSize) {
|
|
182
|
+
if (!textContent?.value) {
|
|
183
|
+
throw new RenderError("TEXT_CONTENT_MISSING", `Text content is missing for built-in asset: ${assetName}`, {
|
|
184
|
+
asset: assetName
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
const group = document.createElementNS(NS$2, "g");
|
|
188
|
+
const text = document.createElementNS(NS$2, "text");
|
|
189
|
+
const align = textContent.align ?? "middle";
|
|
190
|
+
const placement = textContent.placement ?? "cell";
|
|
191
|
+
const fontSize = textContent.fontSize ?? 12;
|
|
192
|
+
const lineHeight = textContent.lineHeight ?? 1.2;
|
|
193
|
+
const anchorX = textAnchorX(align, cellSize);
|
|
194
|
+
const vertical = textVerticalAnchor(placement, cellSize);
|
|
195
|
+
text.setAttribute("x", String(anchorX));
|
|
196
|
+
text.setAttribute("y", String(vertical.y));
|
|
197
|
+
text.setAttribute("text-anchor", align);
|
|
198
|
+
text.setAttribute("dominant-baseline", vertical.baseline);
|
|
199
|
+
text.setAttribute("font-family", "Arial, Helvetica, sans-serif");
|
|
200
|
+
text.setAttribute("font-size", String(fontSize));
|
|
201
|
+
text.setAttribute("font-weight", String(textContent.fontWeight ?? 700));
|
|
202
|
+
text.setAttribute("fill", textContent.fill ?? "currentColor");
|
|
203
|
+
const lines = normalizeTextLines(textContent.value);
|
|
204
|
+
for (const [index, line] of lines.entries()) {
|
|
205
|
+
const tspan = document.createElementNS(NS$2, "tspan");
|
|
206
|
+
tspan.setAttribute("x", String(anchorX));
|
|
207
|
+
tspan.setAttribute("dy", index === 0 ? "0" : String(fontSize * lineHeight));
|
|
208
|
+
tspan.textContent = line;
|
|
209
|
+
text.appendChild(tspan);
|
|
210
|
+
}
|
|
211
|
+
group.appendChild(text);
|
|
212
|
+
return group;
|
|
213
|
+
}
|
|
214
|
+
function createPrimitiveAssetNode(assetName, primitive, cellSize) {
|
|
215
|
+
const group = document.createElementNS(NS$2, "g");
|
|
216
|
+
switch (assetName) {
|
|
217
|
+
case "rectangle":
|
|
218
|
+
appendProjectedPolygon(group, rectanglePoints(), primitive?.rectangle, cellSize);
|
|
219
|
+
return group;
|
|
220
|
+
case "polygon":
|
|
221
|
+
appendProjectedPolygon(group, primitive?.polygon?.points, primitive?.polygon, cellSize);
|
|
222
|
+
return group;
|
|
223
|
+
case "line":
|
|
224
|
+
appendProjectedPolyline(group, primitive?.line, primitive?.line, cellSize);
|
|
225
|
+
return group;
|
|
226
|
+
case "circle":
|
|
227
|
+
appendCircle(group, primitive?.circle, cellSize);
|
|
228
|
+
return group;
|
|
229
|
+
default:
|
|
230
|
+
throw new RenderError("PRIMITIVE_ASSET_UNKNOWN", `Unknown built-in primitive asset: ${assetName}`, {
|
|
231
|
+
asset: assetName
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function textAnchorX(align, cellSize) {
|
|
236
|
+
if (align === "start") return -cellSize / 2;
|
|
237
|
+
if (align === "end") return cellSize / 2;
|
|
238
|
+
return 0;
|
|
239
|
+
}
|
|
240
|
+
function textVerticalAnchor(placement, cellSize) {
|
|
241
|
+
if (placement === "caption") return { y: -cellSize, baseline: "text-before-edge" };
|
|
242
|
+
return { y: -cellSize / 2, baseline: "middle" };
|
|
243
|
+
}
|
|
244
|
+
function normalizeTextLines(value) {
|
|
245
|
+
const normalized = value.replace(/\r\n?/g, "\n").replace(/\n$/, "");
|
|
246
|
+
return normalized.split("\n");
|
|
247
|
+
}
|
|
248
|
+
function rectanglePoints() {
|
|
249
|
+
return [
|
|
250
|
+
[0, 0],
|
|
251
|
+
[1, 0],
|
|
252
|
+
[1, 1],
|
|
253
|
+
[0, 1]
|
|
254
|
+
];
|
|
255
|
+
}
|
|
256
|
+
function appendProjectedPolygon(group, points, style, cellSize) {
|
|
257
|
+
if (!points) return;
|
|
258
|
+
const polygon = document.createElementNS(NS$2, "polygon");
|
|
259
|
+
polygon.setAttribute("points", points.map((point) => projectLocalPoint(point, cellSize)).join(" "));
|
|
260
|
+
applyPrimitiveStyle(polygon, style, { fill: "currentColor", stroke: "none" });
|
|
261
|
+
group.appendChild(polygon);
|
|
262
|
+
}
|
|
263
|
+
function appendProjectedPolyline(group, line, style, cellSize) {
|
|
264
|
+
if (!line?.points) return;
|
|
265
|
+
const polyline = document.createElementNS(NS$2, "polyline");
|
|
266
|
+
polyline.setAttribute("points", line.points.map((point) => projectLocalPoint(point, cellSize)).join(" "));
|
|
267
|
+
polyline.setAttribute("fill", "none");
|
|
268
|
+
polyline.setAttribute("stroke-linecap", line.lineCap ?? "round");
|
|
269
|
+
polyline.setAttribute("stroke-linejoin", line.lineJoin ?? "round");
|
|
270
|
+
applyPrimitiveStyle(polyline, style, {
|
|
271
|
+
fill: "none",
|
|
272
|
+
stroke: "currentColor"
|
|
273
|
+
});
|
|
274
|
+
group.appendChild(polyline);
|
|
275
|
+
}
|
|
276
|
+
function appendCircle(group, style, cellSize) {
|
|
277
|
+
const center = projectLocalPoint([0.5, 0.5], cellSize);
|
|
278
|
+
const circle = document.createElementNS(NS$2, "circle");
|
|
279
|
+
const [cx, cy] = center.split(",").map(Number);
|
|
280
|
+
circle.setAttribute("cx", String(cx));
|
|
281
|
+
circle.setAttribute("cy", String(cy));
|
|
282
|
+
circle.setAttribute("r", String(cellSize * 0.2));
|
|
283
|
+
applyPrimitiveStyle(circle, style, {
|
|
284
|
+
fill: "currentColor",
|
|
285
|
+
stroke: "none"
|
|
286
|
+
});
|
|
287
|
+
group.appendChild(circle);
|
|
288
|
+
}
|
|
289
|
+
function projectLocalPoint(point, cellSize) {
|
|
290
|
+
const projected = projectToRaw(point[0], point[1], cellSize);
|
|
291
|
+
const anchor = projectToRaw(1, 1, cellSize);
|
|
292
|
+
return `${projected.rawX - anchor.rawX},${projected.rawY - anchor.rawY}`;
|
|
293
|
+
}
|
|
294
|
+
function applyPrimitiveStyle(node, style, defaults) {
|
|
295
|
+
node.setAttribute("fill", style?.fill ?? defaults.fill);
|
|
296
|
+
node.setAttribute("stroke", style?.stroke ?? defaults.stroke);
|
|
297
|
+
node.setAttribute("stroke-width", String(style?.strokeWidth ?? 0));
|
|
298
|
+
node.setAttribute("opacity", String(style?.opacity ?? 1));
|
|
299
|
+
if (style?.dash) node.setAttribute("stroke-dasharray", style.dash.join(" "));
|
|
300
|
+
}
|
|
301
|
+
function createUrlAssetNode(url, assetName, cellSize, anchor) {
|
|
302
|
+
if (!isSafeAssetUrl(url)) {
|
|
303
|
+
throw new RenderError("INVALID_ASSET_URL", `Asset URL is unsafe: ${assetName}`, { asset: assetName });
|
|
304
|
+
}
|
|
305
|
+
const group = document.createElementNS(NS$2, "g");
|
|
306
|
+
const image = document.createElementNS(NS$2, "image");
|
|
307
|
+
const resolvedUrl = resolveBrowserAssetUrl(url);
|
|
308
|
+
const [anchorX, anchorY] = anchor ?? [0.5, 1];
|
|
309
|
+
image.setAttribute("href", resolvedUrl);
|
|
310
|
+
image.setAttributeNS("http://www.w3.org/1999/xlink", "href", resolvedUrl);
|
|
311
|
+
image.setAttribute("x", String(-cellSize * anchorX));
|
|
312
|
+
image.setAttribute("y", String(-cellSize * anchorY));
|
|
313
|
+
image.setAttribute("width", String(cellSize));
|
|
314
|
+
image.setAttribute("height", String(cellSize));
|
|
315
|
+
image.setAttribute("preserveAspectRatio", "xMidYMax meet");
|
|
316
|
+
group.appendChild(image);
|
|
317
|
+
return group;
|
|
318
|
+
}
|
|
319
|
+
function createSpriteAssetNode(url, assetName, cellSize, sprite, anchor) {
|
|
320
|
+
if (!isSafeAssetUrl(url)) {
|
|
321
|
+
throw new RenderError("INVALID_ASSET_URL", `Asset URL is unsafe: ${assetName}`, { asset: assetName });
|
|
322
|
+
}
|
|
323
|
+
const group = document.createElementNS(NS$2, "g");
|
|
324
|
+
const viewport = document.createElementNS(NS$2, "svg");
|
|
325
|
+
const image = document.createElementNS(NS$2, "image");
|
|
326
|
+
const resolvedUrl = resolveBrowserAssetUrl(url);
|
|
327
|
+
const [anchorX, anchorY] = anchor ?? [0.5, 1];
|
|
328
|
+
const [rectX, rectY, rectWidth, rectHeight] = sprite.rect;
|
|
329
|
+
viewport.setAttribute("x", String(-cellSize * anchorX));
|
|
330
|
+
viewport.setAttribute("y", String(-cellSize * anchorY));
|
|
331
|
+
viewport.setAttribute("width", String(cellSize));
|
|
332
|
+
viewport.setAttribute("height", String(cellSize));
|
|
333
|
+
viewport.setAttribute("viewBox", `${rectX} ${rectY} ${rectWidth} ${rectHeight}`);
|
|
334
|
+
viewport.setAttribute("preserveAspectRatio", "xMidYMax meet");
|
|
335
|
+
image.setAttribute("href", resolvedUrl);
|
|
336
|
+
image.setAttributeNS("http://www.w3.org/1999/xlink", "href", resolvedUrl);
|
|
337
|
+
image.setAttribute("x", "0");
|
|
338
|
+
image.setAttribute("y", "0");
|
|
339
|
+
image.setAttribute("width", String(sprite.sheetSize[0]));
|
|
340
|
+
image.setAttribute("height", String(sprite.sheetSize[1]));
|
|
341
|
+
viewport.appendChild(image);
|
|
342
|
+
group.appendChild(viewport);
|
|
343
|
+
return group;
|
|
344
|
+
}
|
|
345
|
+
function resolveBrowserAssetUrl(url) {
|
|
346
|
+
try {
|
|
347
|
+
const baseURI = document.baseURI;
|
|
348
|
+
return typeof baseURI === "string" ? new URL(url, baseURI).href : url;
|
|
349
|
+
} catch {
|
|
350
|
+
return url;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
function isSafeAssetUrl(url) {
|
|
354
|
+
const normalized = url.trim().toLowerCase();
|
|
355
|
+
return normalized.length > 0 && !normalized.startsWith("javascript:");
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const NS$1 = "http://www.w3.org/2000/svg";
|
|
359
|
+
function roundedPath(points, radius) {
|
|
360
|
+
if (!points.length) return "";
|
|
361
|
+
let result = `M ${points[0].x} ${points[0].y}`;
|
|
362
|
+
for (let i = 1; i < points.length; i++) {
|
|
363
|
+
const point = points[i];
|
|
364
|
+
const previous = points[i - 1];
|
|
365
|
+
const next = points[i + 1];
|
|
366
|
+
const before = Math.hypot(point.x - previous.x, point.y - previous.y);
|
|
367
|
+
const after = next ? Math.hypot(next.x - point.x, next.y - point.y) : 0;
|
|
368
|
+
const distance = Math.min(radius, before / 2, after / 2);
|
|
369
|
+
if (!next || !distance) {
|
|
370
|
+
result += ` L ${point.x} ${point.y}`;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const a = {
|
|
374
|
+
x: point.x + (previous.x - point.x) * distance / before,
|
|
375
|
+
y: point.y + (previous.y - point.y) * distance / before
|
|
376
|
+
};
|
|
377
|
+
const b = {
|
|
378
|
+
x: point.x + (next.x - point.x) * distance / after,
|
|
379
|
+
y: point.y + (next.y - point.y) * distance / after
|
|
380
|
+
};
|
|
381
|
+
result += ` L ${a.x} ${a.y} Q ${point.x} ${point.y} ${b.x} ${b.y}`;
|
|
382
|
+
}
|
|
383
|
+
return result;
|
|
384
|
+
}
|
|
385
|
+
function shape(tag, attrs) {
|
|
386
|
+
const node = document.createElementNS(NS$1, tag);
|
|
387
|
+
for (const [key, value] of Object.entries(attrs)) node.setAttribute(key, String(value));
|
|
388
|
+
return node;
|
|
389
|
+
}
|
|
390
|
+
function updateTrackEffects(node, shaft, def, d) {
|
|
391
|
+
for (const old of node.querySelectorAll(".iso-track-effect")) node.removeChild(old);
|
|
392
|
+
const { style } = def;
|
|
393
|
+
if (style.glow) {
|
|
394
|
+
const glow = shape("path", {
|
|
395
|
+
d,
|
|
396
|
+
fill: "none",
|
|
397
|
+
stroke: style.glow,
|
|
398
|
+
"stroke-width": style.strokeWidth + (style.glowWidth ?? 8),
|
|
399
|
+
opacity: style.opacity * 0.16,
|
|
400
|
+
"stroke-linecap": "round",
|
|
401
|
+
"stroke-linejoin": "round",
|
|
402
|
+
class: "iso-track-effect iso-connector-glow"
|
|
403
|
+
});
|
|
404
|
+
node.insertBefore(glow, node.firstChild);
|
|
405
|
+
}
|
|
406
|
+
if (style.variant !== "beam") return;
|
|
407
|
+
const highlight = shape("path", {
|
|
408
|
+
d,
|
|
409
|
+
fill: "none",
|
|
410
|
+
stroke: "#efffff",
|
|
411
|
+
"stroke-width": Math.max(0.6, style.strokeWidth * 0.23),
|
|
412
|
+
opacity: style.opacity * 0.7,
|
|
413
|
+
"stroke-linecap": "round",
|
|
414
|
+
"stroke-linejoin": "round",
|
|
415
|
+
class: "iso-track-effect iso-connector-highlight"
|
|
416
|
+
});
|
|
417
|
+
node.insertBefore(highlight, shaft.nextSibling);
|
|
418
|
+
}
|
|
419
|
+
function messageToken(kind, size, color) {
|
|
420
|
+
const group = shape("g", { transform: `scale(${size / 16})`, fill: color });
|
|
421
|
+
group.appendChild(shape("ellipse", { cx: 1, cy: 5, rx: 9, ry: 3.5, fill: "#07131f", opacity: 0.35 }));
|
|
422
|
+
if (kind === "orb") {
|
|
423
|
+
group.appendChild(shape("circle", { r: 7, fill: "#173343" }));
|
|
424
|
+
group.appendChild(shape("circle", { cx: -1, cy: -1.5, r: 5.6 }));
|
|
425
|
+
group.appendChild(shape("ellipse", { cx: -2, cy: -3.5, rx: 2.5, ry: 1.6, fill: "#fff", opacity: 0.85 }));
|
|
426
|
+
} else if (kind === "envelope") {
|
|
427
|
+
group.appendChild(shape("path", { d: "M-8-5 8-2 8 6-8 3Z", fill: "#142e3c", stroke: color, "stroke-width": 1 }));
|
|
428
|
+
group.appendChild(shape("path", { d: "M-8-5 8-2 0 2Z" }));
|
|
429
|
+
group.appendChild(
|
|
430
|
+
shape("path", { d: "M-7-4 0 1 7-1", fill: "none", stroke: "#f0ffff", "stroke-width": 0.8, opacity: 0.8 })
|
|
431
|
+
);
|
|
432
|
+
} else {
|
|
433
|
+
group.appendChild(shape("path", { d: "M-8-2 0-6 8-2 0 2Z" }));
|
|
434
|
+
group.appendChild(shape("path", { d: "M-8-2 0 2 0 7-8 3Z", fill: "#183544", stroke: color, "stroke-width": 0.6 }));
|
|
435
|
+
group.appendChild(shape("path", { d: "M0 2 8-2 8 3 0 7Z", opacity: 0.65 }));
|
|
436
|
+
group.appendChild(
|
|
437
|
+
shape("path", { d: "M-6-2 0-5 6-2", fill: "none", stroke: "#fff", "stroke-width": 0.9, opacity: 0.85 })
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
return group;
|
|
441
|
+
}
|
|
442
|
+
function updateMessages(node, def, d, recreate) {
|
|
443
|
+
if (recreate) for (const old of node.querySelectorAll(".iso-message")) node.removeChild(old);
|
|
444
|
+
const message = def.message;
|
|
445
|
+
if (!message || message.enabled === false) return;
|
|
446
|
+
if (recreate) {
|
|
447
|
+
const count = message.count ?? 1;
|
|
448
|
+
const duration = message.duration ?? 1800;
|
|
449
|
+
for (let i = 0; i < count; i++) {
|
|
450
|
+
const token = shape("g", { class: "iso-message", "aria-hidden": "true", "data-kind": message.kind ?? "packet" });
|
|
451
|
+
token.style.animationDuration = `${duration}ms`;
|
|
452
|
+
token.style.animationDelay = `${-duration * i / count}ms`;
|
|
453
|
+
token.appendChild(messageToken(message.kind ?? "packet", message.size ?? 10, message.color ?? def.style.stroke));
|
|
454
|
+
node.appendChild(token);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
for (const token of node.querySelectorAll(".iso-message")) {
|
|
458
|
+
token.style.offsetPath = `path("${d}")`;
|
|
459
|
+
token.style.opacity = String(def.style.opacity);
|
|
460
|
+
token.style.animationDirection = def.direction === "reverse" ? "reverse" : "normal";
|
|
461
|
+
token.style.display = def.presence === "removed" ? "none" : "";
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
function updateActivity(node, activity, cellSize) {
|
|
465
|
+
for (const old of node.querySelectorAll(".iso-activity")) node.removeChild(old);
|
|
466
|
+
node.setAttribute("data-activity", activity?.state ?? "idle");
|
|
467
|
+
if (!activity || activity.state === "idle") return;
|
|
468
|
+
const state = activity.state;
|
|
469
|
+
const color = activity.color ?? { processing: "#67e8f9", waiting: "#fbbf24", complete: "#6ee7b7", error: "#fb7185" }[state];
|
|
470
|
+
const group = shape("g", {
|
|
471
|
+
class: `iso-activity iso-activity-${state}`,
|
|
472
|
+
color,
|
|
473
|
+
"aria-label": state,
|
|
474
|
+
"pointer-events": "none"
|
|
475
|
+
});
|
|
476
|
+
const radius = cellSize * 0.36;
|
|
477
|
+
const halo = shape("ellipse", {
|
|
478
|
+
cx: 0,
|
|
479
|
+
cy: -2,
|
|
480
|
+
rx: radius,
|
|
481
|
+
ry: radius * 0.42,
|
|
482
|
+
fill: color,
|
|
483
|
+
"fill-opacity": 0.08,
|
|
484
|
+
stroke: color,
|
|
485
|
+
"stroke-opacity": 0.6,
|
|
486
|
+
"stroke-width": 1.3,
|
|
487
|
+
class: "iso-activity-ring"
|
|
488
|
+
});
|
|
489
|
+
group.appendChild(halo);
|
|
490
|
+
const badge = shape("g", {
|
|
491
|
+
transform: `translate(${cellSize * 0.29} ${-cellSize * 0.6})`,
|
|
492
|
+
class: "iso-activity-badge"
|
|
493
|
+
});
|
|
494
|
+
badge.appendChild(shape("circle", { r: 6, fill: "#102330", stroke: color, "stroke-width": 1 }));
|
|
495
|
+
const glyph = {
|
|
496
|
+
processing: "M-2 0h4M0-2v4",
|
|
497
|
+
waiting: "M-2-2v4M2-2v4",
|
|
498
|
+
complete: "M-3 0-1 2 3-2",
|
|
499
|
+
error: "M0-3v3M0 2v.5"
|
|
500
|
+
}[state];
|
|
501
|
+
badge.appendChild(
|
|
502
|
+
shape("path", {
|
|
503
|
+
d: glyph,
|
|
504
|
+
fill: "none",
|
|
505
|
+
stroke: color,
|
|
506
|
+
"stroke-width": 1.5,
|
|
507
|
+
"stroke-linecap": "round",
|
|
508
|
+
"stroke-linejoin": "round"
|
|
509
|
+
})
|
|
510
|
+
);
|
|
511
|
+
group.appendChild(badge);
|
|
512
|
+
node.appendChild(group);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const CSS_CUSTOM_PROPERTY_PATTERN = /^--[a-zA-Z0-9-_]+$/;
|
|
516
|
+
function applyThemeToElement(element, themeVars) {
|
|
517
|
+
for (const [name, value] of Object.entries(themeVars)) {
|
|
518
|
+
if (!CSS_CUSTOM_PROPERTY_PATTERN.test(name)) {
|
|
519
|
+
throw new RenderError("INVALID_THEME_VAR", `Invalid CSS custom property name: ${name}`);
|
|
520
|
+
}
|
|
521
|
+
element.style.setProperty(name, value);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const NS = "http://www.w3.org/2000/svg";
|
|
526
|
+
const BUILT_IN_TEXT_ASSET_ID = "text";
|
|
527
|
+
const BUILT_IN_PRIMITIVE_ASSET_IDS = /* @__PURE__ */ new Set(["rectangle", "circle", "polygon", "line"]);
|
|
528
|
+
const DEFAULT_CONNECTOR_DASH = {
|
|
529
|
+
dashed: [12, 8],
|
|
530
|
+
dotted: [0, 8]
|
|
531
|
+
};
|
|
532
|
+
const ENDPOINT_RADIUS_GRID = 0.14;
|
|
533
|
+
const ARROW_LENGTH_GRID = 0.35;
|
|
534
|
+
const ARROW_WIDTH_GRID = 0.28;
|
|
535
|
+
const BAR_WIDTH_GRID = 0.4;
|
|
536
|
+
function buildSceneDOM(container, bundle, config) {
|
|
537
|
+
const layout = resolveSceneLayout(bundle);
|
|
538
|
+
const initialStop = bundle.scenes[0];
|
|
539
|
+
const allElements = collectElementDefinitions(bundle);
|
|
540
|
+
const allConnectors = collectConnectorDefinitions(bundle);
|
|
541
|
+
const initialById = new Map((initialStop?.elements ?? []).map((element) => [element.id, element]));
|
|
542
|
+
const initialConnectorsById = new Map((initialStop?.connectors ?? []).map((connector) => [connector.id, connector]));
|
|
543
|
+
const svg = createRootSvg(layout, config?.label, bundle.className);
|
|
544
|
+
const assetResolver = createAssetResolver(bundle);
|
|
545
|
+
svg._assetResolver = assetResolver;
|
|
546
|
+
svg.appendChild(createCssDefs());
|
|
547
|
+
applyThemeToElement(svg, {
|
|
548
|
+
...resolveTheme(bundle.theme) ?? {},
|
|
549
|
+
...bundle.themeVars ?? {},
|
|
550
|
+
...config?.themeVars ?? {}
|
|
551
|
+
});
|
|
552
|
+
const sortedLayers = sortLayers(bundle.layers);
|
|
553
|
+
const layerMap = createLayerMap(sortedLayers);
|
|
554
|
+
if (bundle.floor.visible) {
|
|
555
|
+
svg.appendChild(createFloorGrid(bundle, layout));
|
|
556
|
+
}
|
|
557
|
+
const connectorMap = /* @__PURE__ */ new Map();
|
|
558
|
+
for (const def of allConnectors) {
|
|
559
|
+
const initial = initialConnectorsById.get(def.id) ?? {
|
|
560
|
+
...def,
|
|
561
|
+
presence: "removed"
|
|
562
|
+
};
|
|
563
|
+
const state = createConnectorInstance(initial, layout);
|
|
564
|
+
if (initial.presence === "removed") {
|
|
565
|
+
state.isHidden = true;
|
|
566
|
+
hideElementAfterExit(state.node);
|
|
567
|
+
}
|
|
568
|
+
applyConnectorAmbientClasses(state, initial.ambient ?? []);
|
|
569
|
+
svg.appendChild(state.node);
|
|
570
|
+
connectorMap.set(def.id, state);
|
|
571
|
+
}
|
|
572
|
+
const depthGroup = document.createElementNS(NS, "g");
|
|
573
|
+
depthGroup.classList.add("iso-depth-layer");
|
|
574
|
+
depthGroup.setAttribute("data-layer", "depth");
|
|
575
|
+
svg.appendChild(depthGroup);
|
|
576
|
+
const labelGroup = document.createElementNS(NS, "g");
|
|
577
|
+
labelGroup.classList.add("iso-layer", "iso-layer-labels");
|
|
578
|
+
labelGroup.setAttribute("data-layer", "labels");
|
|
579
|
+
svg.appendChild(labelGroup);
|
|
580
|
+
const elementMap = /* @__PURE__ */ new Map();
|
|
581
|
+
const sortedElements = sortElementsForPerspective(allElements);
|
|
582
|
+
for (const def of sortedElements) {
|
|
583
|
+
const declaredLayer = layerMap.get(def.layer);
|
|
584
|
+
if (!declaredLayer) {
|
|
585
|
+
throw new RenderError("MISSING_LAYER", `Unknown layer for "${def.id}": ${def.layer}`);
|
|
586
|
+
}
|
|
587
|
+
const initial = initialById.get(def.id) ?? {
|
|
588
|
+
...def,
|
|
589
|
+
presence: "removed"
|
|
590
|
+
};
|
|
591
|
+
const instance = createElementInstance(initial, layout, assetResolver);
|
|
592
|
+
instance.anchor = assetAnchorForBounds(bundle, initial);
|
|
593
|
+
instance.node.classList.add(`iso-layer-${def.layer}`);
|
|
594
|
+
instance.node.setAttribute("data-layer", def.layer);
|
|
595
|
+
if (initial.presence === "removed") {
|
|
596
|
+
instance.isHidden = true;
|
|
597
|
+
hideElementAfterExit(instance.node);
|
|
598
|
+
}
|
|
599
|
+
applyAmbientClasses(instance, initial.ambient ?? []);
|
|
600
|
+
const parent = isTextAsset(def.asset) ? labelGroup : depthGroup;
|
|
601
|
+
parent.appendChild(instance.node);
|
|
602
|
+
elementMap.set(def.id, instance);
|
|
603
|
+
}
|
|
604
|
+
svg._layerMap = layerMap;
|
|
605
|
+
svg._elementMap = elementMap;
|
|
606
|
+
svg._connectorMap = connectorMap;
|
|
607
|
+
svg._depthGroup = depthGroup;
|
|
608
|
+
container.appendChild(svg);
|
|
609
|
+
return svg;
|
|
610
|
+
}
|
|
611
|
+
function updateElementTransforms(svg, elements, connectors = []) {
|
|
612
|
+
const layout = svg._layout;
|
|
613
|
+
if (!layout) return;
|
|
614
|
+
const map = svg._elementMap;
|
|
615
|
+
if (map) {
|
|
616
|
+
for (const def of elements) {
|
|
617
|
+
const state = map.get(def.id);
|
|
618
|
+
if (!state) continue;
|
|
619
|
+
const previous = state.current;
|
|
620
|
+
state.current = def;
|
|
621
|
+
if (!hasEqualGeneratedContent(previous, def)) {
|
|
622
|
+
updateGeneratedElementContent(state.node, def, layout, svg._assetResolver);
|
|
623
|
+
state.anchor = svg._assetResolver?.(def.asset)?.anchor ?? [0.5, 1];
|
|
624
|
+
}
|
|
625
|
+
if (!hasEqualGeneratedContent(previous, def) || !deepEqual(previous.activity, def.activity)) {
|
|
626
|
+
updateActivity(state.node, def.activity, layout.cellSize);
|
|
627
|
+
}
|
|
628
|
+
applyElementTransform(state.node, def, layout);
|
|
629
|
+
applyAmbientClasses(state, def.ambient ?? []);
|
|
630
|
+
}
|
|
631
|
+
if (svg._depthGroup) {
|
|
632
|
+
reconcileDepthOrder(svg._depthGroup, map);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
const connectorMap = svg._connectorMap;
|
|
636
|
+
if (!connectorMap) return;
|
|
637
|
+
for (const def of connectors) {
|
|
638
|
+
const state = connectorMap.get(def.id);
|
|
639
|
+
if (!state) continue;
|
|
640
|
+
applyConnectorState(state, def, layout);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function getElementState(svg, id) {
|
|
644
|
+
return svg._elementMap?.get(id);
|
|
645
|
+
}
|
|
646
|
+
function getConnectorState(svg, id) {
|
|
647
|
+
return svg._connectorMap?.get(id);
|
|
648
|
+
}
|
|
649
|
+
function getResolvedViewBox(bundle) {
|
|
650
|
+
return resolveSceneLayout(bundle).viewBox;
|
|
651
|
+
}
|
|
652
|
+
function getResolvedProjectionLayout(bundle) {
|
|
653
|
+
const layout = resolveSceneLayout(bundle);
|
|
654
|
+
return {
|
|
655
|
+
cellSize: layout.cellSize,
|
|
656
|
+
padding: layout.padding,
|
|
657
|
+
selectedBounds: layout.selectedBounds
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
function getCurrentElementBounds(svg, id) {
|
|
661
|
+
const layout = svg._layout;
|
|
662
|
+
const state = svg._elementMap?.get(id);
|
|
663
|
+
if (!layout || !state || state.current.presence === "removed") return void 0;
|
|
664
|
+
return boundsToViewBox(calculateElementBounds(state.current, layout, state.anchor));
|
|
665
|
+
}
|
|
666
|
+
function getGridAreaBounds(bundle, area) {
|
|
667
|
+
const layout = resolveSceneLayout(bundle);
|
|
668
|
+
const [x, y] = area.at;
|
|
669
|
+
const [width, height] = area.size;
|
|
670
|
+
let bounds = emptyBounds();
|
|
671
|
+
for (const point of [
|
|
672
|
+
[x, y],
|
|
673
|
+
[x + width, y],
|
|
674
|
+
[x, y + height],
|
|
675
|
+
[x + width, y + height]
|
|
676
|
+
]) {
|
|
677
|
+
const screen = projectToScreen(
|
|
678
|
+
point[0],
|
|
679
|
+
point[1],
|
|
680
|
+
layout.cellSize,
|
|
681
|
+
layout.selectedBounds.minX,
|
|
682
|
+
layout.selectedBounds.minY,
|
|
683
|
+
layout.padding.x,
|
|
684
|
+
layout.padding.y
|
|
685
|
+
);
|
|
686
|
+
bounds = includePoint(bounds, screen.screenX, screen.screenY);
|
|
687
|
+
}
|
|
688
|
+
return boundsToViewBox(bounds);
|
|
689
|
+
}
|
|
690
|
+
function applySceneViewBox(svg, viewBox) {
|
|
691
|
+
svg.setAttribute("viewBox", `${viewBox.minX} ${viewBox.minY} ${viewBox.width} ${viewBox.height}`);
|
|
692
|
+
}
|
|
693
|
+
function hideElementAfterExit(node) {
|
|
694
|
+
node.classList.add("iso-motion-paused");
|
|
695
|
+
node.style.visibility = "hidden";
|
|
696
|
+
node.style.pointerEvents = "none";
|
|
697
|
+
}
|
|
698
|
+
function unhideElementOnReadd(node) {
|
|
699
|
+
node.classList.remove("iso-motion-paused");
|
|
700
|
+
node.style.visibility = "visible";
|
|
701
|
+
node.style.pointerEvents = "auto";
|
|
702
|
+
}
|
|
703
|
+
function resolveSceneLayout(bundle) {
|
|
704
|
+
const cellSize = bundle.grid.cellSize;
|
|
705
|
+
const padding = bundle.layout.padding;
|
|
706
|
+
const contentBounds = calculateContentBounds(bundle, cellSize);
|
|
707
|
+
const floorBounds = calculateFloorBounds(bundle, cellSize);
|
|
708
|
+
const selectedBounds = selectBounds(bundle.layout.bounds, contentBounds, floorBounds);
|
|
709
|
+
const width = selectedBounds.maxX - selectedBounds.minX + padding.x * 2;
|
|
710
|
+
const height = selectedBounds.maxY - selectedBounds.minY + padding.y * 2;
|
|
711
|
+
const viewBox = {
|
|
712
|
+
minX: 0,
|
|
713
|
+
minY: 0,
|
|
714
|
+
width: roundDimension(width || cellSize),
|
|
715
|
+
height: roundDimension(height || cellSize)
|
|
716
|
+
};
|
|
717
|
+
return {
|
|
718
|
+
cellSize,
|
|
719
|
+
padding,
|
|
720
|
+
contentBounds,
|
|
721
|
+
floorBounds,
|
|
722
|
+
selectedBounds,
|
|
723
|
+
viewBox
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
function calculateContentBounds(bundle, cellSize) {
|
|
727
|
+
let bounds = emptyBounds();
|
|
728
|
+
for (const stop of bundle.scenes) {
|
|
729
|
+
for (const element of stop.elements ?? []) {
|
|
730
|
+
if (element.presence === "removed") continue;
|
|
731
|
+
bounds = includeBounds(bounds, calculateRawElementBounds(bundle, element, cellSize));
|
|
732
|
+
}
|
|
733
|
+
for (const connector of stop.connectors ?? []) {
|
|
734
|
+
if (connector.presence === "removed") continue;
|
|
735
|
+
bounds = includeBounds(bounds, calculateConnectorBounds(connector, cellSize));
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
return normalizeBounds(bounds, cellSize);
|
|
739
|
+
}
|
|
740
|
+
function calculateRawElementBounds(bundle, element, cellSize) {
|
|
741
|
+
const { rawX, rawY } = projectToRaw(element.pos[0] + element.size, element.pos[1] + element.size, cellSize);
|
|
742
|
+
const visualSize = calculateVisualSize(element.size, cellSize);
|
|
743
|
+
const [anchorX, anchorY] = assetAnchorForBounds(bundle, element);
|
|
744
|
+
return activityBounds(
|
|
745
|
+
{
|
|
746
|
+
minX: rawX - visualSize * anchorX,
|
|
747
|
+
minY: rawY - visualSize * anchorY,
|
|
748
|
+
maxX: rawX + visualSize * (1 - anchorX),
|
|
749
|
+
maxY: rawY + visualSize * (1 - anchorY)
|
|
750
|
+
},
|
|
751
|
+
element,
|
|
752
|
+
rawX,
|
|
753
|
+
rawY,
|
|
754
|
+
visualSize
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
function calculateElementBounds(element, layout, anchor) {
|
|
758
|
+
const screen = projectToScreen(
|
|
759
|
+
element.pos[0] + element.size,
|
|
760
|
+
element.pos[1] + element.size,
|
|
761
|
+
layout.cellSize,
|
|
762
|
+
layout.selectedBounds.minX,
|
|
763
|
+
layout.selectedBounds.minY,
|
|
764
|
+
layout.padding.x,
|
|
765
|
+
layout.padding.y
|
|
766
|
+
);
|
|
767
|
+
const visualSize = calculateVisualSize(element.size, layout.cellSize);
|
|
768
|
+
return activityBounds(
|
|
769
|
+
{
|
|
770
|
+
minX: screen.screenX - visualSize * anchor[0],
|
|
771
|
+
minY: screen.screenY - visualSize * anchor[1],
|
|
772
|
+
maxX: screen.screenX + visualSize * (1 - anchor[0]),
|
|
773
|
+
maxY: screen.screenY + visualSize * (1 - anchor[1])
|
|
774
|
+
},
|
|
775
|
+
element,
|
|
776
|
+
screen.screenX,
|
|
777
|
+
screen.screenY,
|
|
778
|
+
visualSize
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
function activityBounds(bounds, element, x, y, size) {
|
|
782
|
+
if (!element.activity || element.activity.state === "idle") return bounds;
|
|
783
|
+
return includeBounds(bounds, {
|
|
784
|
+
minX: x - size * 0.4,
|
|
785
|
+
maxX: x + size * 0.4,
|
|
786
|
+
minY: y - size * 0.72,
|
|
787
|
+
maxY: y + size * 0.18
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
function assetAnchorForBounds(bundle, element) {
|
|
791
|
+
return bundle.assets?.[element.asset]?.anchor ?? [0.5, 1];
|
|
792
|
+
}
|
|
793
|
+
function calculateConnectorBounds(connector, cellSize) {
|
|
794
|
+
let bounds = emptyBounds();
|
|
795
|
+
for (const [x, y] of connector.route) {
|
|
796
|
+
const { rawX, rawY } = projectToRaw(x, y, cellSize);
|
|
797
|
+
bounds = includePoint(bounds, rawX, rawY);
|
|
798
|
+
}
|
|
799
|
+
const endpointPadding = Math.max(ARROW_LENGTH_GRID, BAR_WIDTH_GRID, ENDPOINT_RADIUS_GRID * 2) * cellSize;
|
|
800
|
+
const strokePadding = connector.style.strokeWidth / 2 + (connector.style.outlineWidth ?? 0);
|
|
801
|
+
const padding = endpointPadding + strokePadding + (connector.style.glow ? (connector.style.glowWidth ?? 8) / 2 : 0) + (connector.message?.size ?? 0) / 2;
|
|
802
|
+
return {
|
|
803
|
+
minX: bounds.minX - padding,
|
|
804
|
+
minY: bounds.minY - padding,
|
|
805
|
+
maxX: bounds.maxX + padding,
|
|
806
|
+
maxY: bounds.maxY + padding
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
function calculateFloorBounds(bundle, cellSize) {
|
|
810
|
+
const origin = bundle.floor.origin;
|
|
811
|
+
const [width, height] = bundle.floor.size;
|
|
812
|
+
const points = [
|
|
813
|
+
origin,
|
|
814
|
+
[origin[0] + width, origin[1]],
|
|
815
|
+
[origin[0], origin[1] + height],
|
|
816
|
+
[origin[0] + width, origin[1] + height]
|
|
817
|
+
];
|
|
818
|
+
let bounds = emptyBounds();
|
|
819
|
+
for (const [x, y] of points) {
|
|
820
|
+
const { rawX, rawY } = projectToRaw(x, y, cellSize);
|
|
821
|
+
bounds = includePoint(bounds, rawX, rawY);
|
|
822
|
+
}
|
|
823
|
+
return normalizeBounds(bounds, cellSize);
|
|
824
|
+
}
|
|
825
|
+
function selectBounds(mode, content, floor) {
|
|
826
|
+
if (mode === "content") return content;
|
|
827
|
+
if (mode === "floor") return floor;
|
|
828
|
+
return includeBounds(content, floor);
|
|
829
|
+
}
|
|
830
|
+
function emptyBounds() {
|
|
831
|
+
return {
|
|
832
|
+
minX: Number.POSITIVE_INFINITY,
|
|
833
|
+
minY: Number.POSITIVE_INFINITY,
|
|
834
|
+
maxX: Number.NEGATIVE_INFINITY,
|
|
835
|
+
maxY: Number.NEGATIVE_INFINITY
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
function normalizeBounds(bounds, cellSize) {
|
|
839
|
+
if (Number.isFinite(bounds.minX)) return bounds;
|
|
840
|
+
return { minX: 0, minY: 0, maxX: cellSize, maxY: cellSize };
|
|
841
|
+
}
|
|
842
|
+
function boundsToViewBox(bounds) {
|
|
843
|
+
const centerX = (bounds.minX + bounds.maxX) / 2;
|
|
844
|
+
const centerY = (bounds.minY + bounds.maxY) / 2;
|
|
845
|
+
const width = Math.max(1, bounds.maxX - bounds.minX);
|
|
846
|
+
const height = Math.max(1, bounds.maxY - bounds.minY);
|
|
847
|
+
return {
|
|
848
|
+
minX: roundDimension(centerX - width / 2),
|
|
849
|
+
minY: roundDimension(centerY - height / 2),
|
|
850
|
+
width: roundDimension(width),
|
|
851
|
+
height: roundDimension(height)
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
function includePoint(bounds, x, y) {
|
|
855
|
+
return {
|
|
856
|
+
minX: Math.min(bounds.minX, x),
|
|
857
|
+
minY: Math.min(bounds.minY, y),
|
|
858
|
+
maxX: Math.max(bounds.maxX, x),
|
|
859
|
+
maxY: Math.max(bounds.maxY, y)
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
function includeBounds(bounds, next) {
|
|
863
|
+
return {
|
|
864
|
+
minX: Math.min(bounds.minX, next.minX),
|
|
865
|
+
minY: Math.min(bounds.minY, next.minY),
|
|
866
|
+
maxX: Math.max(bounds.maxX, next.maxX),
|
|
867
|
+
maxY: Math.max(bounds.maxY, next.maxY)
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
function roundDimension(value) {
|
|
871
|
+
return Math.round(value * 1e3) / 1e3;
|
|
872
|
+
}
|
|
873
|
+
function createRootSvg(layout, label, className) {
|
|
874
|
+
const svg = document.createElementNS(NS, "svg");
|
|
875
|
+
svg.classList.add("iso-scene");
|
|
876
|
+
for (const token of className?.trim().split(/\s+/) ?? []) {
|
|
877
|
+
if (token) svg.classList.add(token);
|
|
878
|
+
}
|
|
879
|
+
svg.setAttribute("width", "100%");
|
|
880
|
+
svg.setAttribute("height", "100%");
|
|
881
|
+
svg.setAttribute(
|
|
882
|
+
"viewBox",
|
|
883
|
+
`${layout.viewBox.minX} ${layout.viewBox.minY} ${layout.viewBox.width} ${layout.viewBox.height}`
|
|
884
|
+
);
|
|
885
|
+
svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
886
|
+
svg.style.width = "100%";
|
|
887
|
+
svg.style.height = "100%";
|
|
888
|
+
svg.style.display = "block";
|
|
889
|
+
if (label) {
|
|
890
|
+
svg.setAttribute("role", "img");
|
|
891
|
+
svg.setAttribute("aria-label", label);
|
|
892
|
+
} else {
|
|
893
|
+
svg.setAttribute("aria-hidden", "true");
|
|
894
|
+
}
|
|
895
|
+
svg._layout = layout;
|
|
896
|
+
svg._viewBoxW = layout.viewBox.width;
|
|
897
|
+
svg._viewBoxH = layout.viewBox.height;
|
|
898
|
+
return svg;
|
|
899
|
+
}
|
|
900
|
+
function createCssDefs() {
|
|
901
|
+
const styleEl = document.createElementNS(NS, "style");
|
|
902
|
+
styleEl.textContent = buildKeyframeCSS();
|
|
903
|
+
return styleEl;
|
|
904
|
+
}
|
|
905
|
+
function createFloorGrid(bundle, layout) {
|
|
906
|
+
const group = document.createElementNS(NS, "g");
|
|
907
|
+
group.classList.add("iso-floor-grid", `iso-layer-${bundle.floor.layer}`);
|
|
908
|
+
group.setAttribute("data-layer", bundle.floor.layer);
|
|
909
|
+
const [originX, originY] = bundle.floor.origin;
|
|
910
|
+
const [columns, rows] = bundle.floor.size;
|
|
911
|
+
const corners = [
|
|
912
|
+
projectGridPoint(originX, originY, layout),
|
|
913
|
+
projectGridPoint(originX + columns, originY, layout),
|
|
914
|
+
projectGridPoint(originX + columns, originY + rows, layout),
|
|
915
|
+
projectGridPoint(originX, originY + rows, layout)
|
|
916
|
+
];
|
|
917
|
+
const slab = document.createElementNS(NS, "polygon");
|
|
918
|
+
slab.classList.add("iso-floor-slab");
|
|
919
|
+
slab.setAttribute("points", corners.map(pointToString).join(" "));
|
|
920
|
+
slab.setAttribute("fill", "#dbe6f4");
|
|
921
|
+
slab.setAttribute("fill-opacity", "0.22");
|
|
922
|
+
slab.setAttribute("stroke", "#b9c9df");
|
|
923
|
+
slab.setAttribute("stroke-width", "1");
|
|
924
|
+
group.appendChild(slab);
|
|
925
|
+
for (let x = 0; x <= columns; x++) {
|
|
926
|
+
group.appendChild(
|
|
927
|
+
createFloorLine(
|
|
928
|
+
projectGridPoint(originX + x, originY, layout),
|
|
929
|
+
projectGridPoint(originX + x, originY + rows, layout)
|
|
930
|
+
)
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
for (let y = 0; y <= rows; y++) {
|
|
934
|
+
group.appendChild(
|
|
935
|
+
createFloorLine(
|
|
936
|
+
projectGridPoint(originX, originY + y, layout),
|
|
937
|
+
projectGridPoint(originX + columns, originY + y, layout)
|
|
938
|
+
)
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
return group;
|
|
942
|
+
}
|
|
943
|
+
function createFloorLine(start, end) {
|
|
944
|
+
const line = document.createElementNS(NS, "line");
|
|
945
|
+
line.setAttribute("x1", String(start.x));
|
|
946
|
+
line.setAttribute("y1", String(start.y));
|
|
947
|
+
line.setAttribute("x2", String(end.x));
|
|
948
|
+
line.setAttribute("y2", String(end.y));
|
|
949
|
+
line.setAttribute("stroke", "#2563eb");
|
|
950
|
+
line.setAttribute("stroke-width", "1");
|
|
951
|
+
line.setAttribute("stroke-dasharray", "5 5");
|
|
952
|
+
line.setAttribute("stroke-opacity", "0.2");
|
|
953
|
+
return line;
|
|
954
|
+
}
|
|
955
|
+
function projectGridPoint(x, y, layout) {
|
|
956
|
+
const screen = projectToScreen(
|
|
957
|
+
x,
|
|
958
|
+
y,
|
|
959
|
+
layout.cellSize,
|
|
960
|
+
layout.selectedBounds.minX,
|
|
961
|
+
layout.selectedBounds.minY,
|
|
962
|
+
layout.padding.x,
|
|
963
|
+
layout.padding.y
|
|
964
|
+
);
|
|
965
|
+
return { x: screen.screenX, y: screen.screenY };
|
|
966
|
+
}
|
|
967
|
+
function pointToString(point) {
|
|
968
|
+
return `${point.x},${point.y}`;
|
|
969
|
+
}
|
|
970
|
+
function createLayerMap(layers) {
|
|
971
|
+
return new Map(layers.map((layer) => [layer.name, layer]));
|
|
972
|
+
}
|
|
973
|
+
function sortLayers(layers) {
|
|
974
|
+
return [...layers].map((layer, index) => ({ name: layer.name, order: layer.order ?? index })).sort((a, b) => a.order - b.order || a.name.localeCompare(b.name));
|
|
975
|
+
}
|
|
976
|
+
function sortElementsForPerspective(elements) {
|
|
977
|
+
return elements.slice().sort((a, b) => {
|
|
978
|
+
const bucket = renderBucket(a) - renderBucket(b);
|
|
979
|
+
if (bucket !== 0) return bucket;
|
|
980
|
+
const depth = a.pos[0] + a.pos[1] - (b.pos[0] + b.pos[1]);
|
|
981
|
+
if (depth !== 0) return depth;
|
|
982
|
+
return a.id.localeCompare(b.id);
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
function renderBucket(element) {
|
|
986
|
+
if (isTextAsset(element.asset)) return 1;
|
|
987
|
+
return 0;
|
|
988
|
+
}
|
|
989
|
+
function reconcileDepthOrder(depthGroup, elementMap) {
|
|
990
|
+
const current = [];
|
|
991
|
+
for (const state of elementMap.values()) {
|
|
992
|
+
if (state.node.parentElement !== depthGroup) continue;
|
|
993
|
+
current.push(state.current);
|
|
994
|
+
}
|
|
995
|
+
if (current.length < 2) return;
|
|
996
|
+
const desiredOrder = sortElementsForPerspective(current);
|
|
997
|
+
const existingOrder = [...depthGroup.childNodes];
|
|
998
|
+
let orderMatches = existingOrder.length === desiredOrder.length;
|
|
999
|
+
if (orderMatches) {
|
|
1000
|
+
for (let index = 0; index < desiredOrder.length; index++) {
|
|
1001
|
+
const expectedId = desiredOrder[index]?.id;
|
|
1002
|
+
if (existingOrder[index]?.getAttribute("data-id") !== expectedId) {
|
|
1003
|
+
orderMatches = false;
|
|
1004
|
+
break;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
if (orderMatches) return;
|
|
1009
|
+
for (const def of desiredOrder) {
|
|
1010
|
+
const state = elementMap.get(def.id);
|
|
1011
|
+
if (state) depthGroup.appendChild(state.node);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
function collectElementDefinitions(bundle) {
|
|
1015
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1016
|
+
for (const stop of bundle.scenes) {
|
|
1017
|
+
for (const element of stop.elements ?? []) {
|
|
1018
|
+
if (!byId.has(element.id) || byId.get(element.id)?.presence === "removed") {
|
|
1019
|
+
byId.set(element.id, element);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return [...byId.values()];
|
|
1024
|
+
}
|
|
1025
|
+
function collectConnectorDefinitions(bundle) {
|
|
1026
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1027
|
+
for (const stop of bundle.scenes) {
|
|
1028
|
+
for (const connector of stop.connectors ?? []) {
|
|
1029
|
+
if (!byId.has(connector.id) || byId.get(connector.id)?.presence === "removed") {
|
|
1030
|
+
byId.set(connector.id, connector);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
return [...byId.values()];
|
|
1035
|
+
}
|
|
1036
|
+
function createElementInstance(def, layout, resolveAsset) {
|
|
1037
|
+
const node = def.asset === BUILT_IN_TEXT_ASSET_ID ? createTextAssetNode(def.text, def.asset, layout.cellSize) : isPrimitiveAsset(def.asset) ? createPrimitiveAssetNode(def.asset, def.primitive, layout.cellSize) : createResolvedAssetNode(def, resolveAsset, layout.cellSize);
|
|
1038
|
+
node.classList.add("iso-element", `iso-element-${def.id}`);
|
|
1039
|
+
node.setAttribute("data-id", def.id);
|
|
1040
|
+
node.setAttribute("data-asset", def.asset);
|
|
1041
|
+
node.style.overflow = "visible";
|
|
1042
|
+
node.style.pointerEvents = "auto";
|
|
1043
|
+
applyElementTransform(node, def, layout);
|
|
1044
|
+
updateActivity(node, def.activity, layout.cellSize);
|
|
1045
|
+
const entryAnim = def.enter;
|
|
1046
|
+
if (entryAnim && entryAnim !== "none" && def.presence !== "removed") {
|
|
1047
|
+
const keyName = `iso-anim-${entryAnim}`;
|
|
1048
|
+
animateElement(node, keyName, "enter");
|
|
1049
|
+
const expectedAnimation = node.style.animation;
|
|
1050
|
+
node.addEventListener(
|
|
1051
|
+
"animationend",
|
|
1052
|
+
() => {
|
|
1053
|
+
if (node.style.animation === expectedAnimation) node.style.animation = "";
|
|
1054
|
+
},
|
|
1055
|
+
{ once: true }
|
|
1056
|
+
);
|
|
1057
|
+
return { node, current: def, anchor: [0.5, 1], isHidden: false, entryKey: entryAnim, ambient: /* @__PURE__ */ new Set() };
|
|
1058
|
+
}
|
|
1059
|
+
return { node, current: def, anchor: [0.5, 1], isHidden: false, ambient: /* @__PURE__ */ new Set() };
|
|
1060
|
+
}
|
|
1061
|
+
function isTextAsset(assetId) {
|
|
1062
|
+
return assetId === BUILT_IN_TEXT_ASSET_ID;
|
|
1063
|
+
}
|
|
1064
|
+
function isPrimitiveAsset(assetId) {
|
|
1065
|
+
return BUILT_IN_PRIMITIVE_ASSET_IDS.has(assetId);
|
|
1066
|
+
}
|
|
1067
|
+
function createResolvedAssetNode(def, resolveAsset, cellSize) {
|
|
1068
|
+
const asset = resolveAsset(def.asset);
|
|
1069
|
+
if (!asset) {
|
|
1070
|
+
throw new RenderError("ASSET_NOT_FOUND", `Asset not found: ${def.asset}`, {
|
|
1071
|
+
asset: def.asset,
|
|
1072
|
+
elementId: def.id
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
return createAssetNode(asset, def.asset, cellSize);
|
|
1076
|
+
}
|
|
1077
|
+
function updateGeneratedElementContent(node, def, layout, resolveAsset) {
|
|
1078
|
+
const replacement = isTextAsset(def.asset) ? createTextAssetNode(def.text, def.asset, layout.cellSize) : isPrimitiveAsset(def.asset) ? createPrimitiveAssetNode(def.asset, def.primitive, layout.cellSize) : createResolvedAssetNode(def, resolveAsset ?? createAssetResolver(), layout.cellSize);
|
|
1079
|
+
node.setAttribute("data-asset", def.asset);
|
|
1080
|
+
clearChildren(node);
|
|
1081
|
+
while (replacement.firstChild) {
|
|
1082
|
+
const child = replacement.firstChild;
|
|
1083
|
+
replacement.removeChild(child);
|
|
1084
|
+
node.appendChild(child);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
function hasEqualGeneratedContent(previous, next) {
|
|
1088
|
+
if (!previous) return false;
|
|
1089
|
+
if (previous.asset !== next.asset) return false;
|
|
1090
|
+
if (!isTextAsset(next.asset) && !isPrimitiveAsset(next.asset)) return true;
|
|
1091
|
+
if (isTextAsset(next.asset)) return deepEqual(previous.text, next.text);
|
|
1092
|
+
return deepEqual(previous.primitive, next.primitive);
|
|
1093
|
+
}
|
|
1094
|
+
function deepEqual(a, b) {
|
|
1095
|
+
if (a === b) return true;
|
|
1096
|
+
if (typeof a !== typeof b) return false;
|
|
1097
|
+
if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
|
|
1098
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
1099
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
|
|
1100
|
+
return a.every((item, index) => deepEqual(item, b[index]));
|
|
1101
|
+
}
|
|
1102
|
+
const aKeys = Object.keys(a);
|
|
1103
|
+
const bKeys = Object.keys(b);
|
|
1104
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
1105
|
+
return aKeys.every((key) => deepEqual(a[key], b[key]));
|
|
1106
|
+
}
|
|
1107
|
+
function createConnectorInstance(def, layout) {
|
|
1108
|
+
const node = document.createElementNS(NS, "g");
|
|
1109
|
+
const shaft = document.createElementNS(NS, "path");
|
|
1110
|
+
node.appendChild(shaft);
|
|
1111
|
+
const state = { node, shaft, isHidden: false, ambient: /* @__PURE__ */ new Set() };
|
|
1112
|
+
applyConnectorState(state, def, layout);
|
|
1113
|
+
const entryAnim = def.enter;
|
|
1114
|
+
if (entryAnim && entryAnim !== "none" && def.presence !== "removed") {
|
|
1115
|
+
animateElement(node, `iso-anim-${entryAnim}`, "enter");
|
|
1116
|
+
const expectedAnimation = node.style.animation;
|
|
1117
|
+
node.addEventListener(
|
|
1118
|
+
"animationend",
|
|
1119
|
+
() => {
|
|
1120
|
+
if (node.style.animation === expectedAnimation) node.style.animation = "";
|
|
1121
|
+
},
|
|
1122
|
+
{ once: true }
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
return state;
|
|
1126
|
+
}
|
|
1127
|
+
function applyConnectorState(state, def, layout) {
|
|
1128
|
+
const previous = state.previous;
|
|
1129
|
+
const routeChanged = !previous || !routesEqual(previous.route, def.route);
|
|
1130
|
+
const styleChanged = !previous || !connectorStylesEqual(previous.style, def.style);
|
|
1131
|
+
const shapeChanged = !previous || shouldRenderOutline(previous) !== shouldRenderOutline(def) || previous.style.variant !== def.style.variant || previous.style.lane !== def.style.lane || previous.start !== def.start || previous.end !== def.end || previous.route.length !== def.route.length;
|
|
1132
|
+
applyConnectorGroupAttrs(state.node, def, previous);
|
|
1133
|
+
const geometryChanged = routeChanged || shapeChanged || styleChanged;
|
|
1134
|
+
const d = geometryChanged ? routePath(def.route, layout, def.style.cornerRadius ?? 0) : state.shaft.getAttribute("d") ?? "";
|
|
1135
|
+
if (shapeChanged) {
|
|
1136
|
+
if (state.outline) state.node.removeChild(state.outline);
|
|
1137
|
+
state.outline = void 0;
|
|
1138
|
+
if (shouldRenderOutline(def)) {
|
|
1139
|
+
const outline = document.createElementNS(NS, "path");
|
|
1140
|
+
outline.classList.add("iso-connector-outline");
|
|
1141
|
+
applyConnectorPathAttrs(outline, def, d, {
|
|
1142
|
+
stroke: def.style.outline ?? def.style.stroke,
|
|
1143
|
+
strokeWidth: def.style.strokeWidth + def.style.outlineWidth * 2,
|
|
1144
|
+
includeDash: false
|
|
1145
|
+
});
|
|
1146
|
+
state.node.insertBefore(outline, state.shaft);
|
|
1147
|
+
state.outline = outline;
|
|
1148
|
+
}
|
|
1149
|
+
} else if (state.outline && geometryChanged) {
|
|
1150
|
+
applyConnectorPathAttrs(state.outline, def, d, {
|
|
1151
|
+
stroke: def.style.outline ?? def.style.stroke,
|
|
1152
|
+
strokeWidth: def.style.strokeWidth + def.style.outlineWidth * 2,
|
|
1153
|
+
includeDash: false
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
if (!state.shaft.parentNode) state.node.appendChild(state.shaft);
|
|
1157
|
+
state.shaft.classList.add("iso-connector-shaft");
|
|
1158
|
+
if (geometryChanged) {
|
|
1159
|
+
applyConnectorPathAttrs(state.shaft, def, d, {
|
|
1160
|
+
stroke: def.style.stroke,
|
|
1161
|
+
strokeWidth: def.style.strokeWidth,
|
|
1162
|
+
includeDash: true
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
if (shapeChanged) {
|
|
1166
|
+
if (state.lane) state.node.removeChild(state.lane);
|
|
1167
|
+
state.lane = void 0;
|
|
1168
|
+
if (def.style.variant === "road" && def.style.lane === "center-dashed") {
|
|
1169
|
+
const lane = document.createElementNS(NS, "path");
|
|
1170
|
+
lane.classList.add("iso-connector-lane");
|
|
1171
|
+
applyConnectorPathAttrs(lane, def, d, {
|
|
1172
|
+
stroke: "#ffffff",
|
|
1173
|
+
strokeWidth: Math.max(1, def.style.strokeWidth * 0.12),
|
|
1174
|
+
includeDash: false
|
|
1175
|
+
});
|
|
1176
|
+
lane.setAttribute("stroke-dasharray", "8 8");
|
|
1177
|
+
state.node.appendChild(lane);
|
|
1178
|
+
state.lane = lane;
|
|
1179
|
+
}
|
|
1180
|
+
} else if (state.lane && geometryChanged) {
|
|
1181
|
+
applyConnectorPathAttrs(state.lane, def, d, {
|
|
1182
|
+
stroke: "#ffffff",
|
|
1183
|
+
strokeWidth: Math.max(1, def.style.strokeWidth * 0.12),
|
|
1184
|
+
includeDash: false
|
|
1185
|
+
});
|
|
1186
|
+
state.lane.setAttribute("stroke-dasharray", "8 8");
|
|
1187
|
+
}
|
|
1188
|
+
if (geometryChanged) {
|
|
1189
|
+
if (state.startEndpoint) state.node.removeChild(state.startEndpoint);
|
|
1190
|
+
if (state.endEndpoint) state.node.removeChild(state.endEndpoint);
|
|
1191
|
+
state.startEndpoint = appendEndpoint(state.node, def, "start", layout);
|
|
1192
|
+
state.endEndpoint = appendEndpoint(state.node, def, "end", layout);
|
|
1193
|
+
}
|
|
1194
|
+
if (geometryChanged) updateTrackEffects(state.node, state.shaft, def, d);
|
|
1195
|
+
updateMessages(
|
|
1196
|
+
state.node,
|
|
1197
|
+
def,
|
|
1198
|
+
d,
|
|
1199
|
+
!previous || !deepEqual(previous.message, def.message) || previous.style.stroke !== def.style.stroke
|
|
1200
|
+
);
|
|
1201
|
+
applyConnectorAmbientClasses(state, def.ambient ?? []);
|
|
1202
|
+
state.previous = def;
|
|
1203
|
+
}
|
|
1204
|
+
function clearChildren(node) {
|
|
1205
|
+
while (node.firstChild) node.removeChild(node.firstChild);
|
|
1206
|
+
}
|
|
1207
|
+
function routesEqual(a, b) {
|
|
1208
|
+
if (a === b) return true;
|
|
1209
|
+
if (a.length !== b.length) return false;
|
|
1210
|
+
return a.every((point, index) => {
|
|
1211
|
+
const other = b[index];
|
|
1212
|
+
return other !== void 0 && point[0] === other[0] && point[1] === other[1];
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
function connectorStylesEqual(a, b) {
|
|
1216
|
+
if (a === b) return true;
|
|
1217
|
+
return a.variant === b.variant && a.pattern === b.pattern && a.stroke === b.stroke && a.strokeWidth === b.strokeWidth && a.opacity === b.opacity && a.outline === b.outline && a.outlineWidth === b.outlineWidth && a.lane === b.lane && a.cornerRadius === b.cornerRadius && a.glow === b.glow && a.glowWidth === b.glowWidth && (a.dash ?? []).join(",") === (b.dash ?? []).join(",");
|
|
1218
|
+
}
|
|
1219
|
+
function applyConnectorGroupAttrs(node, def, previous) {
|
|
1220
|
+
const nextClasses = [
|
|
1221
|
+
"iso-connector",
|
|
1222
|
+
`iso-connector-${def.id}`,
|
|
1223
|
+
`iso-connector-variant-${def.style.variant}`,
|
|
1224
|
+
`iso-connector-pattern-${def.style.pattern}`,
|
|
1225
|
+
`iso-connector-direction-${def.direction}`,
|
|
1226
|
+
`iso-layer-${def.layer}`
|
|
1227
|
+
];
|
|
1228
|
+
if (!previous) {
|
|
1229
|
+
node.classList.add(...nextClasses);
|
|
1230
|
+
} else {
|
|
1231
|
+
const previousClasses = [
|
|
1232
|
+
"iso-connector",
|
|
1233
|
+
`iso-connector-${previous.id}`,
|
|
1234
|
+
`iso-connector-variant-${previous.style.variant}`,
|
|
1235
|
+
`iso-connector-pattern-${previous.style.pattern}`,
|
|
1236
|
+
`iso-connector-direction-${previous.direction}`,
|
|
1237
|
+
`iso-layer-${previous.layer}`
|
|
1238
|
+
];
|
|
1239
|
+
for (const name of previousClasses) {
|
|
1240
|
+
if (!nextClasses.includes(name)) node.classList.remove(name);
|
|
1241
|
+
}
|
|
1242
|
+
for (const name of nextClasses) {
|
|
1243
|
+
if (!previousClasses.includes(name)) node.classList.add(name);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
node.setAttribute("data-id", def.id);
|
|
1247
|
+
node.setAttribute("data-layer", def.layer);
|
|
1248
|
+
node.style.overflow = "visible";
|
|
1249
|
+
node.style.pointerEvents = "auto";
|
|
1250
|
+
}
|
|
1251
|
+
function shouldRenderOutline(def) {
|
|
1252
|
+
return Boolean(def.style.outline && def.style.outlineWidth > 0);
|
|
1253
|
+
}
|
|
1254
|
+
function applyConnectorPathAttrs(path, def, d, options) {
|
|
1255
|
+
path.setAttribute("d", d);
|
|
1256
|
+
path.setAttribute("fill", "none");
|
|
1257
|
+
path.setAttribute("stroke", options.stroke);
|
|
1258
|
+
path.setAttribute("stroke-width", String(options.strokeWidth));
|
|
1259
|
+
path.setAttribute("stroke-linecap", "round");
|
|
1260
|
+
path.setAttribute("stroke-linejoin", "round");
|
|
1261
|
+
path.setAttribute("opacity", String(def.style.opacity));
|
|
1262
|
+
if (options.includeDash && def.style.pattern !== "solid") {
|
|
1263
|
+
const dash = def.style.dash ?? DEFAULT_CONNECTOR_DASH[def.style.pattern];
|
|
1264
|
+
path.setAttribute("stroke-dasharray", dash.join(" "));
|
|
1265
|
+
} else {
|
|
1266
|
+
path.setAttribute("stroke-dasharray", "none");
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
function routePath(route, layout, radius) {
|
|
1270
|
+
return roundedPath(
|
|
1271
|
+
route.map(([x, y]) => projectGridPoint(x, y, layout)),
|
|
1272
|
+
radius
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
function appendEndpoint(group, def, kind, layout) {
|
|
1276
|
+
const endpoint = def[kind];
|
|
1277
|
+
if (endpoint === "none" || def.route.length < 2) return void 0;
|
|
1278
|
+
const node = createEndpointNode(endpoint, def, kind, layout);
|
|
1279
|
+
node.classList.add(`iso-connector-${kind}`);
|
|
1280
|
+
group.appendChild(node);
|
|
1281
|
+
return node;
|
|
1282
|
+
}
|
|
1283
|
+
function createEndpointNode(endpoint, def, kind, layout) {
|
|
1284
|
+
switch (endpoint) {
|
|
1285
|
+
case "arrow":
|
|
1286
|
+
return createArrowEndpoint(def, kind, layout);
|
|
1287
|
+
case "dot":
|
|
1288
|
+
return createCircleEndpoint(def, kind, layout, true);
|
|
1289
|
+
case "circle":
|
|
1290
|
+
return createCircleEndpoint(def, kind, layout, false);
|
|
1291
|
+
case "diamond":
|
|
1292
|
+
return createDiamondEndpoint(def, kind, layout);
|
|
1293
|
+
case "bar":
|
|
1294
|
+
return createBarEndpoint(def, kind, layout);
|
|
1295
|
+
case "none":
|
|
1296
|
+
throw new RenderError("CONNECTOR_ENDPOINT_NONE", "Cannot create geometry for endpoint none");
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
function createArrowEndpoint(def, kind, layout) {
|
|
1300
|
+
const tip = endpointPoint(def, kind);
|
|
1301
|
+
const direction = endpointDirection(def, kind);
|
|
1302
|
+
const perpendicular = [-direction[1], direction[0]];
|
|
1303
|
+
const base = [tip[0] - direction[0] * ARROW_LENGTH_GRID, tip[1] - direction[1] * ARROW_LENGTH_GRID];
|
|
1304
|
+
const halfWidth = ARROW_WIDTH_GRID / 2;
|
|
1305
|
+
const points = [
|
|
1306
|
+
tip,
|
|
1307
|
+
[base[0] + perpendicular[0] * halfWidth, base[1] + perpendicular[1] * halfWidth],
|
|
1308
|
+
[base[0] - perpendicular[0] * halfWidth, base[1] - perpendicular[1] * halfWidth]
|
|
1309
|
+
].map((point) => projectGridPoint(point[0], point[1], layout));
|
|
1310
|
+
const polygon = document.createElementNS(NS, "polygon");
|
|
1311
|
+
polygon.setAttribute("points", points.map(pointToString).join(" "));
|
|
1312
|
+
polygon.setAttribute("fill", def.style.stroke);
|
|
1313
|
+
polygon.setAttribute("opacity", String(def.style.opacity));
|
|
1314
|
+
return polygon;
|
|
1315
|
+
}
|
|
1316
|
+
function createCircleEndpoint(def, kind, layout, filled) {
|
|
1317
|
+
const point = endpointPoint(def, kind);
|
|
1318
|
+
const projected = projectGridPoint(point[0], point[1], layout);
|
|
1319
|
+
const circle = document.createElementNS(NS, "circle");
|
|
1320
|
+
circle.setAttribute("cx", String(projected.x));
|
|
1321
|
+
circle.setAttribute("cy", String(projected.y));
|
|
1322
|
+
circle.setAttribute("r", String(ENDPOINT_RADIUS_GRID * layout.cellSize));
|
|
1323
|
+
circle.setAttribute("stroke", def.style.stroke);
|
|
1324
|
+
circle.setAttribute("stroke-width", String(Math.max(1, def.style.strokeWidth)));
|
|
1325
|
+
circle.setAttribute("opacity", String(def.style.opacity));
|
|
1326
|
+
circle.setAttribute("fill", filled ? def.style.stroke : "none");
|
|
1327
|
+
return circle;
|
|
1328
|
+
}
|
|
1329
|
+
function createDiamondEndpoint(def, kind, layout) {
|
|
1330
|
+
const center = endpointPoint(def, kind);
|
|
1331
|
+
const radius = ENDPOINT_RADIUS_GRID;
|
|
1332
|
+
const points = [
|
|
1333
|
+
[center[0], center[1] - radius],
|
|
1334
|
+
[center[0] + radius, center[1]],
|
|
1335
|
+
[center[0], center[1] + radius],
|
|
1336
|
+
[center[0] - radius, center[1]]
|
|
1337
|
+
];
|
|
1338
|
+
const polygon = document.createElementNS(NS, "polygon");
|
|
1339
|
+
polygon.setAttribute(
|
|
1340
|
+
"points",
|
|
1341
|
+
points.map((point) => projectGridPoint(point[0], point[1], layout)).map(pointToString).join(" ")
|
|
1342
|
+
);
|
|
1343
|
+
polygon.setAttribute("fill", def.style.stroke);
|
|
1344
|
+
polygon.setAttribute("opacity", String(def.style.opacity));
|
|
1345
|
+
return polygon;
|
|
1346
|
+
}
|
|
1347
|
+
function createBarEndpoint(def, kind, layout) {
|
|
1348
|
+
const center = endpointPoint(def, kind);
|
|
1349
|
+
const direction = endpointDirection(def, kind);
|
|
1350
|
+
const perpendicular = [-direction[1], direction[0]];
|
|
1351
|
+
const half = BAR_WIDTH_GRID / 2;
|
|
1352
|
+
const a = projectGridPoint(center[0] + perpendicular[0] * half, center[1] + perpendicular[1] * half, layout);
|
|
1353
|
+
const b = projectGridPoint(center[0] - perpendicular[0] * half, center[1] - perpendicular[1] * half, layout);
|
|
1354
|
+
const line = document.createElementNS(NS, "line");
|
|
1355
|
+
line.setAttribute("x1", String(a.x));
|
|
1356
|
+
line.setAttribute("y1", String(a.y));
|
|
1357
|
+
line.setAttribute("x2", String(b.x));
|
|
1358
|
+
line.setAttribute("y2", String(b.y));
|
|
1359
|
+
line.setAttribute("stroke", def.style.stroke);
|
|
1360
|
+
line.setAttribute("stroke-width", String(Math.max(1, def.style.strokeWidth)));
|
|
1361
|
+
line.setAttribute("stroke-linecap", "round");
|
|
1362
|
+
line.setAttribute("opacity", String(def.style.opacity));
|
|
1363
|
+
return line;
|
|
1364
|
+
}
|
|
1365
|
+
function endpointPoint(def, kind) {
|
|
1366
|
+
return kind === "start" ? def.route[0] : def.route[def.route.length - 1];
|
|
1367
|
+
}
|
|
1368
|
+
function endpointDirection(def, kind) {
|
|
1369
|
+
const point = kind === "start" ? vectorBetween(def.route[0], def.route[1]) : vectorBetween(def.route[def.route.length - 2], def.route[def.route.length - 1]);
|
|
1370
|
+
const effective = def.direction === "reverse" ? [-point[0], -point[1]] : point;
|
|
1371
|
+
return normalizeVector(effective);
|
|
1372
|
+
}
|
|
1373
|
+
function vectorBetween(start, end) {
|
|
1374
|
+
return [end[0] - start[0], end[1] - start[1]];
|
|
1375
|
+
}
|
|
1376
|
+
function normalizeVector(vector) {
|
|
1377
|
+
const length = Math.hypot(vector[0], vector[1]);
|
|
1378
|
+
if (length === 0) return [1, 0];
|
|
1379
|
+
return [vector[0] / length, vector[1] / length];
|
|
1380
|
+
}
|
|
1381
|
+
function applyElementTransform(node, def, layout) {
|
|
1382
|
+
const screen = projectToScreen(
|
|
1383
|
+
def.pos[0] + def.size,
|
|
1384
|
+
def.pos[1] + def.size,
|
|
1385
|
+
layout.cellSize,
|
|
1386
|
+
layout.selectedBounds.minX,
|
|
1387
|
+
layout.selectedBounds.minY,
|
|
1388
|
+
layout.padding.x,
|
|
1389
|
+
layout.padding.y
|
|
1390
|
+
);
|
|
1391
|
+
const visualSize = calculateVisualSize(def.size, layout.cellSize);
|
|
1392
|
+
const scale = visualSize / layout.cellSize;
|
|
1393
|
+
node.setAttribute("transform", `translate(${screen.screenX} ${screen.screenY}) scale(${scale})`);
|
|
1394
|
+
}
|
|
1395
|
+
function applyAmbientClasses(state, ambient) {
|
|
1396
|
+
const next = new Set((ambient ?? []).map((item) => item.name));
|
|
1397
|
+
for (const name of state.ambient) {
|
|
1398
|
+
if (!next.has(name)) state.node.classList.remove(`iso-ambient-${name}`);
|
|
1399
|
+
}
|
|
1400
|
+
for (const name of next) {
|
|
1401
|
+
if (!state.ambient.has(name)) state.node.classList.add(`iso-ambient-${name}`);
|
|
1402
|
+
}
|
|
1403
|
+
state.ambient = next;
|
|
1404
|
+
}
|
|
1405
|
+
function applyConnectorAmbientClasses(state, ambient) {
|
|
1406
|
+
const next = new Set((ambient ?? []).map((item) => item.name));
|
|
1407
|
+
for (const name of state.ambient) {
|
|
1408
|
+
if (!next.has(name)) state.shaft.classList.remove(`iso-ambient-${name}`);
|
|
1409
|
+
}
|
|
1410
|
+
for (const name of next) {
|
|
1411
|
+
state.shaft.classList.add(`iso-ambient-${name}`);
|
|
1412
|
+
}
|
|
1413
|
+
state.ambient = next;
|
|
1414
|
+
}
|
|
1415
|
+
function animateElement(node, keyframeName, type = "enter") {
|
|
1416
|
+
node.style.opacity = "1";
|
|
1417
|
+
node.style.animation = "none";
|
|
1418
|
+
node.getBoundingClientRect();
|
|
1419
|
+
const duration = type === "exit" ? "var(--iso-anim-duration-exit, 300ms)" : "var(--iso-anim-duration-enter, 400ms)";
|
|
1420
|
+
const easing = type === "exit" ? "var(--iso-anim-easing-exit, ease-in)" : "var(--iso-anim-easing-enter, ease-out)";
|
|
1421
|
+
node.style.animation = `${keyframeName} ${duration} ${easing} forwards`;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
export { AssetRegistryImpl as A, DEFAULT_CELL_SIZE as D, getResolvedViewBox as a, getElementState as b, getCurrentElementBounds as c, getConnectorState as d, updateElementTransforms as e, projectToScreen as f, getResolvedProjectionLayout as g, hideElementAfterExit as h, applyThemeToElement as i, buildSceneDOM as j, calculateTransform as k, calculateVisualSize as l, composeTheme as m, createAssetRegistry as n, createDefaultRegistry as o, projectToRaw as p, getGridAreaBounds as q, resolveTheme as r, applySceneViewBox as s, animateElement as t, unhideElementOnReadd as u };
|
|
1425
|
+
//# sourceMappingURL=rendering-engine-DLaM1XbU.js.map
|