@visualli/core 0.1.5 → 0.1.6
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/animations/index.cjs +146 -0
- package/dist/animations/index.cjs.map +1 -0
- package/dist/animations/index.d.cts +81 -0
- package/dist/animations/index.d.ts +81 -0
- package/dist/animations/index.js +35 -0
- package/dist/animations/index.js.map +1 -0
- package/dist/chunk-6NXADJK2.js +562 -0
- package/dist/chunk-6NXADJK2.js.map +1 -0
- package/dist/chunk-F36SMC3K.js +106 -0
- package/dist/chunk-F36SMC3K.js.map +1 -0
- package/dist/chunk-G5H3P4YZ.js +273 -0
- package/dist/chunk-G5H3P4YZ.js.map +1 -0
- package/dist/chunk-GQMFBYLK.js +81 -0
- package/dist/chunk-GQMFBYLK.js.map +1 -0
- package/dist/chunk-I75TMOE4.js +108 -0
- package/dist/chunk-I75TMOE4.js.map +1 -0
- package/dist/chunk-LDJRGT2Q.js +163 -0
- package/dist/chunk-LDJRGT2Q.js.map +1 -0
- package/dist/chunk-LI3BVD6H.js +98 -0
- package/dist/chunk-LI3BVD6H.js.map +1 -0
- package/dist/chunk-LJYSKSCE.js +95 -0
- package/dist/chunk-LJYSKSCE.js.map +1 -0
- package/dist/chunk-LNTJTDB2.js +349 -0
- package/dist/chunk-LNTJTDB2.js.map +1 -0
- package/dist/chunk-PDP5CVUL.js +139 -0
- package/dist/chunk-PDP5CVUL.js.map +1 -0
- package/dist/chunk-VLGR5PZX.js +1 -0
- package/dist/chunk-VLGR5PZX.js.map +1 -0
- package/dist/config/index.cjs +391 -0
- package/dist/config/index.cjs.map +1 -0
- package/dist/config/index.d.cts +77 -0
- package/dist/config/index.d.ts +77 -0
- package/dist/config/index.js +38 -0
- package/dist/config/index.js.map +1 -0
- package/dist/constants/index.cjs +642 -0
- package/dist/constants/index.cjs.map +1 -0
- package/dist/constants/index.d.cts +448 -0
- package/dist/constants/index.d.ts +448 -0
- package/dist/constants/index.js +183 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/document-B3hnNr-F.d.cts +73 -0
- package/dist/document-B3hnNr-F.d.ts +73 -0
- package/dist/index.cjs +32 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -1044
- package/dist/index.d.ts +15 -1044
- package/dist/index.js +179 -1747
- package/dist/index.js.map +1 -1
- package/dist/layout/index.cjs +210 -0
- package/dist/layout/index.cjs.map +1 -0
- package/dist/layout/index.d.cts +80 -0
- package/dist/layout/index.d.ts +80 -0
- package/dist/layout/index.js +25 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/mindmap-DWS0WZT_.d.cts +118 -0
- package/dist/mindmap-DWS0WZT_.d.ts +118 -0
- package/dist/parser/index.cjs +739 -0
- package/dist/parser/index.cjs.map +1 -0
- package/dist/parser/index.d.cts +87 -0
- package/dist/parser/index.d.ts +87 -0
- package/dist/parser/index.js +43 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/performance/index.cjs +167 -0
- package/dist/performance/index.cjs.map +1 -0
- package/dist/performance/index.d.cts +40 -0
- package/dist/performance/index.d.ts +40 -0
- package/dist/performance/index.js +12 -0
- package/dist/performance/index.js.map +1 -0
- package/dist/types/index.cjs +19 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.cts +8 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/viewport/index.cjs +131 -0
- package/dist/viewport/index.cjs.map +1 -0
- package/dist/viewport/index.d.cts +56 -0
- package/dist/viewport/index.d.ts +56 -0
- package/dist/viewport/index.js +26 -0
- package/dist/viewport/index.js.map +1 -0
- package/package.json +6 -1
- package/src/config/README.md +59 -0
- package/src/config/USAGE_EXAMPLES.md +285 -0
- package/src/config/index.ts +7 -0
- package/src/index.ts +1 -2
package/dist/index.js
CHANGED
|
@@ -1,1424 +1,182 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
constructor(message, lineNumber) {
|
|
181
|
-
super(message);
|
|
182
|
-
this.lineNumber = lineNumber;
|
|
183
|
-
this.name = "VisualliParseError";
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
function parseVisualliFile(content) {
|
|
187
|
-
const lines = content.trim().split("\n");
|
|
188
|
-
const doc = {
|
|
189
|
-
meta: null,
|
|
190
|
-
layers: /* @__PURE__ */ new Map(),
|
|
191
|
-
layersByLevel: /* @__PURE__ */ new Map(),
|
|
192
|
-
rootLayer: null
|
|
193
|
-
};
|
|
194
|
-
let lineNumber = 0;
|
|
195
|
-
for (const line of lines) {
|
|
196
|
-
lineNumber++;
|
|
197
|
-
if (!line.trim()) continue;
|
|
198
|
-
let obj;
|
|
199
|
-
try {
|
|
200
|
-
obj = JSON.parse(line);
|
|
201
|
-
} catch (err) {
|
|
202
|
-
throw new VisualliParseError(
|
|
203
|
-
`Failed to parse JSON at line ${lineNumber}: ${err}`,
|
|
204
|
-
lineNumber
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
if (!obj["type"]) {
|
|
208
|
-
throw new VisualliParseError(
|
|
209
|
-
`Missing 'type' field at line ${lineNumber}`,
|
|
210
|
-
lineNumber
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
switch (obj["type"]) {
|
|
214
|
-
case "meta":
|
|
215
|
-
doc.meta = obj;
|
|
216
|
-
break;
|
|
217
|
-
case "layer": {
|
|
218
|
-
const schemaLayer = obj;
|
|
219
|
-
const layer = toVisualliLayer(schemaLayer);
|
|
220
|
-
doc.layers.set(layer.id, layer);
|
|
221
|
-
if (!doc.layersByLevel.has(layer.level)) {
|
|
222
|
-
doc.layersByLevel.set(layer.level, []);
|
|
223
|
-
}
|
|
224
|
-
doc.layersByLevel.get(layer.level).push(layer);
|
|
225
|
-
if (layer.level === 0) {
|
|
226
|
-
doc.rootLayer = layer;
|
|
227
|
-
}
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
default:
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
if (!doc.meta) throw new VisualliParseError("Missing required meta section");
|
|
235
|
-
if (!doc.rootLayer) throw new VisualliParseError("Missing root layer (level 0)");
|
|
236
|
-
return doc;
|
|
237
|
-
}
|
|
238
|
-
async function fetchAndParseVisualli(url) {
|
|
239
|
-
const response = await fetch(url);
|
|
240
|
-
if (!response.ok) {
|
|
241
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
242
|
-
}
|
|
243
|
-
return parseVisualliFile(await response.text());
|
|
244
|
-
}
|
|
245
|
-
function parseVisualliFromMongoDB(visualliJsonl) {
|
|
246
|
-
if (!visualliJsonl || typeof visualliJsonl !== "string") {
|
|
247
|
-
throw new VisualliParseError("Invalid visualli data: expected a JSONL string");
|
|
248
|
-
}
|
|
249
|
-
const trimmed = visualliJsonl.trim();
|
|
250
|
-
if (!trimmed) throw new VisualliParseError("Empty visualli data from MongoDB");
|
|
251
|
-
return parseVisualliFile(trimmed);
|
|
252
|
-
}
|
|
253
|
-
function loadVisualliFileFromFile(file) {
|
|
254
|
-
return new Promise((resolve, reject) => {
|
|
255
|
-
const reader = new FileReader();
|
|
256
|
-
reader.onload = (e) => {
|
|
257
|
-
try {
|
|
258
|
-
resolve(parseVisualliFile(e.target?.result));
|
|
259
|
-
} catch (err) {
|
|
260
|
-
reject(err);
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
reader.onerror = () => reject(new Error("Failed to read file"));
|
|
264
|
-
reader.readAsText(file);
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
function getChildLayers(doc, nodeId) {
|
|
268
|
-
const result = [];
|
|
269
|
-
for (const layer of doc.layers.values()) {
|
|
270
|
-
if (layer.parentNodeId === nodeId) result.push(layer);
|
|
271
|
-
}
|
|
272
|
-
return result;
|
|
273
|
-
}
|
|
274
|
-
function countLayersBeneath(doc, nodeId, visited = /* @__PURE__ */ new Set()) {
|
|
275
|
-
if (visited.has(nodeId)) return 0;
|
|
276
|
-
visited.add(nodeId);
|
|
277
|
-
const children = getChildLayers(doc, nodeId);
|
|
278
|
-
if (children.length === 0) return 0;
|
|
279
|
-
let maxDepth = 0;
|
|
280
|
-
for (const layer of children) {
|
|
281
|
-
let depth = 1;
|
|
282
|
-
for (const node of layer.nodes) {
|
|
283
|
-
depth = Math.max(depth, 1 + countLayersBeneath(doc, node.id, visited));
|
|
284
|
-
}
|
|
285
|
-
maxDepth = Math.max(maxDepth, depth);
|
|
286
|
-
}
|
|
287
|
-
return maxDepth;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// src/parser/visualliConverter.ts
|
|
291
|
-
function doNodesOverlap(n1, n2, padding = 20) {
|
|
292
|
-
return !(n1.x + n1.width / 2 + padding < n2.x - n2.width / 2 - padding || n1.x - n1.width / 2 - padding > n2.x + n2.width / 2 + padding || n1.y + n1.height / 2 + padding < n2.y - n2.height / 2 - padding || n1.y - n1.height / 2 - padding > n2.y + n2.height / 2 + padding);
|
|
293
|
-
}
|
|
294
|
-
function resolveNodeOverlaps(nodes, maxIterations = 10) {
|
|
295
|
-
const padding = 150;
|
|
296
|
-
for (let iter = 0; iter < maxIterations; iter++) {
|
|
297
|
-
let any = false;
|
|
298
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
299
|
-
for (let j = i + 1; j < nodes.length; j++) {
|
|
300
|
-
const n1 = nodes[i];
|
|
301
|
-
const n2 = nodes[j];
|
|
302
|
-
if (!doNodesOverlap(n1, n2, padding)) continue;
|
|
303
|
-
any = true;
|
|
304
|
-
const dx = n2.x - n1.x;
|
|
305
|
-
const dy = n2.y - n1.y;
|
|
306
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
307
|
-
if (dist < 1) {
|
|
308
|
-
n2.x += n2.width / 2 + padding;
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
311
|
-
const minDist = (n1.width + n2.width) / 2 + padding;
|
|
312
|
-
if (dist < minDist) {
|
|
313
|
-
const push = (minDist - dist) / 2;
|
|
314
|
-
n1.x -= dx / dist * push;
|
|
315
|
-
n1.y -= dy / dist * push;
|
|
316
|
-
n2.x += dx / dist * push;
|
|
317
|
-
n2.y += dy / dist * push;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
if (!any) break;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
var COLOR_PALETTE = [
|
|
325
|
-
"#12C7D3",
|
|
326
|
-
"#325E8C",
|
|
327
|
-
"#8A70A6",
|
|
328
|
-
"#F54A57",
|
|
329
|
-
"#FF6C4D",
|
|
330
|
-
"#F28C16",
|
|
331
|
-
"#FFD347",
|
|
332
|
-
"#12C7D3",
|
|
333
|
-
"#7F7F7F",
|
|
334
|
-
"#8D8D8D",
|
|
335
|
-
"#12C7D3"
|
|
336
|
-
];
|
|
337
|
-
function getRandomColorForNode(nodeId) {
|
|
338
|
-
let hash = 0;
|
|
339
|
-
for (let i = 0; i < nodeId.length; i++) {
|
|
340
|
-
hash = nodeId.charCodeAt(i) + ((hash << 5) - hash);
|
|
341
|
-
}
|
|
342
|
-
const index = Math.abs(hash) % COLOR_PALETTE.length;
|
|
343
|
-
return COLOR_PALETTE[index];
|
|
344
|
-
}
|
|
345
|
-
function applyFormation(nodes, formation) {
|
|
346
|
-
if (nodes.length === 0) return;
|
|
347
|
-
if (nodes.length === 1) {
|
|
348
|
-
nodes[0].x = 0;
|
|
349
|
-
nodes[0].y = 0;
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
if (formation === "linear-horizontal" || formation === "linear") {
|
|
353
|
-
applyLinearHorizontalLayout(nodes, { centerX: 0, centerY: 0 });
|
|
354
|
-
} else if (formation === "linear-vertical") {
|
|
355
|
-
applyLinearVerticalLayout(nodes, { centerX: 0, centerY: 0 });
|
|
356
|
-
} else {
|
|
357
|
-
const r = Math.max(250, nodes.length * 70);
|
|
358
|
-
const step = 2 * Math.PI / nodes.length;
|
|
359
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
360
|
-
nodes[i].x = r * Math.cos(i * step);
|
|
361
|
-
nodes[i].y = r * Math.sin(i * step);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
function containerBBox(nodes, padding) {
|
|
366
|
-
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
367
|
-
for (const n of nodes) {
|
|
368
|
-
minX = Math.min(minX, n.x - n.width / 2);
|
|
369
|
-
maxX = Math.max(maxX, n.x + n.width / 2);
|
|
370
|
-
minY = Math.min(minY, n.y - n.height / 2);
|
|
371
|
-
maxY = Math.max(maxY, n.y + n.height / 2);
|
|
372
|
-
}
|
|
373
|
-
return { width: maxX - minX + padding * 2, height: maxY - minY + padding * 2 };
|
|
374
|
-
}
|
|
375
|
-
function proxyLinearH(proxies, gap = 180) {
|
|
376
|
-
const total = proxies.reduce((s, p) => s + p.width, 0) + gap * (proxies.length - 1);
|
|
377
|
-
let x = -total / 2;
|
|
378
|
-
for (const p of proxies) {
|
|
379
|
-
p.x = x + p.width / 2;
|
|
380
|
-
p.y = 0;
|
|
381
|
-
x += p.width + gap;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
function proxyLinearV(proxies, gap = 180) {
|
|
385
|
-
const total = proxies.reduce((s, p) => s + p.height, 0) + gap * (proxies.length - 1);
|
|
386
|
-
let y = -total / 2;
|
|
387
|
-
for (const p of proxies) {
|
|
388
|
-
p.x = 0;
|
|
389
|
-
p.y = y + p.height / 2;
|
|
390
|
-
y += p.height + gap;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
function proxyRadial(proxies, radius = 500) {
|
|
394
|
-
if (proxies.length === 1) {
|
|
395
|
-
proxies[0].x = 0;
|
|
396
|
-
proxies[0].y = 0;
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
const startAngle = proxies.length === 2 ? 0 : -Math.PI / 2;
|
|
400
|
-
const step = 2 * Math.PI / proxies.length;
|
|
401
|
-
for (let i = 0; i < proxies.length; i++) {
|
|
402
|
-
const angle = startAngle + i * step;
|
|
403
|
-
proxies[i].x = radius * Math.cos(angle);
|
|
404
|
-
proxies[i].y = radius * Math.sin(angle);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
function calculateNodeWidth(title) {
|
|
408
|
-
return Math.max(200, title.length * 8 + 40);
|
|
409
|
-
}
|
|
410
|
-
function makeFlatNode(nodeId, label, summary, layer, color, branchCount, x = 0, y = 0) {
|
|
411
|
-
return {
|
|
412
|
-
id: nodeId,
|
|
413
|
-
parentId: layer.parentNodeId ?? null,
|
|
414
|
-
x,
|
|
415
|
-
y,
|
|
416
|
-
level: layer.level,
|
|
417
|
-
title: label,
|
|
418
|
-
description: summary,
|
|
419
|
-
color,
|
|
420
|
-
width: calculateNodeWidth(label),
|
|
421
|
-
height: 80,
|
|
422
|
-
isExpanded: branchCount > 0,
|
|
423
|
-
branchCount,
|
|
424
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
425
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
function convertLayerWithContainers(layer, doc) {
|
|
429
|
-
const PADDING = 80;
|
|
430
|
-
const flatNodes = [];
|
|
431
|
-
for (const node of layer.nodes) {
|
|
432
|
-
const label = Array.isArray(node.data.label) ? node.data.label.join(" ") : node.data.label || "Untitled";
|
|
433
|
-
const branchCount = countLayersBeneath(doc, node.id);
|
|
434
|
-
flatNodes.push(
|
|
435
|
-
makeFlatNode(
|
|
436
|
-
node.id,
|
|
437
|
-
label,
|
|
438
|
-
node.data.summary || "",
|
|
439
|
-
layer,
|
|
440
|
-
node.data.color || getRandomColorForNode(node.id),
|
|
441
|
-
branchCount
|
|
442
|
-
)
|
|
443
|
-
);
|
|
444
|
-
}
|
|
445
|
-
const byId = new Map(flatNodes.map((n) => [n.id, n]));
|
|
446
|
-
const containerNodeIds = /* @__PURE__ */ new Set();
|
|
447
|
-
const containerGroups = /* @__PURE__ */ new Map();
|
|
448
|
-
for (const container of layer.containers) {
|
|
449
|
-
const group = container.nodes.map((id) => byId.get(id)).filter((n) => !!n);
|
|
450
|
-
if (!group.length) continue;
|
|
451
|
-
container.nodes.forEach((id) => containerNodeIds.add(id));
|
|
452
|
-
const formation = container.data?.["formation"] ?? "radial";
|
|
453
|
-
applyFormation(group, formation);
|
|
454
|
-
containerGroups.set(container.id, group);
|
|
455
|
-
}
|
|
456
|
-
const proxies = [];
|
|
457
|
-
for (const node of layer.nodes) {
|
|
458
|
-
if (!containerNodeIds.has(node.id)) {
|
|
459
|
-
const nodeWidth = calculateNodeWidth(node.data.label);
|
|
460
|
-
proxies.push({ id: node.id, x: 0, y: 0, width: nodeWidth, height: 80 });
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
for (const container of layer.containers) {
|
|
464
|
-
const group = containerGroups.get(container.id);
|
|
465
|
-
if (!group?.length) continue;
|
|
466
|
-
const bbox = containerBBox(group, PADDING);
|
|
467
|
-
proxies.push({ id: `__c__${container.id}`, x: 0, y: 0, width: bbox.width, height: bbox.height });
|
|
468
|
-
}
|
|
469
|
-
const layout = layer.layout || "radial";
|
|
470
|
-
if (layout === "linear-horizontal") proxyLinearH(proxies, 180);
|
|
471
|
-
else if (layout === "linear-vertical") proxyLinearV(proxies, 180);
|
|
472
|
-
else proxyRadial(proxies, 500);
|
|
473
|
-
for (const proxy of proxies) {
|
|
474
|
-
if (proxy.id.startsWith("__c__")) {
|
|
475
|
-
const group = containerGroups.get(proxy.id.slice(5));
|
|
476
|
-
group?.forEach((n) => {
|
|
477
|
-
n.x += proxy.x;
|
|
478
|
-
n.y += proxy.y;
|
|
479
|
-
});
|
|
480
|
-
} else {
|
|
481
|
-
const fn = byId.get(proxy.id);
|
|
482
|
-
if (fn) {
|
|
483
|
-
fn.x = proxy.x;
|
|
484
|
-
fn.y = proxy.y;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
resolveNodeOverlaps(flatNodes);
|
|
489
|
-
return flatNodes;
|
|
490
|
-
}
|
|
491
|
-
function convertLayerToFlatNodes(layer, doc) {
|
|
492
|
-
if ((layer.containers ?? []).length > 0) {
|
|
493
|
-
return convertLayerWithContainers(layer, doc);
|
|
494
|
-
}
|
|
495
|
-
const flatNodes = [];
|
|
496
|
-
for (const node of layer.nodes) {
|
|
497
|
-
const label = Array.isArray(node.data.label) ? node.data.label.join(" ") : node.data.label || "Untitled";
|
|
498
|
-
const branchCount = countLayersBeneath(doc, node.id);
|
|
499
|
-
flatNodes.push(
|
|
500
|
-
makeFlatNode(
|
|
501
|
-
node.id,
|
|
502
|
-
label,
|
|
503
|
-
node.data.summary || "",
|
|
504
|
-
layer,
|
|
505
|
-
node.data.color || getRandomColorForNode(node.id),
|
|
506
|
-
branchCount,
|
|
507
|
-
0,
|
|
508
|
-
0
|
|
509
|
-
)
|
|
510
|
-
);
|
|
511
|
-
}
|
|
512
|
-
if (flatNodes.length > 0) {
|
|
513
|
-
const layout = layer.layout || "radial";
|
|
514
|
-
if (layout === "linear-horizontal") {
|
|
515
|
-
applyLinearHorizontalLayout(flatNodes, { centerX: 0, centerY: 0 });
|
|
516
|
-
} else if (layout === "linear-vertical") {
|
|
517
|
-
applyLinearVerticalLayout(flatNodes, { centerX: 0, centerY: 0 });
|
|
518
|
-
} else {
|
|
519
|
-
const pct = calculateOptimalRadiusPercentage(flatNodes.length, 2e3, 2e3, 200, 30);
|
|
520
|
-
applyCircularLayout(flatNodes, {
|
|
521
|
-
radiusPercentage: pct,
|
|
522
|
-
containerWidth: 2e3,
|
|
523
|
-
containerHeight: 2e3,
|
|
524
|
-
centerX: 0,
|
|
525
|
-
centerY: 0
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
resolveNodeOverlaps(flatNodes);
|
|
530
|
-
return flatNodes;
|
|
531
|
-
}
|
|
532
|
-
function convertVisualliToFlatNodes(doc) {
|
|
533
|
-
const map = /* @__PURE__ */ new Map();
|
|
534
|
-
for (const layer of doc.layers.values()) {
|
|
535
|
-
for (const node of convertLayerToFlatNodes(layer, doc)) {
|
|
536
|
-
map.set(node.id, node);
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
for (const node of map.values()) {
|
|
540
|
-
node.childrenIds = [];
|
|
541
|
-
for (const candidate of map.values()) {
|
|
542
|
-
if (candidate.parentId === node.id) node.childrenIds.push(candidate.id);
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
return map;
|
|
546
|
-
}
|
|
547
|
-
function getNodesForLayer(doc, layerId) {
|
|
548
|
-
const layer = doc.layers.get(layerId);
|
|
549
|
-
return layer ? convertLayerToFlatNodes(layer, doc) : [];
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// src/parser/mindmapUtils.ts
|
|
553
|
-
function flattenNodes(nodes) {
|
|
554
|
-
const result = [];
|
|
555
|
-
const traverse = (list) => {
|
|
556
|
-
for (const n of list) {
|
|
557
|
-
result.push(n);
|
|
558
|
-
if (n.children) traverse(n.children);
|
|
559
|
-
}
|
|
560
|
-
};
|
|
561
|
-
traverse(nodes);
|
|
562
|
-
return result;
|
|
563
|
-
}
|
|
564
|
-
function getVisibleNodes(nodes, zoom, focusedNode) {
|
|
565
|
-
const flat = flattenNodes(nodes);
|
|
566
|
-
if (focusedNode) {
|
|
567
|
-
const focused = flat.find((n) => n.id === focusedNode);
|
|
568
|
-
if (focused) {
|
|
569
|
-
return focused.children ? [focused, ...focused.children] : [focused];
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
if (zoom <= 0.7) return flat.filter((n) => n.level === 0);
|
|
573
|
-
const maxLevel = Math.floor((zoom - 0.7) / 0.05);
|
|
574
|
-
return flat.filter((n) => n.level <= maxLevel);
|
|
575
|
-
}
|
|
576
|
-
function getNodeConnections(nodes) {
|
|
577
|
-
const flat = flattenNodes(nodes);
|
|
578
|
-
const result = [];
|
|
579
|
-
for (const n of flat) {
|
|
580
|
-
if (!n.parent) continue;
|
|
581
|
-
const parent = flat.find((p) => p.id === n.parent);
|
|
582
|
-
if (parent) result.push({ from: parent, to: n, label: n.relationshipLabel });
|
|
583
|
-
}
|
|
584
|
-
return result;
|
|
585
|
-
}
|
|
586
|
-
function getTopLevelConnections(nodes, topLevelConnections) {
|
|
587
|
-
const flat = flattenNodes(nodes);
|
|
588
|
-
const result = [];
|
|
589
|
-
for (const conn of topLevelConnections) {
|
|
590
|
-
const from = flat.find((n) => n.id === conn.from);
|
|
591
|
-
const to = flat.find((n) => n.id === conn.to);
|
|
592
|
-
if (from && to) result.push({ from, to, label: conn.label ?? "" });
|
|
593
|
-
}
|
|
594
|
-
return result;
|
|
595
|
-
}
|
|
596
|
-
function calculateDistance(x1, y1, x2, y2) {
|
|
597
|
-
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
// src/constants/design.ts
|
|
601
|
-
var DS_COLORS = {
|
|
602
|
-
light: {
|
|
603
|
-
bgApp: "#F0EDE6",
|
|
604
|
-
bgSurface: "#FAF8F4",
|
|
605
|
-
bgInput: "#FFFFFF",
|
|
606
|
-
border: "#DDD9D0",
|
|
607
|
-
borderDivider: "#E8E4DC",
|
|
608
|
-
primary: "#1B2D4F",
|
|
609
|
-
primaryHover: "#243B68",
|
|
610
|
-
textPrimary: "#1A1A18",
|
|
611
|
-
textSecondary: "#6B6860",
|
|
612
|
-
textMuted: "#747270",
|
|
613
|
-
textOnPrimary: "#FAF8F4",
|
|
614
|
-
hoverItem: "rgba(27,45,79,0.07)",
|
|
615
|
-
focusRing: "rgba(27,45,79,0.40)",
|
|
616
|
-
btnMuted: "#8E8C88"
|
|
617
|
-
},
|
|
618
|
-
dark: {
|
|
619
|
-
bgApp: "#141412",
|
|
620
|
-
bgSurface: "#1C1C1A",
|
|
621
|
-
bgInput: "#262622",
|
|
622
|
-
border: "#333330",
|
|
623
|
-
borderDivider: "#2A2A28",
|
|
624
|
-
primary: "#BB532D",
|
|
625
|
-
primaryHover: "#CC6440",
|
|
626
|
-
textPrimary: "#F0EDE6",
|
|
627
|
-
textSecondary: "#B0ABA3",
|
|
628
|
-
textMuted: "#8E8C88",
|
|
629
|
-
textOnPrimary: "#FAF8F4",
|
|
630
|
-
hoverItem: "rgba(198,94,56,0.12)",
|
|
631
|
-
focusRing: "rgba(198,94,56,0.50)",
|
|
632
|
-
btnMuted: "#4A4845"
|
|
633
|
-
}
|
|
634
|
-
};
|
|
635
|
-
var DS_TYPOGRAPHY = {
|
|
636
|
-
fontDisplay: "'Nunito', sans-serif",
|
|
637
|
-
fontBody: "'Nunito Sans', sans-serif",
|
|
638
|
-
logo: { size: "20px", weight: 800, letterSpacing: "0.04em" },
|
|
639
|
-
heading: { size: "16px", weight: 700, letterSpacing: "-0.2px" },
|
|
640
|
-
cta: { size: "11px", weight: 800, letterSpacing: "0.12em", transform: "uppercase" },
|
|
641
|
-
body: { size: "13px", weight: 400 },
|
|
642
|
-
input: { size: "13px", weight: 300, style: "italic" },
|
|
643
|
-
search: { size: "12px", weight: 400 },
|
|
644
|
-
username: { size: "13px", weight: 600 },
|
|
645
|
-
avatar: { size: "11px", weight: 700 },
|
|
646
|
-
footer: { size: "12px", weight: 400 },
|
|
647
|
-
empty: { size: "11px", weight: 300, style: "italic" }
|
|
648
|
-
};
|
|
649
|
-
var DS_RADII = {
|
|
650
|
-
sidebar: 16,
|
|
651
|
-
input: 8,
|
|
652
|
-
cta: 7,
|
|
653
|
-
item: 6,
|
|
654
|
-
swatch: 10
|
|
655
|
-
};
|
|
656
|
-
var BRAND_COLORS = {
|
|
657
|
-
primary: {
|
|
658
|
-
50: "#EFF6FF",
|
|
659
|
-
100: "#DBEAFE",
|
|
660
|
-
200: "#BFDBFE",
|
|
661
|
-
300: "#93C5FD",
|
|
662
|
-
400: "#60A5FA",
|
|
663
|
-
500: "#3B82F6",
|
|
664
|
-
600: "#2563EB",
|
|
665
|
-
700: "#1D4ED8",
|
|
666
|
-
800: "#1E40AF",
|
|
667
|
-
900: "#1E3A8A"
|
|
668
|
-
},
|
|
669
|
-
secondary: {
|
|
670
|
-
50: "#F0FDF4",
|
|
671
|
-
100: "#DCFCE7",
|
|
672
|
-
200: "#BBF7D0",
|
|
673
|
-
300: "#86EFAC",
|
|
674
|
-
400: "#4ADE80",
|
|
675
|
-
500: "#10B981",
|
|
676
|
-
600: "#059669",
|
|
677
|
-
700: "#047857",
|
|
678
|
-
800: "#065F46",
|
|
679
|
-
900: "#064E3B"
|
|
680
|
-
},
|
|
681
|
-
accent: {
|
|
682
|
-
purple: "#8B5CF6",
|
|
683
|
-
cyan: "#06B6D4",
|
|
684
|
-
sky: "#0EA5E9",
|
|
685
|
-
lime: "#84CC16",
|
|
686
|
-
amber: "#F59E0B",
|
|
687
|
-
red: "#EF4444"
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
var LEVEL_COLORS = {
|
|
691
|
-
level0: BRAND_COLORS.primary[500],
|
|
692
|
-
level1: BRAND_COLORS.primary[400],
|
|
693
|
-
level2: BRAND_COLORS.primary[300],
|
|
694
|
-
level3: BRAND_COLORS.primary[200],
|
|
695
|
-
level4: BRAND_COLORS.primary[300],
|
|
696
|
-
level5: BRAND_COLORS.primary[400],
|
|
697
|
-
level6: BRAND_COLORS.primary[500],
|
|
698
|
-
level7: BRAND_COLORS.primary[600],
|
|
699
|
-
level8: BRAND_COLORS.primary[700]
|
|
700
|
-
};
|
|
701
|
-
var LEVEL_COLOR_ARRAY = [
|
|
702
|
-
LEVEL_COLORS.level0,
|
|
703
|
-
LEVEL_COLORS.level1,
|
|
704
|
-
LEVEL_COLORS.level2,
|
|
705
|
-
LEVEL_COLORS.level3,
|
|
706
|
-
LEVEL_COLORS.level4,
|
|
707
|
-
LEVEL_COLORS.level5,
|
|
708
|
-
LEVEL_COLORS.level6,
|
|
709
|
-
LEVEL_COLORS.level7,
|
|
710
|
-
LEVEL_COLORS.level8
|
|
711
|
-
];
|
|
712
|
-
var PARENT_FALLBACK_COLORS = [
|
|
713
|
-
"#12C7D3",
|
|
714
|
-
"#325E8C",
|
|
715
|
-
"#8A70A6",
|
|
716
|
-
"#F54A57",
|
|
717
|
-
"#FF6C4D",
|
|
718
|
-
"#F28C16",
|
|
719
|
-
"#FFD347",
|
|
720
|
-
"#7F7F7F",
|
|
721
|
-
"#8D8D8D"
|
|
722
|
-
];
|
|
723
|
-
var SEMANTIC_COLORS = {
|
|
724
|
-
success: BRAND_COLORS.secondary[500],
|
|
725
|
-
error: BRAND_COLORS.accent.red,
|
|
726
|
-
warning: BRAND_COLORS.accent.amber,
|
|
727
|
-
info: BRAND_COLORS.primary[500]
|
|
728
|
-
};
|
|
729
|
-
var THEME_COLORS = {
|
|
730
|
-
light: {
|
|
731
|
-
background: { primary: "#FAF8F4", secondary: "#F0EDE6", tertiary: "#FFFFFF" },
|
|
732
|
-
text: { primary: "#1A1A18", secondary: "#6B6860", tertiary: "#747270" },
|
|
733
|
-
border: { primary: "#DDD9D0", secondary: "#E8E4DC" }
|
|
734
|
-
},
|
|
735
|
-
dark: {
|
|
736
|
-
background: { primary: "#1C1C1A", secondary: "#141412", tertiary: "#262622" },
|
|
737
|
-
text: { primary: "#F0EDE6", secondary: "#B0ABA3", tertiary: "#8E8C88" },
|
|
738
|
-
border: { primary: "#333330", secondary: "#2A2A28" }
|
|
739
|
-
}
|
|
740
|
-
};
|
|
741
|
-
var CANVAS_COLORS = {
|
|
742
|
-
node: {
|
|
743
|
-
border: "#FFFFFF",
|
|
744
|
-
titleColor: "#1e1b4b",
|
|
745
|
-
badgeBackground: "#FFC107",
|
|
746
|
-
badgeStroke: "#fcd34d"
|
|
747
|
-
}
|
|
748
|
-
};
|
|
749
|
-
var SPACING = {
|
|
750
|
-
xs: 4,
|
|
751
|
-
sm: 8,
|
|
752
|
-
md: 16,
|
|
753
|
-
lg: 24,
|
|
754
|
-
xl: 32,
|
|
755
|
-
"2xl": 48,
|
|
756
|
-
"3xl": 64,
|
|
757
|
-
"4xl": 96
|
|
758
|
-
};
|
|
759
|
-
var LAYOUT_SPACING = {
|
|
760
|
-
nodeSpacing: 200,
|
|
761
|
-
levelSpacing: 150,
|
|
762
|
-
containerPadding: 20,
|
|
763
|
-
gridSize: 50
|
|
764
|
-
};
|
|
765
|
-
var FONTS = {
|
|
766
|
-
primary: "'Inter', sans-serif",
|
|
767
|
-
secondary: "'Poppins', sans-serif",
|
|
768
|
-
mono: "'Roboto Mono', monospace"
|
|
769
|
-
};
|
|
770
|
-
var FONT_SIZES = {
|
|
771
|
-
xs: "0.75rem",
|
|
772
|
-
sm: "0.875rem",
|
|
773
|
-
base: "1rem",
|
|
774
|
-
lg: "1.125rem",
|
|
775
|
-
xl: "1.25rem",
|
|
776
|
-
"2xl": "1.5rem",
|
|
777
|
-
"3xl": "1.875rem",
|
|
778
|
-
"4xl": "2.25rem"
|
|
779
|
-
};
|
|
780
|
-
function getColorForLevel(level) {
|
|
781
|
-
return LEVEL_COLOR_ARRAY[level % LEVEL_COLOR_ARRAY.length];
|
|
782
|
-
}
|
|
783
|
-
function darkenHexColor(hex, amount = 0.22) {
|
|
784
|
-
if (!hex || !hex.startsWith("#")) return hex;
|
|
785
|
-
let r, g, b;
|
|
786
|
-
if (hex.length === 4) {
|
|
787
|
-
r = parseInt(hex[1] + hex[1], 16);
|
|
788
|
-
g = parseInt(hex[2] + hex[2], 16);
|
|
789
|
-
b = parseInt(hex[3] + hex[3], 16);
|
|
790
|
-
} else if (hex.length === 7) {
|
|
791
|
-
r = parseInt(hex.slice(1, 3), 16);
|
|
792
|
-
g = parseInt(hex.slice(3, 5), 16);
|
|
793
|
-
b = parseInt(hex.slice(5, 7), 16);
|
|
794
|
-
} else {
|
|
795
|
-
return hex;
|
|
796
|
-
}
|
|
797
|
-
if (isNaN(r) || isNaN(g) || isNaN(b)) return hex;
|
|
798
|
-
const rn = r / 255, gn = g / 255, bn = b / 255;
|
|
799
|
-
const cmax = Math.max(rn, gn, bn), cmin = Math.min(rn, gn, bn);
|
|
800
|
-
const d = cmax - cmin;
|
|
801
|
-
const l = (cmax + cmin) / 2;
|
|
802
|
-
const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));
|
|
803
|
-
let h = 0;
|
|
804
|
-
if (d !== 0) {
|
|
805
|
-
const seg = cmax === rn ? (gn - bn) / d : cmax === gn ? (bn - rn) / d + 2 : (rn - gn) / d + 4;
|
|
806
|
-
h = (seg * 60 + 360) % 360;
|
|
807
|
-
}
|
|
808
|
-
const newL = Math.max(0, l - amount);
|
|
809
|
-
const c2 = (1 - Math.abs(2 * newL - 1)) * s;
|
|
810
|
-
const x2 = c2 * (1 - Math.abs(h / 60 % 2 - 1));
|
|
811
|
-
const m2 = newL - c2 / 2;
|
|
812
|
-
let r1 = 0, g1 = 0, b1 = 0;
|
|
813
|
-
if (h < 60) {
|
|
814
|
-
r1 = c2;
|
|
815
|
-
g1 = x2;
|
|
816
|
-
b1 = 0;
|
|
817
|
-
} else if (h < 120) {
|
|
818
|
-
r1 = x2;
|
|
819
|
-
g1 = c2;
|
|
820
|
-
b1 = 0;
|
|
821
|
-
} else if (h < 180) {
|
|
822
|
-
r1 = 0;
|
|
823
|
-
g1 = c2;
|
|
824
|
-
b1 = x2;
|
|
825
|
-
} else if (h < 240) {
|
|
826
|
-
r1 = 0;
|
|
827
|
-
g1 = x2;
|
|
828
|
-
b1 = c2;
|
|
829
|
-
} else if (h < 300) {
|
|
830
|
-
r1 = x2;
|
|
831
|
-
g1 = 0;
|
|
832
|
-
b1 = c2;
|
|
833
|
-
} else {
|
|
834
|
-
r1 = c2;
|
|
835
|
-
g1 = 0;
|
|
836
|
-
b1 = x2;
|
|
837
|
-
}
|
|
838
|
-
const toHex = (v) => Math.round((v + m2) * 255).toString(16).padStart(2, "0");
|
|
839
|
-
return `#${toHex(r1)}${toHex(g1)}${toHex(b1)}`;
|
|
840
|
-
}
|
|
841
|
-
function getThemeBackground(isDark, variant = "primary") {
|
|
842
|
-
return isDark ? THEME_COLORS.dark.background[variant] : THEME_COLORS.light.background[variant];
|
|
843
|
-
}
|
|
844
|
-
function getThemeText(isDark, variant = "primary") {
|
|
845
|
-
return isDark ? THEME_COLORS.dark.text[variant] : THEME_COLORS.light.text[variant];
|
|
846
|
-
}
|
|
847
|
-
function getThemeBorder(isDark, variant = "primary") {
|
|
848
|
-
return isDark ? THEME_COLORS.dark.border[variant] : THEME_COLORS.light.border[variant];
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
// src/parser/configUtils.ts
|
|
852
|
-
function createMindMapConfig(nodes, topLevelConnections, title = "Untitled Mindmap") {
|
|
853
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
854
|
-
return {
|
|
855
|
-
metadata: {
|
|
856
|
-
title,
|
|
857
|
-
description: `Interactive mindmap with ${nodes.length} nodes`,
|
|
858
|
-
version: "1.0.0",
|
|
859
|
-
created: now,
|
|
860
|
-
lastModified: now
|
|
861
|
-
},
|
|
862
|
-
nodes,
|
|
863
|
-
topLevelConnections,
|
|
864
|
-
settings: {
|
|
865
|
-
defaultColors: {
|
|
866
|
-
level0: LEVEL_COLORS.level0,
|
|
867
|
-
level1: LEVEL_COLORS.level1,
|
|
868
|
-
level2: LEVEL_COLORS.level2,
|
|
869
|
-
level3: LEVEL_COLORS.level3
|
|
870
|
-
},
|
|
871
|
-
layout: {
|
|
872
|
-
nodeSpacing: LAYOUT_SPACING.nodeSpacing,
|
|
873
|
-
levelSpacing: LAYOUT_SPACING.levelSpacing
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
};
|
|
877
|
-
}
|
|
878
|
-
function generateId(prefix, level, index) {
|
|
879
|
-
return `${prefix}-l${level}-${index}`;
|
|
880
|
-
}
|
|
881
|
-
function generateLevelNodes(parentId, level, maxLevels, xOffset = 0, yOffset = 0) {
|
|
882
|
-
if (level >= maxLevels) return [];
|
|
883
|
-
const count = 5;
|
|
884
|
-
const levelSpacing = 200;
|
|
885
|
-
const nodeSpacing = 300;
|
|
886
|
-
const nodes = [];
|
|
887
|
-
for (let i = 0; i < count; i++) {
|
|
888
|
-
const nodeId = parentId ? generateId(`${parentId}-${i}`, level, i) : generateId("root", level, i);
|
|
889
|
-
const x = xOffset + (i - (count - 1) / 2) * nodeSpacing;
|
|
890
|
-
const y = yOffset + level * levelSpacing;
|
|
891
|
-
const node = {
|
|
892
|
-
id: nodeId,
|
|
893
|
-
title: `Level ${level} Node ${i + 1}`,
|
|
894
|
-
level,
|
|
895
|
-
x,
|
|
896
|
-
y,
|
|
897
|
-
color: getColorForLevel(level),
|
|
898
|
-
relationshipLabel: level > 0 ? "child" : void 0,
|
|
899
|
-
parent: parentId ?? void 0
|
|
900
|
-
};
|
|
901
|
-
const children = generateLevelNodes(nodeId, level + 1, maxLevels, x, y + levelSpacing);
|
|
902
|
-
if (children.length > 0) node.children = children;
|
|
903
|
-
nodes.push(node);
|
|
904
|
-
}
|
|
905
|
-
return nodes;
|
|
906
|
-
}
|
|
907
|
-
function generateSampleConfig(maxLevels = 9) {
|
|
908
|
-
const nodes = generateLevelNodes(null, 0, maxLevels, 0, 0);
|
|
909
|
-
const topLevelConnections = nodes.slice(0, -1).map((n, i) => ({
|
|
910
|
-
from: n.id,
|
|
911
|
-
to: nodes[i + 1].id,
|
|
912
|
-
label: "related to"
|
|
913
|
-
}));
|
|
914
|
-
return {
|
|
915
|
-
metadata: {
|
|
916
|
-
id: `mindmap-${Date.now()}`,
|
|
917
|
-
title: "Sample Mind Map",
|
|
918
|
-
description: "A sample mind map",
|
|
919
|
-
version: "1.0.0",
|
|
920
|
-
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
921
|
-
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
922
|
-
},
|
|
923
|
-
nodes,
|
|
924
|
-
topLevelConnections,
|
|
925
|
-
settings: {
|
|
926
|
-
defaultColors: {
|
|
927
|
-
level0: LEVEL_COLORS.level0,
|
|
928
|
-
level1: LEVEL_COLORS.level1,
|
|
929
|
-
level2: LEVEL_COLORS.level2,
|
|
930
|
-
level3: LEVEL_COLORS.level3,
|
|
931
|
-
level4: LEVEL_COLORS.level4,
|
|
932
|
-
level5: LEVEL_COLORS.level5,
|
|
933
|
-
level6: LEVEL_COLORS.level6,
|
|
934
|
-
level7: LEVEL_COLORS.level7,
|
|
935
|
-
level8: LEVEL_COLORS.level8
|
|
936
|
-
},
|
|
937
|
-
layout: {
|
|
938
|
-
nodeSpacing: LAYOUT_SPACING.nodeSpacing,
|
|
939
|
-
levelSpacing: LAYOUT_SPACING.levelSpacing
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
};
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
// src/constants/performanceConstants.ts
|
|
946
|
-
var FPS_TARGET = 60;
|
|
947
|
-
var FPS_WARNING_THRESHOLD = 45;
|
|
948
|
-
var FPS_CRITICAL_THRESHOLD = 30;
|
|
949
|
-
var TARGET_FRAME_TIME = 1e3 / FPS_TARGET;
|
|
950
|
-
var MAX_FRAME_TIME = 18;
|
|
951
|
-
var FPS_TARGETS = {
|
|
952
|
-
PAN_MIN: 30,
|
|
953
|
-
ZOOM_TARGET: 60,
|
|
954
|
-
WARNING_THRESHOLD: 20
|
|
955
|
-
};
|
|
956
|
-
var TIMING_THRESHOLDS = {
|
|
957
|
-
VIEWPORT_QUERY_MAX: 5,
|
|
958
|
-
SPATIAL_UPDATE_MAX: 10,
|
|
959
|
-
DRAG_RESPONSE_MAX: 16,
|
|
960
|
-
LOAD_5K_TARGET: 2e3,
|
|
961
|
-
LOAD_10K_TARGET: 3e3,
|
|
962
|
-
VIEWPORT_DEBOUNCE: 100,
|
|
963
|
-
SPATIAL_INDEX_BUILD: 50
|
|
964
|
-
};
|
|
965
|
-
var MEMORY_TARGET_MB = 500;
|
|
966
|
-
var MEMORY_WARNING_MB = 600;
|
|
967
|
-
var MEMORY_CRITICAL_MB = 800;
|
|
968
|
-
var MEMORY_LIMITS = {
|
|
969
|
-
MAX_10K_NODES: 500,
|
|
970
|
-
MAX_GROWTH_PERCENT: 20,
|
|
971
|
-
WARNING_THRESHOLD: 400
|
|
972
|
-
};
|
|
973
|
-
var VIEWPORT_MARGIN = 0.1;
|
|
974
|
-
var MAX_VISIBLE_NODES = 800;
|
|
975
|
-
var CULLING_QUERY_TIME_BUDGET = 5;
|
|
976
|
-
var RBUSH_MAX_ENTRIES = 16;
|
|
977
|
-
var SPATIAL_INDEX_BUILD_BUDGET = 50;
|
|
978
|
-
var NODE_MIN_WIDTH = 200;
|
|
979
|
-
var NODE_HEIGHT = 80;
|
|
980
|
-
var NODE_PADDING = 40;
|
|
981
|
-
var CHAR_WIDTH = 8;
|
|
982
|
-
var TITLE_MAX_LENGTH = 150;
|
|
983
|
-
var CORNER_RADIUS = 8;
|
|
984
|
-
var BORDER_WIDTH_NORMAL = 2;
|
|
985
|
-
var BORDER_WIDTH_SELECTED = 3;
|
|
986
|
-
var COLOR_SELECTED = "#1B2D4F";
|
|
987
|
-
var COLOR_BORDER_LIGHT = "#4A3728";
|
|
988
|
-
var COLOR_BORDER_DARK = "#FAF6F1";
|
|
989
|
-
var COLOR_DEFAULT_NODE = "#FAF6F1";
|
|
990
|
-
var ZOOM_MIN = 0.05;
|
|
991
|
-
var ZOOM_MAX = 5;
|
|
992
|
-
var ZOOM_DEFAULT = 1;
|
|
993
|
-
var ZOOM_STEP = 0.1;
|
|
994
|
-
var ZOOM_WHEEL_SENSITIVITY = 1e-3;
|
|
995
|
-
var ZOOM_NAV_IN_THRESHOLD = 2.7;
|
|
996
|
-
var ZOOM_NAV_OUT_THRESHOLD = 0.4;
|
|
997
|
-
var TEXT_LABEL_HIDE_BELOW_ZOOM = 0.3;
|
|
998
|
-
var QUALITY_HIGH = {
|
|
999
|
-
shadows: true,
|
|
1000
|
-
bezierCurves: true,
|
|
1001
|
-
animations: true,
|
|
1002
|
-
textQuality: "high",
|
|
1003
|
-
antialiasing: true
|
|
1004
|
-
};
|
|
1005
|
-
var QUALITY_MEDIUM = {
|
|
1006
|
-
shadows: false,
|
|
1007
|
-
bezierCurves: true,
|
|
1008
|
-
animations: true,
|
|
1009
|
-
textQuality: "medium",
|
|
1010
|
-
antialiasing: true
|
|
1011
|
-
};
|
|
1012
|
-
var QUALITY_LOW = {
|
|
1013
|
-
shadows: false,
|
|
1014
|
-
bezierCurves: false,
|
|
1015
|
-
animations: false,
|
|
1016
|
-
textQuality: "low",
|
|
1017
|
-
antialiasing: false
|
|
1018
|
-
};
|
|
1019
|
-
var FPS_SAMPLE_WINDOW = 60;
|
|
1020
|
-
var FPS_UPDATE_INTERVAL = 1e3;
|
|
1021
|
-
var MEMORY_CHECK_INTERVAL = 5e3;
|
|
1022
|
-
var PERFORMANCE_TOAST_COOLDOWN = 1e4;
|
|
1023
|
-
var FPS_DOWNGRADE_THRESHOLD = 45;
|
|
1024
|
-
var FPS_UPGRADE_THRESHOLD = 58;
|
|
1025
|
-
var FPS_STABILIZATION_FRAMES = 180;
|
|
1026
|
-
var DEFAULT_CANVAS_WIDTH = 1920;
|
|
1027
|
-
var DEFAULT_CANVAS_HEIGHT = 1080;
|
|
1028
|
-
var CLICK_THRESHOLD = 5;
|
|
1029
|
-
var DOUBLE_CLICK_DELAY = 300;
|
|
1030
|
-
var DRAG_START_DISTANCE = 10;
|
|
1031
|
-
var MAX_NODES = 2e4;
|
|
1032
|
-
var CIRCULAR_REFERENCE_MAX_DEPTH = 1e3;
|
|
1033
|
-
var RESIZE_DEBOUNCE = 300;
|
|
1034
|
-
var SCROLL_THROTTLE = 16;
|
|
1035
|
-
var SEARCH_DEBOUNCE = 500;
|
|
1036
|
-
var NODE_COUNT_THRESHOLDS = {
|
|
1037
|
-
SPATIAL_INDEX_MIN: 100,
|
|
1038
|
-
VIEWPORT_CULLING_MIN: 500,
|
|
1039
|
-
CANVAS_RENDERING_MIN: 2e3,
|
|
1040
|
-
DOM_RENDERING_MAX: 5e3
|
|
1041
|
-
};
|
|
1042
|
-
var VIEWPORT_CONFIG = {
|
|
1043
|
-
BUFFER_PERCENT: 0.2,
|
|
1044
|
-
MIN_VISIBLE_NODES: 10
|
|
1045
|
-
};
|
|
1046
|
-
|
|
1047
|
-
// src/constants/renderConfig.ts
|
|
1048
|
-
var DEFAULT_RENDER_CONFIG = {
|
|
1049
|
-
renderMode: "canvas",
|
|
1050
|
-
qualityLevel: "high",
|
|
1051
|
-
cullingEnabled: false,
|
|
1052
|
-
fpsTarget: FPS_TARGET,
|
|
1053
|
-
memoryLimit: MEMORY_TARGET_MB
|
|
1054
|
-
};
|
|
1055
|
-
var SIMPLIFIED_RENDER_CONFIG = {
|
|
1056
|
-
renderMode: "simplified",
|
|
1057
|
-
qualityLevel: "low",
|
|
1058
|
-
cullingEnabled: true,
|
|
1059
|
-
fpsTarget: 30,
|
|
1060
|
-
memoryLimit: 400
|
|
1061
|
-
};
|
|
1062
|
-
var QUALITY_SETTINGS = {
|
|
1063
|
-
high: QUALITY_HIGH,
|
|
1064
|
-
medium: QUALITY_MEDIUM,
|
|
1065
|
-
low: QUALITY_LOW
|
|
1066
|
-
};
|
|
1067
|
-
var FEATURE_FLAGS = {
|
|
1068
|
-
viewportCulling: true,
|
|
1069
|
-
spatialIndexing: true,
|
|
1070
|
-
shadows: true,
|
|
1071
|
-
bezierCurves: true,
|
|
1072
|
-
animations: true,
|
|
1073
|
-
branchBadges: true,
|
|
1074
|
-
autoQualityAdjustment: true,
|
|
1075
|
-
performanceMonitoring: true,
|
|
1076
|
-
performanceToasts: true,
|
|
1077
|
-
debugOverlay: false,
|
|
1078
|
-
showFPS: false,
|
|
1079
|
-
showMemory: false,
|
|
1080
|
-
showVisibleCount: false
|
|
1081
|
-
};
|
|
1082
|
-
var RENDER_MODES = {
|
|
1083
|
-
canvas: {
|
|
1084
|
-
name: "Canvas",
|
|
1085
|
-
description: "Full Konva canvas rendering with all features",
|
|
1086
|
-
features: { culling: true, shadows: true, bezierCurves: true, animations: true }
|
|
1087
|
-
},
|
|
1088
|
-
simplified: {
|
|
1089
|
-
name: "Simplified",
|
|
1090
|
-
description: "Reduced feature set for low-end devices",
|
|
1091
|
-
features: { culling: true, shadows: false, bezierCurves: false, animations: false }
|
|
1092
|
-
}
|
|
1093
|
-
};
|
|
1094
|
-
var QUALITY_LEVELS = {
|
|
1095
|
-
high: { name: "High", description: "All visual features enabled", targetFPS: 60, features: QUALITY_HIGH },
|
|
1096
|
-
medium: { name: "Medium", description: "Shadows disabled, other features enabled", targetFPS: 60, features: QUALITY_MEDIUM },
|
|
1097
|
-
low: { name: "Low", description: "Minimal visual features, max performance", targetFPS: 30, features: QUALITY_LOW }
|
|
1098
|
-
};
|
|
1099
|
-
function getOptimalQualityLevel(currentFPS, currentQuality) {
|
|
1100
|
-
if (currentFPS < 45 && currentQuality === "high") return "medium";
|
|
1101
|
-
if (currentFPS < 30 && currentQuality === "medium") return "low";
|
|
1102
|
-
if (currentFPS > 58 && currentQuality === "low") return "medium";
|
|
1103
|
-
if (currentFPS > 58 && currentQuality === "medium") return "high";
|
|
1104
|
-
return currentQuality;
|
|
1105
|
-
}
|
|
1106
|
-
function getRenderConfigForQuality(quality) {
|
|
1107
|
-
return { qualityLevel: quality, fpsTarget: QUALITY_LEVELS[quality].targetFPS };
|
|
1108
|
-
}
|
|
1109
|
-
function isFeatureEnabled(featureName, config) {
|
|
1110
|
-
if (!FEATURE_FLAGS[featureName]) return false;
|
|
1111
|
-
const qs = QUALITY_SETTINGS[config.qualityLevel];
|
|
1112
|
-
switch (featureName) {
|
|
1113
|
-
case "shadows":
|
|
1114
|
-
return qs.shadows;
|
|
1115
|
-
case "bezierCurves":
|
|
1116
|
-
return qs.bezierCurves;
|
|
1117
|
-
case "animations":
|
|
1118
|
-
return qs.animations;
|
|
1119
|
-
default:
|
|
1120
|
-
return FEATURE_FLAGS[featureName];
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
function getRecommendedRenderConfig() {
|
|
1124
|
-
if (typeof performance === "undefined" || !performance["memory"]) {
|
|
1125
|
-
return SIMPLIFIED_RENDER_CONFIG;
|
|
1126
|
-
}
|
|
1127
|
-
const memory = performance["memory"];
|
|
1128
|
-
if (memory?.["jsHeapSizeLimit"] && memory["jsHeapSizeLimit"] < 512 * 1024 * 1024) {
|
|
1129
|
-
return SIMPLIFIED_RENDER_CONFIG;
|
|
1130
|
-
}
|
|
1131
|
-
return DEFAULT_RENDER_CONFIG;
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
// src/viewport/viewportUtils.ts
|
|
1135
|
-
function calculateViewportBounds(viewport, canvasWidth = DEFAULT_CANVAS_WIDTH, canvasHeight = DEFAULT_CANVAS_HEIGHT) {
|
|
1136
|
-
const worldW = canvasWidth / viewport.zoomLevel;
|
|
1137
|
-
const worldH = canvasHeight / viewport.zoomLevel;
|
|
1138
|
-
const mx = worldW * VIEWPORT_MARGIN;
|
|
1139
|
-
const my = worldH * VIEWPORT_MARGIN;
|
|
1140
|
-
return {
|
|
1141
|
-
minX: viewport.centerX - worldW / 2 - mx,
|
|
1142
|
-
minY: viewport.centerY - worldH / 2 - my,
|
|
1143
|
-
maxX: viewport.centerX + worldW / 2 + mx,
|
|
1144
|
-
maxY: viewport.centerY + worldH / 2 + my
|
|
1145
|
-
};
|
|
1146
|
-
}
|
|
1147
|
-
function recalculateViewportBounds(viewport, canvasWidth = DEFAULT_CANVAS_WIDTH, canvasHeight = DEFAULT_CANVAS_HEIGHT) {
|
|
1148
|
-
return {
|
|
1149
|
-
...viewport,
|
|
1150
|
-
visibleBounds: calculateViewportBounds(viewport, canvasWidth, canvasHeight)
|
|
1151
|
-
};
|
|
1152
|
-
}
|
|
1153
|
-
function worldToScreen(worldX, worldY, viewport, canvasWidth = DEFAULT_CANVAS_WIDTH, canvasHeight = DEFAULT_CANVAS_HEIGHT) {
|
|
1154
|
-
return {
|
|
1155
|
-
x: (worldX - viewport.centerX) * viewport.zoomLevel + canvasWidth / 2,
|
|
1156
|
-
y: (worldY - viewport.centerY) * viewport.zoomLevel + canvasHeight / 2
|
|
1157
|
-
};
|
|
1158
|
-
}
|
|
1159
|
-
function screenToWorld(screenX, screenY, viewport, canvasWidth = DEFAULT_CANVAS_WIDTH, canvasHeight = DEFAULT_CANVAS_HEIGHT) {
|
|
1160
|
-
return {
|
|
1161
|
-
x: (screenX - canvasWidth / 2) / viewport.zoomLevel + viewport.centerX,
|
|
1162
|
-
y: (screenY - canvasHeight / 2) / viewport.zoomLevel + viewport.centerY
|
|
1163
|
-
};
|
|
1164
|
-
}
|
|
1165
|
-
function clampZoom(zoom) {
|
|
1166
|
-
return Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, zoom));
|
|
1167
|
-
}
|
|
1168
|
-
function panViewport(deltaX, deltaY, viewport) {
|
|
1169
|
-
return {
|
|
1170
|
-
...viewport,
|
|
1171
|
-
centerX: viewport.centerX - deltaX / viewport.zoomLevel,
|
|
1172
|
-
centerY: viewport.centerY - deltaY / viewport.zoomLevel
|
|
1173
|
-
};
|
|
1174
|
-
}
|
|
1175
|
-
function setViewportCenter(x, y, viewport) {
|
|
1176
|
-
return { ...viewport, centerX: x, centerY: y };
|
|
1177
|
-
}
|
|
1178
|
-
function zoomViewport(delta, viewport, pivotX, pivotY, canvasWidth = DEFAULT_CANVAS_WIDTH, canvasHeight = DEFAULT_CANVAS_HEIGHT) {
|
|
1179
|
-
const newZoom = clampZoom(viewport.zoomLevel * (1 + delta));
|
|
1180
|
-
let cx = viewport.centerX;
|
|
1181
|
-
let cy = viewport.centerY;
|
|
1182
|
-
if (pivotX !== void 0 && pivotY !== void 0) {
|
|
1183
|
-
const worldPivot = screenToWorld(pivotX, pivotY, viewport, canvasWidth, canvasHeight);
|
|
1184
|
-
cx = worldPivot.x - (pivotX - canvasWidth / 2) / newZoom;
|
|
1185
|
-
cy = worldPivot.y - (pivotY - canvasHeight / 2) / newZoom;
|
|
1186
|
-
}
|
|
1187
|
-
return { ...viewport, centerX: cx, centerY: cy, zoomLevel: newZoom };
|
|
1188
|
-
}
|
|
1189
|
-
function focusOnNode(nodeX, nodeY, zoom) {
|
|
1190
|
-
const clamped = clampZoom(zoom);
|
|
1191
|
-
return {
|
|
1192
|
-
centerX: nodeX,
|
|
1193
|
-
centerY: nodeY,
|
|
1194
|
-
zoomLevel: clamped,
|
|
1195
|
-
rotation: 0,
|
|
1196
|
-
visibleBounds: calculateViewportBounds(
|
|
1197
|
-
{ centerX: nodeX, centerY: nodeY, zoomLevel: clamped, rotation: 0, visibleBounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 } }
|
|
1198
|
-
)
|
|
1199
|
-
};
|
|
1200
|
-
}
|
|
1201
|
-
function isNodeInViewport(nodeX, nodeY, nodeWidth, nodeHeight, viewport, canvasWidth = DEFAULT_CANVAS_WIDTH, canvasHeight = DEFAULT_CANVAS_HEIGHT) {
|
|
1202
|
-
const bounds = calculateViewportBounds(viewport, canvasWidth, canvasHeight);
|
|
1203
|
-
const hw = nodeWidth / 2;
|
|
1204
|
-
const hh = nodeHeight / 2;
|
|
1205
|
-
return !(nodeX + hw < bounds.minX || nodeX - hw > bounds.maxX || nodeY + hh < bounds.minY || nodeY - hh > bounds.maxY);
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
// src/performance/performanceMonitor.ts
|
|
1209
|
-
var FPSMonitor = class {
|
|
1210
|
-
constructor() {
|
|
1211
|
-
this.frameTimes = [];
|
|
1212
|
-
this.lastTime = 0;
|
|
1213
|
-
this.currentFPS = FPS_TARGET;
|
|
1214
|
-
this.rafId = null;
|
|
1215
|
-
}
|
|
1216
|
-
start() {
|
|
1217
|
-
if (this.rafId !== null) return;
|
|
1218
|
-
const measure = (ts) => {
|
|
1219
|
-
if (this.lastTime > 0) {
|
|
1220
|
-
this.frameTimes.push(ts - this.lastTime);
|
|
1221
|
-
if (this.frameTimes.length > FPS_SAMPLE_WINDOW) this.frameTimes.shift();
|
|
1222
|
-
this.currentFPS = this.calc();
|
|
1223
|
-
}
|
|
1224
|
-
this.lastTime = ts;
|
|
1225
|
-
this.rafId = requestAnimationFrame(measure);
|
|
1226
|
-
};
|
|
1227
|
-
this.rafId = requestAnimationFrame(measure);
|
|
1228
|
-
}
|
|
1229
|
-
stop() {
|
|
1230
|
-
if (this.rafId !== null) {
|
|
1231
|
-
cancelAnimationFrame(this.rafId);
|
|
1232
|
-
this.rafId = null;
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
calc() {
|
|
1236
|
-
if (this.frameTimes.length === 0) return FPS_TARGET;
|
|
1237
|
-
const avg = this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length;
|
|
1238
|
-
return Math.round(1e3 / avg);
|
|
1239
|
-
}
|
|
1240
|
-
getFPS() {
|
|
1241
|
-
return this.currentFPS;
|
|
1242
|
-
}
|
|
1243
|
-
getAverageFPS() {
|
|
1244
|
-
return this.currentFPS;
|
|
1245
|
-
}
|
|
1246
|
-
getP95FrameTime() {
|
|
1247
|
-
if (this.frameTimes.length === 0) return 0;
|
|
1248
|
-
const sorted = [...this.frameTimes].sort((a, b) => a - b);
|
|
1249
|
-
return sorted[Math.floor(sorted.length * 0.95)];
|
|
1250
|
-
}
|
|
1251
|
-
reset() {
|
|
1252
|
-
this.frameTimes = [];
|
|
1253
|
-
this.currentFPS = FPS_TARGET;
|
|
1254
|
-
}
|
|
1255
|
-
};
|
|
1256
|
-
var MemoryMonitor = class {
|
|
1257
|
-
constructor() {
|
|
1258
|
-
this.timer = null;
|
|
1259
|
-
this.current = 0;
|
|
1260
|
-
}
|
|
1261
|
-
start(onUpdate) {
|
|
1262
|
-
if (this.timer !== null) return;
|
|
1263
|
-
this.timer = setInterval(() => {
|
|
1264
|
-
this.current = this.measure();
|
|
1265
|
-
onUpdate?.(this.current);
|
|
1266
|
-
}, MEMORY_CHECK_INTERVAL);
|
|
1267
|
-
}
|
|
1268
|
-
stop() {
|
|
1269
|
-
if (this.timer !== null) {
|
|
1270
|
-
clearInterval(this.timer);
|
|
1271
|
-
this.timer = null;
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
measure() {
|
|
1275
|
-
const mem = performance["memory"];
|
|
1276
|
-
return mem ? mem["usedJSHeapSize"] / (1024 * 1024) : 0;
|
|
1277
|
-
}
|
|
1278
|
-
getMemoryMB() {
|
|
1279
|
-
return this.current;
|
|
1280
|
-
}
|
|
1281
|
-
getStats() {
|
|
1282
|
-
const mem = performance["memory"];
|
|
1283
|
-
if (!mem) return null;
|
|
1284
|
-
return {
|
|
1285
|
-
usedJSHeapSize: mem["usedJSHeapSize"],
|
|
1286
|
-
totalJSHeapSize: mem["totalJSHeapSize"],
|
|
1287
|
-
jsHeapSizeLimit: mem["jsHeapSizeLimit"],
|
|
1288
|
-
heapUsagePercent: mem["usedJSHeapSize"] / mem["jsHeapSizeLimit"] * 100
|
|
1289
|
-
};
|
|
1290
|
-
}
|
|
1291
|
-
static isSupported() {
|
|
1292
|
-
return !!performance["memory"];
|
|
1293
|
-
}
|
|
1294
|
-
};
|
|
1295
|
-
var PerformanceProfiler = class {
|
|
1296
|
-
constructor() {
|
|
1297
|
-
this.marks = /* @__PURE__ */ new Map();
|
|
1298
|
-
this.measures = /* @__PURE__ */ new Map();
|
|
1299
|
-
}
|
|
1300
|
-
mark(label) {
|
|
1301
|
-
this.marks.set(label, performance.now());
|
|
1302
|
-
}
|
|
1303
|
-
measure(label) {
|
|
1304
|
-
const start = this.marks.get(label);
|
|
1305
|
-
if (start === void 0) return 0;
|
|
1306
|
-
const duration = performance.now() - start;
|
|
1307
|
-
const list = this.measures.get(label) ?? [];
|
|
1308
|
-
list.push(duration);
|
|
1309
|
-
this.measures.set(label, list);
|
|
1310
|
-
this.marks.delete(label);
|
|
1311
|
-
return duration;
|
|
1312
|
-
}
|
|
1313
|
-
getAverage(label) {
|
|
1314
|
-
const list = this.measures.get(label);
|
|
1315
|
-
if (!list?.length) return 0;
|
|
1316
|
-
return list.reduce((a, b) => a + b, 0) / list.length;
|
|
1317
|
-
}
|
|
1318
|
-
getP95(label) {
|
|
1319
|
-
const list = this.measures.get(label);
|
|
1320
|
-
if (!list?.length) return 0;
|
|
1321
|
-
const sorted = [...list].sort((a, b) => a - b);
|
|
1322
|
-
return sorted[Math.floor(sorted.length * 0.95)];
|
|
1323
|
-
}
|
|
1324
|
-
clear(label) {
|
|
1325
|
-
if (label) {
|
|
1326
|
-
this.marks.delete(label);
|
|
1327
|
-
this.measures.delete(label);
|
|
1328
|
-
} else {
|
|
1329
|
-
this.marks.clear();
|
|
1330
|
-
this.measures.clear();
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
};
|
|
1334
|
-
|
|
1335
|
-
// src/animations/easing.ts
|
|
1336
|
-
var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
|
1337
|
-
var easeInOutQuart = (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2;
|
|
1338
|
-
var easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
|
|
1339
|
-
var easeInCubic = (t) => t * t * t;
|
|
1340
|
-
var easeOutQuad = (t) => 1 - (1 - t) * (1 - t);
|
|
1341
|
-
var easeInOutSine = (t) => -(Math.cos(Math.PI * t) - 1) / 2;
|
|
1342
|
-
function createCubicBezier(x1, y1, x2, y2) {
|
|
1343
|
-
const N = 256;
|
|
1344
|
-
const lut = new Float64Array(N + 1);
|
|
1345
|
-
for (let i = 0; i <= N; i++) {
|
|
1346
|
-
const target = i / N;
|
|
1347
|
-
let lo = 0, hi = 1;
|
|
1348
|
-
for (let j = 0; j < 20; j++) {
|
|
1349
|
-
const mid = (lo + hi) / 2;
|
|
1350
|
-
const om = 1 - mid;
|
|
1351
|
-
const x = 3 * om * om * mid * x1 + 3 * om * mid * mid * x2 + mid * mid * mid;
|
|
1352
|
-
if (x < target) lo = mid;
|
|
1353
|
-
else hi = mid;
|
|
1354
|
-
}
|
|
1355
|
-
const u = (lo + hi) / 2;
|
|
1356
|
-
const ou = 1 - u;
|
|
1357
|
-
lut[i] = 3 * ou * ou * u * y1 + 3 * ou * u * u * y2 + u * u * u;
|
|
1358
|
-
}
|
|
1359
|
-
return (t) => {
|
|
1360
|
-
if (t <= 0) return 0;
|
|
1361
|
-
if (t >= 1) return 1;
|
|
1362
|
-
const s = t * N;
|
|
1363
|
-
const i = s | 0;
|
|
1364
|
-
return lut[i] + (lut[i + 1] - lut[i]) * (s - i);
|
|
1365
|
-
};
|
|
1366
|
-
}
|
|
1367
|
-
var easeZoomTransition = createCubicBezier(0.2, 0.8, 0.2, 1);
|
|
1368
|
-
|
|
1369
|
-
// src/animations/constants.ts
|
|
1370
|
-
var ANIMATION_DURATION = {
|
|
1371
|
-
ZOOM_IN_LAYER: 500,
|
|
1372
|
-
ZOOM_OUT_LAYER: 500,
|
|
1373
|
-
ZOOM_GESTURE: 500,
|
|
1374
|
-
FADE_OUT: 200,
|
|
1375
|
-
FADE_IN: 250,
|
|
1376
|
-
COLOR_TRANSITION: 500,
|
|
1377
|
-
CURSOR_CHANGE: 150,
|
|
1378
|
-
LOADING_FADE: 200
|
|
1379
|
-
};
|
|
1380
|
-
var ANIMATION_PHASES = {
|
|
1381
|
-
ZOOM_IN: {
|
|
1382
|
-
ZOOM_TO_TARGET: 500,
|
|
1383
|
-
FADE_OUT_START: 120,
|
|
1384
|
-
FADE_OUT: 280,
|
|
1385
|
-
CONTENT_SWAP: 310,
|
|
1386
|
-
FADE_IN: 200,
|
|
1387
|
-
TOTAL: 510
|
|
1388
|
-
},
|
|
1389
|
-
ZOOM_OUT: {
|
|
1390
|
-
FADE_OUT: 200,
|
|
1391
|
-
ZOOM_BACK: 50,
|
|
1392
|
-
FADE_IN: 250,
|
|
1393
|
-
TOTAL: 500
|
|
1394
|
-
}
|
|
1395
|
-
};
|
|
1396
|
-
var ZOOM_THRESHOLDS = {
|
|
1397
|
-
ENTER_LAYER: 5,
|
|
1398
|
-
EXIT_LAYER: 0.5,
|
|
1399
|
-
GESTURE_TRIGGER: 0.8
|
|
1400
|
-
};
|
|
1401
|
-
var COOLDOWN = {
|
|
1402
|
-
NAVIGATION: 1e3,
|
|
1403
|
-
ZOOM_GESTURE: 800,
|
|
1404
|
-
DOUBLE_CLICK: 200
|
|
1405
|
-
};
|
|
1406
|
-
var OPACITY = {
|
|
1407
|
-
VISIBLE: 1,
|
|
1408
|
-
HIDDEN: 0,
|
|
1409
|
-
TRANSITIONING: 0.3
|
|
1410
|
-
};
|
|
1411
|
-
var TARGET_ZOOM = {
|
|
1412
|
-
NORMAL: 1,
|
|
1413
|
-
FOCUSED: 0.8,
|
|
1414
|
-
FILL_NODE: 3,
|
|
1415
|
-
DETAIL: 2
|
|
1416
|
-
};
|
|
1417
|
-
var VIEWPORT_FRAMING = {
|
|
1418
|
-
NODE_FILL_RATIO: 0.7,
|
|
1419
|
-
EXIT_NODE_SIZE: 0.4,
|
|
1420
|
-
PADDING_RATIO: 0.1
|
|
1421
|
-
};
|
|
1
|
+
import "./chunk-VLGR5PZX.js";
|
|
2
|
+
import {
|
|
3
|
+
ANIMATION_DURATION,
|
|
4
|
+
ANIMATION_PHASES,
|
|
5
|
+
COOLDOWN,
|
|
6
|
+
OPACITY,
|
|
7
|
+
TARGET_ZOOM,
|
|
8
|
+
VIEWPORT_FRAMING,
|
|
9
|
+
ZOOM_THRESHOLDS,
|
|
10
|
+
createCubicBezier,
|
|
11
|
+
easeInCubic,
|
|
12
|
+
easeInOutCubic,
|
|
13
|
+
easeInOutQuart,
|
|
14
|
+
easeInOutSine,
|
|
15
|
+
easeOutCubic,
|
|
16
|
+
easeOutQuad,
|
|
17
|
+
easeZoomTransition
|
|
18
|
+
} from "./chunk-F36SMC3K.js";
|
|
19
|
+
import {
|
|
20
|
+
ACTIVE_BLOB_TYPES,
|
|
21
|
+
ALL_BLOB_SHAPES,
|
|
22
|
+
BLOB_LAYER_CONFIG,
|
|
23
|
+
BLOB_TEXT_OFFSETS,
|
|
24
|
+
CONTAINER_LABEL_BASE_FONT_PX,
|
|
25
|
+
DESCRIPTION_TEXT_BASE_FONT_PX,
|
|
26
|
+
EDGE_LABEL_BASE_FONT_PX,
|
|
27
|
+
NODE_LAYER_CONFIG,
|
|
28
|
+
NODE_TEXT_BASE_FONT_PX,
|
|
29
|
+
OVERLAY_FONT_UPPER_BOOST_PX,
|
|
30
|
+
computeEdgeLabelScale,
|
|
31
|
+
computeNodeTextScreenScale,
|
|
32
|
+
computeNodeTextWorldScale,
|
|
33
|
+
computeOverlayScale,
|
|
34
|
+
drawBlobPath,
|
|
35
|
+
getBlobTypeForLayer
|
|
36
|
+
} from "./chunk-LNTJTDB2.js";
|
|
37
|
+
import {
|
|
38
|
+
DEFAULT_RENDER_CONFIG,
|
|
39
|
+
FEATURE_FLAGS,
|
|
40
|
+
QUALITY_LEVELS,
|
|
41
|
+
QUALITY_SETTINGS,
|
|
42
|
+
RENDER_MODES,
|
|
43
|
+
SIMPLIFIED_RENDER_CONFIG,
|
|
44
|
+
getOptimalQualityLevel,
|
|
45
|
+
getRecommendedRenderConfig,
|
|
46
|
+
getRenderConfigForQuality,
|
|
47
|
+
isFeatureEnabled
|
|
48
|
+
} from "./chunk-I75TMOE4.js";
|
|
49
|
+
import {
|
|
50
|
+
checkCollision,
|
|
51
|
+
getNodeBounds,
|
|
52
|
+
optimizeLayout,
|
|
53
|
+
resolveCollisions
|
|
54
|
+
} from "./chunk-LI3BVD6H.js";
|
|
55
|
+
import {
|
|
56
|
+
VisualliParseError,
|
|
57
|
+
calculateDistance,
|
|
58
|
+
convertLayerToFlatNodes,
|
|
59
|
+
convertVisualliToFlatNodes,
|
|
60
|
+
countLayersBeneath,
|
|
61
|
+
createMindMapConfig,
|
|
62
|
+
fetchAndParseVisualli,
|
|
63
|
+
flattenNodes,
|
|
64
|
+
generateSampleConfig,
|
|
65
|
+
getChildLayers,
|
|
66
|
+
getNodeConnections,
|
|
67
|
+
getNodesForLayer,
|
|
68
|
+
getTopLevelConnections,
|
|
69
|
+
getVisibleNodes,
|
|
70
|
+
loadVisualliFileFromFile,
|
|
71
|
+
parseVisualliFile,
|
|
72
|
+
parseVisualliFromMongoDB,
|
|
73
|
+
resolveNodeOverlaps
|
|
74
|
+
} from "./chunk-6NXADJK2.js";
|
|
75
|
+
import {
|
|
76
|
+
BRAND_COLORS,
|
|
77
|
+
CANVAS_COLORS,
|
|
78
|
+
DS_COLORS,
|
|
79
|
+
DS_RADII,
|
|
80
|
+
DS_TYPOGRAPHY,
|
|
81
|
+
FONTS,
|
|
82
|
+
FONT_SIZES,
|
|
83
|
+
LAYOUT_SPACING,
|
|
84
|
+
LEVEL_COLORS,
|
|
85
|
+
LEVEL_COLOR_ARRAY,
|
|
86
|
+
PARENT_FALLBACK_COLORS,
|
|
87
|
+
SEMANTIC_COLORS,
|
|
88
|
+
SPACING,
|
|
89
|
+
THEME_COLORS,
|
|
90
|
+
darkenHexColor,
|
|
91
|
+
getColorForLevel,
|
|
92
|
+
getThemeBackground,
|
|
93
|
+
getThemeBorder,
|
|
94
|
+
getThemeText
|
|
95
|
+
} from "./chunk-G5H3P4YZ.js";
|
|
96
|
+
import {
|
|
97
|
+
applyCircularLayout,
|
|
98
|
+
applyLinearHorizontalLayout,
|
|
99
|
+
applyLinearVerticalLayout,
|
|
100
|
+
calculateMinimumRadius,
|
|
101
|
+
calculateOptimalRadiusPercentage
|
|
102
|
+
} from "./chunk-GQMFBYLK.js";
|
|
103
|
+
import {
|
|
104
|
+
FPSMonitor,
|
|
105
|
+
MemoryMonitor,
|
|
106
|
+
PerformanceProfiler
|
|
107
|
+
} from "./chunk-PDP5CVUL.js";
|
|
108
|
+
import {
|
|
109
|
+
calculateViewportBounds,
|
|
110
|
+
clampZoom,
|
|
111
|
+
focusOnNode,
|
|
112
|
+
isNodeInViewport,
|
|
113
|
+
panViewport,
|
|
114
|
+
recalculateViewportBounds,
|
|
115
|
+
screenToWorld,
|
|
116
|
+
setViewportCenter,
|
|
117
|
+
worldToScreen,
|
|
118
|
+
zoomViewport
|
|
119
|
+
} from "./chunk-LJYSKSCE.js";
|
|
120
|
+
import {
|
|
121
|
+
BORDER_WIDTH_NORMAL,
|
|
122
|
+
BORDER_WIDTH_SELECTED,
|
|
123
|
+
CHAR_WIDTH,
|
|
124
|
+
CIRCULAR_REFERENCE_MAX_DEPTH,
|
|
125
|
+
CLICK_THRESHOLD,
|
|
126
|
+
COLOR_BORDER_DARK,
|
|
127
|
+
COLOR_BORDER_LIGHT,
|
|
128
|
+
COLOR_DEFAULT_NODE,
|
|
129
|
+
COLOR_SELECTED,
|
|
130
|
+
CORNER_RADIUS,
|
|
131
|
+
CULLING_QUERY_TIME_BUDGET,
|
|
132
|
+
DEFAULT_CANVAS_HEIGHT,
|
|
133
|
+
DEFAULT_CANVAS_WIDTH,
|
|
134
|
+
DOUBLE_CLICK_DELAY,
|
|
135
|
+
DRAG_START_DISTANCE,
|
|
136
|
+
FPS_CRITICAL_THRESHOLD,
|
|
137
|
+
FPS_DOWNGRADE_THRESHOLD,
|
|
138
|
+
FPS_SAMPLE_WINDOW,
|
|
139
|
+
FPS_STABILIZATION_FRAMES,
|
|
140
|
+
FPS_TARGET,
|
|
141
|
+
FPS_TARGETS,
|
|
142
|
+
FPS_UPDATE_INTERVAL,
|
|
143
|
+
FPS_UPGRADE_THRESHOLD,
|
|
144
|
+
FPS_WARNING_THRESHOLD,
|
|
145
|
+
MAX_FRAME_TIME,
|
|
146
|
+
MAX_NODES,
|
|
147
|
+
MAX_VISIBLE_NODES,
|
|
148
|
+
MEMORY_CHECK_INTERVAL,
|
|
149
|
+
MEMORY_CRITICAL_MB,
|
|
150
|
+
MEMORY_LIMITS,
|
|
151
|
+
MEMORY_TARGET_MB,
|
|
152
|
+
MEMORY_WARNING_MB,
|
|
153
|
+
NODE_COUNT_THRESHOLDS,
|
|
154
|
+
NODE_HEIGHT,
|
|
155
|
+
NODE_MIN_WIDTH,
|
|
156
|
+
NODE_PADDING,
|
|
157
|
+
PERFORMANCE_TOAST_COOLDOWN,
|
|
158
|
+
QUALITY_HIGH,
|
|
159
|
+
QUALITY_LOW,
|
|
160
|
+
QUALITY_MEDIUM,
|
|
161
|
+
RBUSH_MAX_ENTRIES,
|
|
162
|
+
RESIZE_DEBOUNCE,
|
|
163
|
+
SCROLL_THROTTLE,
|
|
164
|
+
SEARCH_DEBOUNCE,
|
|
165
|
+
SPATIAL_INDEX_BUILD_BUDGET,
|
|
166
|
+
TARGET_FRAME_TIME,
|
|
167
|
+
TEXT_LABEL_HIDE_BELOW_ZOOM,
|
|
168
|
+
TIMING_THRESHOLDS,
|
|
169
|
+
TITLE_MAX_LENGTH,
|
|
170
|
+
VIEWPORT_CONFIG,
|
|
171
|
+
VIEWPORT_MARGIN,
|
|
172
|
+
ZOOM_DEFAULT,
|
|
173
|
+
ZOOM_MAX,
|
|
174
|
+
ZOOM_MIN,
|
|
175
|
+
ZOOM_NAV_IN_THRESHOLD,
|
|
176
|
+
ZOOM_NAV_OUT_THRESHOLD,
|
|
177
|
+
ZOOM_STEP,
|
|
178
|
+
ZOOM_WHEEL_SENSITIVITY
|
|
179
|
+
} from "./chunk-LDJRGT2Q.js";
|
|
1422
180
|
|
|
1423
181
|
// src/spatial/spatialIndex.ts
|
|
1424
182
|
import RBush from "rbush";
|
|
@@ -1621,332 +379,6 @@ function getViewportVisibleNodes(options) {
|
|
|
1621
379
|
(n) => n.x + n.width >= bounds.minX && n.x <= bounds.maxX && n.y + n.height >= bounds.minY && n.y <= bounds.maxY
|
|
1622
380
|
);
|
|
1623
381
|
}
|
|
1624
|
-
|
|
1625
|
-
// src/config/textScaling.ts
|
|
1626
|
-
var NODE_TEXT_BASE_FONT_PX = 28;
|
|
1627
|
-
var DESCRIPTION_TEXT_BASE_FONT_PX = 12;
|
|
1628
|
-
var CONTAINER_LABEL_BASE_FONT_PX = 24;
|
|
1629
|
-
var EDGE_LABEL_BASE_FONT_PX = 18;
|
|
1630
|
-
var OVERLAY_FONT_UPPER_BOOST_PX = 8;
|
|
1631
|
-
var NODE_TEXT_SAFE_BLOB_FILL_RATIO = 0.88;
|
|
1632
|
-
function computeNodeTextWorldScale(nodeWidth, zoomLevel) {
|
|
1633
|
-
const safeZoom = Math.max(zoomLevel, 1e-4);
|
|
1634
|
-
const baseRadiusX = nodeWidth / 2;
|
|
1635
|
-
const baseRadiusY = Math.max(NODE_HEIGHT * 1.6 / 2, baseRadiusX * 0.74);
|
|
1636
|
-
const textNaturalWidth = nodeWidth - 40;
|
|
1637
|
-
const textNaturalHeight = NODE_HEIGHT - 20;
|
|
1638
|
-
const maxScaleX = baseRadiusX * 2 * NODE_TEXT_SAFE_BLOB_FILL_RATIO / Math.max(textNaturalWidth, 1);
|
|
1639
|
-
const maxScaleY = baseRadiusY * 2 * NODE_TEXT_SAFE_BLOB_FILL_RATIO / Math.max(textNaturalHeight, 1);
|
|
1640
|
-
const fitScale = Math.max(0.01, Math.min(maxScaleX, maxScaleY));
|
|
1641
|
-
return Math.min(1 / safeZoom, fitScale);
|
|
1642
|
-
}
|
|
1643
|
-
function computeNodeTextScreenScale(nodeWidth, zoomLevel) {
|
|
1644
|
-
return computeNodeTextWorldScale(nodeWidth, zoomLevel) * zoomLevel;
|
|
1645
|
-
}
|
|
1646
|
-
function computeOverlayScale(zoomLevel) {
|
|
1647
|
-
const safeZoom = Math.max(zoomLevel, 1e-4);
|
|
1648
|
-
const inverseScale = 1 / safeZoom;
|
|
1649
|
-
const maxScale = (NODE_TEXT_BASE_FONT_PX + OVERLAY_FONT_UPPER_BOOST_PX) / NODE_TEXT_BASE_FONT_PX;
|
|
1650
|
-
return Math.min(Math.max(inverseScale, 1), maxScale);
|
|
1651
|
-
}
|
|
1652
|
-
function computeEdgeLabelScale(zoomLevel) {
|
|
1653
|
-
const safeZoom = Math.max(zoomLevel, 1e-4);
|
|
1654
|
-
return Math.min(Math.max(EDGE_LABEL_BASE_FONT_PX / safeZoom, 10), 32);
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
|
-
// src/config/blobShapes.ts
|
|
1658
|
-
var BLOB_LAYER_CONFIG = [
|
|
1659
|
-
{ opacity: 0.3, rotation: -15, scaleUp: 1.3, strokeWidth: 3, dash: [6, 4] },
|
|
1660
|
-
// Layer #3 (outermost)
|
|
1661
|
-
{ opacity: 0.4, rotation: -10, scaleUp: 1.2, strokeWidth: 1, dash: void 0 },
|
|
1662
|
-
// Layer #2
|
|
1663
|
-
{ opacity: 0.5, rotation: -5, scaleUp: 1.1, strokeWidth: 2, dash: void 0 }
|
|
1664
|
-
// Layer #1
|
|
1665
|
-
];
|
|
1666
|
-
var NODE_LAYER_CONFIG = { opacity: 1, rotation: 0, strokeWidth: 3 };
|
|
1667
|
-
var ALL_BLOB_SHAPES = [
|
|
1668
|
-
// Shape 0 · Blob 1
|
|
1669
|
-
[
|
|
1670
|
-
{ x: 1.12, y: 0 },
|
|
1671
|
-
{ x: 0.86, y: 0.56 },
|
|
1672
|
-
{ x: 0.46, y: 0.94 },
|
|
1673
|
-
{ x: -0.08, y: 1.06 },
|
|
1674
|
-
{ x: -0.68, y: 0.82 },
|
|
1675
|
-
{ x: -0.96, y: 0.08 },
|
|
1676
|
-
{ x: -0.55, y: -0.82 },
|
|
1677
|
-
{ x: 0.04, y: -1.02 },
|
|
1678
|
-
{ x: 0.72, y: -0.8 },
|
|
1679
|
-
{ x: 1.08, y: -0.38 }
|
|
1680
|
-
],
|
|
1681
|
-
// Shape 1 · Blob 2
|
|
1682
|
-
[
|
|
1683
|
-
{ x: -0.489, y: -0.625 },
|
|
1684
|
-
{ x: -0.384, y: -0.716 },
|
|
1685
|
-
{ x: -0.285, y: -0.792 },
|
|
1686
|
-
{ x: -0.189, y: -0.855 },
|
|
1687
|
-
{ x: -0.09, y: -0.903 },
|
|
1688
|
-
{ x: 0.014, y: -0.932 },
|
|
1689
|
-
{ x: 0.129, y: -0.94 },
|
|
1690
|
-
{ x: 0.255, y: -0.924 },
|
|
1691
|
-
{ x: 0.412, y: -0.876 },
|
|
1692
|
-
{ x: 0.516, y: -0.832 },
|
|
1693
|
-
{ x: 0.612, y: -0.78 },
|
|
1694
|
-
{ x: 0.695, y: -0.725 },
|
|
1695
|
-
{ x: 0.767, y: -0.666 },
|
|
1696
|
-
{ x: 0.83, y: -0.606 },
|
|
1697
|
-
{ x: 0.885, y: -0.546 },
|
|
1698
|
-
{ x: 0.933, y: -0.486 },
|
|
1699
|
-
{ x: 0.979, y: -0.425 },
|
|
1700
|
-
{ x: 1.006, y: -0.385 },
|
|
1701
|
-
{ x: 1.034, y: -0.334 },
|
|
1702
|
-
{ x: 1.058, y: -0.276 },
|
|
1703
|
-
{ x: 1.078, y: -0.209 },
|
|
1704
|
-
{ x: 1.092, y: -0.133 },
|
|
1705
|
-
{ x: 1.101, y: -0.046 },
|
|
1706
|
-
{ x: 1.102, y: 0.052 },
|
|
1707
|
-
{ x: 1.094, y: 0.173 },
|
|
1708
|
-
{ x: 1.083, y: 0.244 },
|
|
1709
|
-
{ x: 1.063, y: 0.324 },
|
|
1710
|
-
{ x: 1.034, y: 0.401 },
|
|
1711
|
-
{ x: 0.996, y: 0.477 },
|
|
1712
|
-
{ x: 0.948, y: 0.549 },
|
|
1713
|
-
{ x: 0.889, y: 0.617 },
|
|
1714
|
-
{ x: 0.82, y: 0.681 },
|
|
1715
|
-
{ x: 0.735, y: 0.741 },
|
|
1716
|
-
{ x: 0.658, y: 0.783 },
|
|
1717
|
-
{ x: 0.569, y: 0.822 },
|
|
1718
|
-
{ x: 0.474, y: 0.855 },
|
|
1719
|
-
{ x: 0.372, y: 0.882 },
|
|
1720
|
-
{ x: 0.265, y: 0.904 },
|
|
1721
|
-
{ x: 0.156, y: 0.92 },
|
|
1722
|
-
{ x: 0.046, y: 0.931 },
|
|
1723
|
-
{ x: -0.069, y: 0.938 },
|
|
1724
|
-
{ x: -0.155, y: 0.935 },
|
|
1725
|
-
{ x: -0.25, y: 0.919 },
|
|
1726
|
-
{ x: -0.346, y: 0.89 },
|
|
1727
|
-
{ x: -0.443, y: 0.851 },
|
|
1728
|
-
{ x: -0.539, y: 0.8 },
|
|
1729
|
-
{ x: -0.633, y: 0.738 },
|
|
1730
|
-
{ x: -0.723, y: 0.667 },
|
|
1731
|
-
{ x: -0.808, y: 0.585 },
|
|
1732
|
-
{ x: -0.882, y: 0.501 },
|
|
1733
|
-
{ x: -0.944, y: 0.421 },
|
|
1734
|
-
{ x: -0.994, y: 0.343 },
|
|
1735
|
-
{ x: -1.034, y: 0.267 },
|
|
1736
|
-
{ x: -1.064, y: 0.192 },
|
|
1737
|
-
{ x: -1.085, y: 0.12 },
|
|
1738
|
-
{ x: -1.097, y: 0.042 },
|
|
1739
|
-
{ x: -1.102, y: 1e-3 },
|
|
1740
|
-
{ x: -1.09, y: -0.243 },
|
|
1741
|
-
{ x: -1.05, y: -0.365 },
|
|
1742
|
-
{ x: -0.99, y: -0.441 },
|
|
1743
|
-
{ x: -0.911, y: -0.479 },
|
|
1744
|
-
{ x: -0.819, y: -0.499 },
|
|
1745
|
-
{ x: -0.715, y: -0.517 },
|
|
1746
|
-
{ x: -0.605, y: -0.551 }
|
|
1747
|
-
],
|
|
1748
|
-
// Shape 2 · Blob 3
|
|
1749
|
-
[
|
|
1750
|
-
{ x: 3e-3, y: -0.97 },
|
|
1751
|
-
{ x: 0.163, y: -0.984 },
|
|
1752
|
-
{ x: 0.286, y: -1.028 },
|
|
1753
|
-
{ x: 0.389, y: -1.096 },
|
|
1754
|
-
{ x: 0.488, y: -1.174 },
|
|
1755
|
-
{ x: 0.597, y: -1.21 },
|
|
1756
|
-
{ x: 0.728, y: -1.165 },
|
|
1757
|
-
{ x: 0.867, y: -1.036 },
|
|
1758
|
-
{ x: 0.996, y: -0.839 },
|
|
1759
|
-
{ x: 1.098, y: -0.59 },
|
|
1760
|
-
{ x: 1.158, y: -0.304 },
|
|
1761
|
-
{ x: 1.153, y: 0.012 },
|
|
1762
|
-
{ x: 1.08, y: 0.336 },
|
|
1763
|
-
{ x: 0.944, y: 0.639 },
|
|
1764
|
-
{ x: 0.756, y: 0.889 },
|
|
1765
|
-
{ x: 0.484, y: 1.072 },
|
|
1766
|
-
{ x: 0.339, y: 1.079 },
|
|
1767
|
-
{ x: 0.219, y: 1.051 },
|
|
1768
|
-
{ x: 0.131, y: 0.994 },
|
|
1769
|
-
{ x: 0.059, y: 0.939 },
|
|
1770
|
-
{ x: 8e-3, y: 0.915 },
|
|
1771
|
-
{ x: -0.105, y: 0.931 },
|
|
1772
|
-
{ x: -0.176, y: 0.965 },
|
|
1773
|
-
{ x: -0.249, y: 1.005 },
|
|
1774
|
-
{ x: -0.345, y: 1.039 },
|
|
1775
|
-
{ x: -0.497, y: 1.055 },
|
|
1776
|
-
{ x: -0.672, y: 1.032 },
|
|
1777
|
-
{ x: -0.817, y: 0.952 },
|
|
1778
|
-
{ x: -0.945, y: 0.81 },
|
|
1779
|
-
{ x: -1.054, y: 0.6 },
|
|
1780
|
-
{ x: -1.16, y: 0.302 },
|
|
1781
|
-
{ x: -1.187, y: -0.011 },
|
|
1782
|
-
{ x: -1.165, y: -0.326 },
|
|
1783
|
-
{ x: -1.097, y: -0.599 },
|
|
1784
|
-
{ x: -0.991, y: -0.838 },
|
|
1785
|
-
{ x: -0.852, y: -0.912 },
|
|
1786
|
-
{ x: -0.695, y: -0.958 },
|
|
1787
|
-
{ x: -0.53, y: -0.988 },
|
|
1788
|
-
{ x: -0.357, y: -0.992 },
|
|
1789
|
-
{ x: -0.18, y: -0.983 }
|
|
1790
|
-
],
|
|
1791
|
-
// Shape 3 · Blob 4
|
|
1792
|
-
[
|
|
1793
|
-
{ x: -0.734, y: -1.127 },
|
|
1794
|
-
{ x: -0.656, y: -1.146 },
|
|
1795
|
-
{ x: -0.567, y: -1.142 },
|
|
1796
|
-
{ x: -0.468, y: -1.115 },
|
|
1797
|
-
{ x: -0.358, y: -1.079 },
|
|
1798
|
-
{ x: -0.238, y: -1.034 },
|
|
1799
|
-
{ x: -0.107, y: -0.989 },
|
|
1800
|
-
{ x: 0.035, y: -0.953 },
|
|
1801
|
-
{ x: 0.188, y: -0.929 },
|
|
1802
|
-
{ x: 0.325, y: -0.916 },
|
|
1803
|
-
{ x: 0.484, y: -0.896 },
|
|
1804
|
-
{ x: 0.65, y: -0.854 },
|
|
1805
|
-
{ x: 0.811, y: -0.77 },
|
|
1806
|
-
{ x: 0.955, y: -0.631 },
|
|
1807
|
-
{ x: 1.068, y: -0.422 },
|
|
1808
|
-
{ x: 1.138, y: -0.126 },
|
|
1809
|
-
{ x: 1.152, y: 0.272 },
|
|
1810
|
-
{ x: 1.121, y: 0.451 },
|
|
1811
|
-
{ x: 1.046, y: 0.602 },
|
|
1812
|
-
{ x: 0.928, y: 0.727 },
|
|
1813
|
-
{ x: 0.767, y: 0.833 },
|
|
1814
|
-
{ x: 0.565, y: 0.925 },
|
|
1815
|
-
{ x: 0.323, y: 1.001 },
|
|
1816
|
-
{ x: 0.042, y: 1.075 },
|
|
1817
|
-
{ x: -0.277, y: 1.142 },
|
|
1818
|
-
{ x: -0.368, y: 1.147 },
|
|
1819
|
-
{ x: -0.475, y: 1.136 },
|
|
1820
|
-
{ x: -0.589, y: 1.104 },
|
|
1821
|
-
{ x: -0.704, y: 1.05 },
|
|
1822
|
-
{ x: -0.815, y: 0.973 },
|
|
1823
|
-
{ x: -0.913, y: 0.871 },
|
|
1824
|
-
{ x: -0.993, y: 0.746 },
|
|
1825
|
-
{ x: -1.048, y: 0.593 },
|
|
1826
|
-
{ x: -1.109, y: 0.298 },
|
|
1827
|
-
{ x: -1.145, y: 0.018 },
|
|
1828
|
-
{ x: -1.154, y: -0.243 },
|
|
1829
|
-
{ x: -1.135, y: -0.482 },
|
|
1830
|
-
{ x: -1.085, y: -0.695 },
|
|
1831
|
-
{ x: -1.003, y: -0.874 },
|
|
1832
|
-
{ x: -0.886, y: -1.02 }
|
|
1833
|
-
],
|
|
1834
|
-
// Shape 4 · Blob 5
|
|
1835
|
-
[
|
|
1836
|
-
{ x: -0.734, y: 1.127 },
|
|
1837
|
-
{ x: -0.656, y: 1.146 },
|
|
1838
|
-
{ x: -0.567, y: 1.142 },
|
|
1839
|
-
{ x: -0.468, y: 1.115 },
|
|
1840
|
-
{ x: -0.358, y: 1.079 },
|
|
1841
|
-
{ x: -0.238, y: 1.034 },
|
|
1842
|
-
{ x: -0.107, y: 0.989 },
|
|
1843
|
-
{ x: 0.035, y: 0.953 },
|
|
1844
|
-
{ x: 0.188, y: 0.929 },
|
|
1845
|
-
{ x: 0.325, y: 0.916 },
|
|
1846
|
-
{ x: 0.484, y: 0.896 },
|
|
1847
|
-
{ x: 0.65, y: 0.854 },
|
|
1848
|
-
{ x: 0.811, y: 0.77 },
|
|
1849
|
-
{ x: 0.955, y: 0.631 },
|
|
1850
|
-
{ x: 1.068, y: 0.422 },
|
|
1851
|
-
{ x: 1.138, y: 0.126 },
|
|
1852
|
-
{ x: 1.152, y: -0.272 },
|
|
1853
|
-
{ x: 1.121, y: -0.451 },
|
|
1854
|
-
{ x: 1.046, y: -0.602 },
|
|
1855
|
-
{ x: 0.928, y: -0.727 },
|
|
1856
|
-
{ x: 0.767, y: -0.833 },
|
|
1857
|
-
{ x: 0.565, y: -0.925 },
|
|
1858
|
-
{ x: 0.323, y: -1.001 },
|
|
1859
|
-
{ x: 0.042, y: -1.075 },
|
|
1860
|
-
{ x: -0.277, y: -1.142 },
|
|
1861
|
-
{ x: -0.368, y: -1.147 },
|
|
1862
|
-
{ x: -0.475, y: -1.136 },
|
|
1863
|
-
{ x: -0.589, y: -1.104 },
|
|
1864
|
-
{ x: -0.704, y: -1.05 },
|
|
1865
|
-
{ x: -0.815, y: -0.973 },
|
|
1866
|
-
{ x: -0.913, y: -0.871 },
|
|
1867
|
-
{ x: -0.993, y: -0.746 },
|
|
1868
|
-
{ x: -1.048, y: -0.593 },
|
|
1869
|
-
{ x: -1.109, y: -0.298 },
|
|
1870
|
-
{ x: -1.145, y: -0.018 },
|
|
1871
|
-
{ x: -1.154, y: 0.243 },
|
|
1872
|
-
{ x: -1.135, y: 0.482 },
|
|
1873
|
-
{ x: -1.085, y: 0.695 },
|
|
1874
|
-
{ x: -1.003, y: 0.874 },
|
|
1875
|
-
{ x: -0.886, y: 1.02 }
|
|
1876
|
-
],
|
|
1877
|
-
// Shape 5 · Blob 6
|
|
1878
|
-
[
|
|
1879
|
-
{ x: 1e-3, y: -1.006 },
|
|
1880
|
-
{ x: 0.134, y: -1.001 },
|
|
1881
|
-
{ x: 0.262, y: -1.024 },
|
|
1882
|
-
{ x: 0.382, y: -1.073 },
|
|
1883
|
-
{ x: 0.498, y: -1.107 },
|
|
1884
|
-
{ x: 0.614, y: -1.105 },
|
|
1885
|
-
{ x: 0.733, y: -1.049 },
|
|
1886
|
-
{ x: 0.85, y: -0.932 },
|
|
1887
|
-
{ x: 0.953, y: -0.755 },
|
|
1888
|
-
{ x: 1.03, y: -0.529 },
|
|
1889
|
-
{ x: 1.067, y: -0.265 },
|
|
1890
|
-
{ x: 1.054, y: 0.018 },
|
|
1891
|
-
{ x: 0.986, y: 0.3 },
|
|
1892
|
-
{ x: 0.868, y: 0.557 },
|
|
1893
|
-
{ x: 0.715, y: 0.766 },
|
|
1894
|
-
{ x: 0.55, y: 0.909 },
|
|
1895
|
-
{ x: 0.396, y: 0.984 },
|
|
1896
|
-
{ x: 0.262, y: 1.005 },
|
|
1897
|
-
{ x: 0.148, y: 1.003 },
|
|
1898
|
-
{ x: 0.037, y: 1.008 },
|
|
1899
|
-
{ x: -0.083, y: 1.04 },
|
|
1900
|
-
{ x: -0.22, y: 1.118 },
|
|
1901
|
-
{ x: -0.36, y: 1.192 },
|
|
1902
|
-
{ x: -0.5, y: 1.234 },
|
|
1903
|
-
{ x: -0.65, y: 1.175 },
|
|
1904
|
-
{ x: -0.81, y: 1.045 },
|
|
1905
|
-
{ x: -0.99, y: 0.855 },
|
|
1906
|
-
{ x: -1.14, y: 0.61 },
|
|
1907
|
-
{ x: -1.24, y: 0.33 },
|
|
1908
|
-
{ x: -1.27, y: 0.04 },
|
|
1909
|
-
{ x: -1.275, y: -0.25 },
|
|
1910
|
-
{ x: -1.225, y: -0.5 },
|
|
1911
|
-
{ x: -1.08, y: -0.72 },
|
|
1912
|
-
{ x: -0.89, y: -0.92 },
|
|
1913
|
-
{ x: -0.734, y: -1.053 },
|
|
1914
|
-
{ x: -0.614, y: -1.112 },
|
|
1915
|
-
{ x: -0.498, y: -1.127 },
|
|
1916
|
-
{ x: -0.381, y: -1.11 },
|
|
1917
|
-
{ x: -0.261, y: -1.095 },
|
|
1918
|
-
{ x: -0.133, y: -1.058 },
|
|
1919
|
-
{ x: 1e-3, y: -1.01 },
|
|
1920
|
-
{ x: 0.134, y: -1.001 }
|
|
1921
|
-
]
|
|
1922
|
-
];
|
|
1923
|
-
var ACTIVE_BLOB_TYPES = [0, 1, 2, 3, 4, 5];
|
|
1924
|
-
var BLOB_TEXT_OFFSETS = [0, 0, 0, 0, 0, -0.1];
|
|
1925
|
-
function getBlobTypeForLayer(level) {
|
|
1926
|
-
const numTypes = ACTIVE_BLOB_TYPES.length;
|
|
1927
|
-
if (numTypes <= 1) return ACTIVE_BLOB_TYPES[0] ?? 0;
|
|
1928
|
-
let currentType = 0;
|
|
1929
|
-
for (let i = 1; i <= level; i++) {
|
|
1930
|
-
const pseudoRandom = Math.floor(Math.abs(Math.sin((i + 1) * 12.9898) * 43758.5453));
|
|
1931
|
-
const stepOffset = pseudoRandom % (numTypes - 1) + 1;
|
|
1932
|
-
currentType = (currentType + stepOffset) % numTypes;
|
|
1933
|
-
}
|
|
1934
|
-
return ACTIVE_BLOB_TYPES[currentType];
|
|
1935
|
-
}
|
|
1936
|
-
function drawBlobPath(ctx, radiusX, radiusY, blobType) {
|
|
1937
|
-
const srcPts = ALL_BLOB_SHAPES[blobType] ?? ALL_BLOB_SHAPES[0];
|
|
1938
|
-
const pts = srcPts.map((p) => ({ x: p.x * radiusX, y: p.y * radiusY }));
|
|
1939
|
-
ctx.beginPath();
|
|
1940
|
-
const last = pts[pts.length - 1];
|
|
1941
|
-
const first = pts[0];
|
|
1942
|
-
ctx.moveTo((last.x + first.x) / 2, (last.y + first.y) / 2);
|
|
1943
|
-
for (let i = 0; i < pts.length; i++) {
|
|
1944
|
-
const curr = pts[i];
|
|
1945
|
-
const next = pts[(i + 1) % pts.length];
|
|
1946
|
-
ctx.quadraticCurveTo(curr.x, curr.y, (curr.x + next.x) / 2, (curr.y + next.y) / 2);
|
|
1947
|
-
}
|
|
1948
|
-
ctx.closePath();
|
|
1949
|
-
}
|
|
1950
382
|
export {
|
|
1951
383
|
ACTIVE_BLOB_TYPES,
|
|
1952
384
|
ALL_BLOB_SHAPES,
|