@visualli/core 0.1.4 → 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
|
@@ -0,0 +1,739 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/parser/index.ts
|
|
21
|
+
var parser_exports = {};
|
|
22
|
+
__export(parser_exports, {
|
|
23
|
+
VisualliParseError: () => VisualliParseError,
|
|
24
|
+
calculateDistance: () => calculateDistance,
|
|
25
|
+
convertLayerToFlatNodes: () => convertLayerToFlatNodes,
|
|
26
|
+
convertVisualliToFlatNodes: () => convertVisualliToFlatNodes,
|
|
27
|
+
countLayersBeneath: () => countLayersBeneath,
|
|
28
|
+
createMindMapConfig: () => createMindMapConfig,
|
|
29
|
+
fetchAndParseVisualli: () => fetchAndParseVisualli,
|
|
30
|
+
flattenNodes: () => flattenNodes,
|
|
31
|
+
generateSampleConfig: () => generateSampleConfig,
|
|
32
|
+
getChildLayers: () => getChildLayers,
|
|
33
|
+
getNodeConnections: () => getNodeConnections,
|
|
34
|
+
getNodesForLayer: () => getNodesForLayer,
|
|
35
|
+
getTopLevelConnections: () => getTopLevelConnections,
|
|
36
|
+
getVisibleNodes: () => getVisibleNodes,
|
|
37
|
+
loadVisualliFileFromFile: () => loadVisualliFileFromFile,
|
|
38
|
+
parseVisualliFile: () => parseVisualliFile,
|
|
39
|
+
parseVisualliFromMongoDB: () => parseVisualliFromMongoDB,
|
|
40
|
+
resolveNodeOverlaps: () => resolveNodeOverlaps
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(parser_exports);
|
|
43
|
+
|
|
44
|
+
// src/parser/visualliParser.ts
|
|
45
|
+
function toVisualliLayer(schemaLayer) {
|
|
46
|
+
return {
|
|
47
|
+
type: "layer",
|
|
48
|
+
id: schemaLayer.id,
|
|
49
|
+
level: schemaLayer.level,
|
|
50
|
+
parentLayerId: schemaLayer.parentLayerId,
|
|
51
|
+
parentNodeId: schemaLayer.parentNodeId,
|
|
52
|
+
layout: schemaLayer.layout,
|
|
53
|
+
nodes: schemaLayer.nodes ?? [],
|
|
54
|
+
connections: schemaLayer.connections ?? [],
|
|
55
|
+
containers: schemaLayer.containers ?? []
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
var VisualliParseError = class extends Error {
|
|
59
|
+
constructor(message, lineNumber) {
|
|
60
|
+
super(message);
|
|
61
|
+
this.lineNumber = lineNumber;
|
|
62
|
+
this.name = "VisualliParseError";
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
function parseVisualliFile(content) {
|
|
66
|
+
const lines = content.trim().split("\n");
|
|
67
|
+
const doc = {
|
|
68
|
+
meta: null,
|
|
69
|
+
layers: /* @__PURE__ */ new Map(),
|
|
70
|
+
layersByLevel: /* @__PURE__ */ new Map(),
|
|
71
|
+
rootLayer: null
|
|
72
|
+
};
|
|
73
|
+
let lineNumber = 0;
|
|
74
|
+
for (const line of lines) {
|
|
75
|
+
lineNumber++;
|
|
76
|
+
if (!line.trim()) continue;
|
|
77
|
+
let obj;
|
|
78
|
+
try {
|
|
79
|
+
obj = JSON.parse(line);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
throw new VisualliParseError(
|
|
82
|
+
`Failed to parse JSON at line ${lineNumber}: ${err}`,
|
|
83
|
+
lineNumber
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (!obj["type"]) {
|
|
87
|
+
throw new VisualliParseError(
|
|
88
|
+
`Missing 'type' field at line ${lineNumber}`,
|
|
89
|
+
lineNumber
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
switch (obj["type"]) {
|
|
93
|
+
case "meta":
|
|
94
|
+
doc.meta = obj;
|
|
95
|
+
break;
|
|
96
|
+
case "layer": {
|
|
97
|
+
const schemaLayer = obj;
|
|
98
|
+
const layer = toVisualliLayer(schemaLayer);
|
|
99
|
+
doc.layers.set(layer.id, layer);
|
|
100
|
+
if (!doc.layersByLevel.has(layer.level)) {
|
|
101
|
+
doc.layersByLevel.set(layer.level, []);
|
|
102
|
+
}
|
|
103
|
+
doc.layersByLevel.get(layer.level).push(layer);
|
|
104
|
+
if (layer.level === 0) {
|
|
105
|
+
doc.rootLayer = layer;
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
default:
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (!doc.meta) throw new VisualliParseError("Missing required meta section");
|
|
114
|
+
if (!doc.rootLayer) throw new VisualliParseError("Missing root layer (level 0)");
|
|
115
|
+
return doc;
|
|
116
|
+
}
|
|
117
|
+
async function fetchAndParseVisualli(url) {
|
|
118
|
+
const response = await fetch(url);
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
121
|
+
}
|
|
122
|
+
return parseVisualliFile(await response.text());
|
|
123
|
+
}
|
|
124
|
+
function parseVisualliFromMongoDB(visualliJsonl) {
|
|
125
|
+
if (!visualliJsonl || typeof visualliJsonl !== "string") {
|
|
126
|
+
throw new VisualliParseError("Invalid visualli data: expected a JSONL string");
|
|
127
|
+
}
|
|
128
|
+
const trimmed = visualliJsonl.trim();
|
|
129
|
+
if (!trimmed) throw new VisualliParseError("Empty visualli data from MongoDB");
|
|
130
|
+
return parseVisualliFile(trimmed);
|
|
131
|
+
}
|
|
132
|
+
function loadVisualliFileFromFile(file) {
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
const reader = new FileReader();
|
|
135
|
+
reader.onload = (e) => {
|
|
136
|
+
try {
|
|
137
|
+
resolve(parseVisualliFile(e.target?.result));
|
|
138
|
+
} catch (err) {
|
|
139
|
+
reject(err);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
reader.onerror = () => reject(new Error("Failed to read file"));
|
|
143
|
+
reader.readAsText(file);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function getChildLayers(doc, nodeId) {
|
|
147
|
+
const result = [];
|
|
148
|
+
for (const layer of doc.layers.values()) {
|
|
149
|
+
if (layer.parentNodeId === nodeId) result.push(layer);
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
function countLayersBeneath(doc, nodeId, visited = /* @__PURE__ */ new Set()) {
|
|
154
|
+
if (visited.has(nodeId)) return 0;
|
|
155
|
+
visited.add(nodeId);
|
|
156
|
+
const children = getChildLayers(doc, nodeId);
|
|
157
|
+
if (children.length === 0) return 0;
|
|
158
|
+
let maxDepth = 0;
|
|
159
|
+
for (const layer of children) {
|
|
160
|
+
let depth = 1;
|
|
161
|
+
for (const node of layer.nodes) {
|
|
162
|
+
depth = Math.max(depth, 1 + countLayersBeneath(doc, node.id, visited));
|
|
163
|
+
}
|
|
164
|
+
maxDepth = Math.max(maxDepth, depth);
|
|
165
|
+
}
|
|
166
|
+
return maxDepth;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/layout/circularLayout.ts
|
|
170
|
+
function applyCircularLayout(nodes, options = {}) {
|
|
171
|
+
const {
|
|
172
|
+
radiusPercentage = 0.135,
|
|
173
|
+
containerWidth = 2e3,
|
|
174
|
+
containerHeight = 2e3,
|
|
175
|
+
centerX = 0,
|
|
176
|
+
centerY = 0
|
|
177
|
+
} = options;
|
|
178
|
+
if (nodes.length === 0) return nodes;
|
|
179
|
+
if (nodes.length === 1) {
|
|
180
|
+
nodes[0].x = centerX;
|
|
181
|
+
nodes[0].y = centerY;
|
|
182
|
+
return nodes;
|
|
183
|
+
}
|
|
184
|
+
const radius = Math.min(containerWidth, containerHeight) * radiusPercentage;
|
|
185
|
+
const startAngle = nodes.length === 2 ? 0 : -Math.PI / 2;
|
|
186
|
+
const angleStep = 2 * Math.PI / nodes.length;
|
|
187
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
188
|
+
const angle = startAngle + i * angleStep;
|
|
189
|
+
nodes[i].x = centerX + radius * Math.cos(angle);
|
|
190
|
+
nodes[i].y = centerY + radius * Math.sin(angle);
|
|
191
|
+
}
|
|
192
|
+
return nodes;
|
|
193
|
+
}
|
|
194
|
+
function calculateMinimumRadius(nodeCount, nodeWidth = 200, nodePadding = 150) {
|
|
195
|
+
if (nodeCount <= 1) return 0;
|
|
196
|
+
const angleStep = 2 * Math.PI / nodeCount;
|
|
197
|
+
const minChordLength = nodeWidth + nodePadding;
|
|
198
|
+
return minChordLength / (2 * Math.sin(angleStep / 2));
|
|
199
|
+
}
|
|
200
|
+
function calculateOptimalRadiusPercentage(nodeCount, containerWidth = 2e3, containerHeight = 2e3, nodeWidth = 200, nodePadding = 120) {
|
|
201
|
+
const minRadius = calculateMinimumRadius(nodeCount, nodeWidth, nodePadding);
|
|
202
|
+
const minDimension = Math.min(containerWidth, containerHeight);
|
|
203
|
+
return Math.min(0.45, Math.max(0.135, minRadius / minDimension));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/layout/linearLayout.ts
|
|
207
|
+
function applyLinearHorizontalLayout(nodes, options = {}) {
|
|
208
|
+
const { nodeWidth = 200, hGap = 180, centerX = 0, centerY = 0 } = options;
|
|
209
|
+
if (nodes.length === 0) return nodes;
|
|
210
|
+
if (nodes.length === 1) {
|
|
211
|
+
nodes[0].x = centerX;
|
|
212
|
+
nodes[0].y = centerY;
|
|
213
|
+
return nodes;
|
|
214
|
+
}
|
|
215
|
+
const spacing = nodeWidth + hGap;
|
|
216
|
+
const totalWidth = (nodes.length - 1) * spacing;
|
|
217
|
+
const startX = centerX - totalWidth / 2;
|
|
218
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
219
|
+
nodes[i].x = startX + i * spacing;
|
|
220
|
+
nodes[i].y = centerY;
|
|
221
|
+
}
|
|
222
|
+
return nodes;
|
|
223
|
+
}
|
|
224
|
+
function applyLinearVerticalLayout(nodes, options = {}) {
|
|
225
|
+
const { nodeHeight = 80, vGap = 220, centerX = 0, centerY = 0 } = options;
|
|
226
|
+
if (nodes.length === 0) return nodes;
|
|
227
|
+
if (nodes.length === 1) {
|
|
228
|
+
nodes[0].x = centerX;
|
|
229
|
+
nodes[0].y = centerY;
|
|
230
|
+
return nodes;
|
|
231
|
+
}
|
|
232
|
+
const spacing = nodeHeight + vGap;
|
|
233
|
+
const totalHeight = (nodes.length - 1) * spacing;
|
|
234
|
+
const startY = centerY - totalHeight / 2;
|
|
235
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
236
|
+
nodes[i].x = centerX;
|
|
237
|
+
nodes[i].y = startY + i * spacing;
|
|
238
|
+
}
|
|
239
|
+
return nodes;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/parser/visualliConverter.ts
|
|
243
|
+
function doNodesOverlap(n1, n2, padding = 20) {
|
|
244
|
+
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);
|
|
245
|
+
}
|
|
246
|
+
function resolveNodeOverlaps(nodes, maxIterations = 10) {
|
|
247
|
+
const padding = 150;
|
|
248
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
249
|
+
let any = false;
|
|
250
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
251
|
+
for (let j = i + 1; j < nodes.length; j++) {
|
|
252
|
+
const n1 = nodes[i];
|
|
253
|
+
const n2 = nodes[j];
|
|
254
|
+
if (!doNodesOverlap(n1, n2, padding)) continue;
|
|
255
|
+
any = true;
|
|
256
|
+
const dx = n2.x - n1.x;
|
|
257
|
+
const dy = n2.y - n1.y;
|
|
258
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
259
|
+
if (dist < 1) {
|
|
260
|
+
n2.x += n2.width / 2 + padding;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const minDist = (n1.width + n2.width) / 2 + padding;
|
|
264
|
+
if (dist < minDist) {
|
|
265
|
+
const push = (minDist - dist) / 2;
|
|
266
|
+
n1.x -= dx / dist * push;
|
|
267
|
+
n1.y -= dy / dist * push;
|
|
268
|
+
n2.x += dx / dist * push;
|
|
269
|
+
n2.y += dy / dist * push;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (!any) break;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
var COLOR_PALETTE = [
|
|
277
|
+
"#12C7D3",
|
|
278
|
+
"#325E8C",
|
|
279
|
+
"#8A70A6",
|
|
280
|
+
"#F54A57",
|
|
281
|
+
"#FF6C4D",
|
|
282
|
+
"#F28C16",
|
|
283
|
+
"#FFD347",
|
|
284
|
+
"#12C7D3",
|
|
285
|
+
"#7F7F7F",
|
|
286
|
+
"#8D8D8D",
|
|
287
|
+
"#12C7D3"
|
|
288
|
+
];
|
|
289
|
+
function getRandomColorForNode(nodeId) {
|
|
290
|
+
let hash = 0;
|
|
291
|
+
for (let i = 0; i < nodeId.length; i++) {
|
|
292
|
+
hash = nodeId.charCodeAt(i) + ((hash << 5) - hash);
|
|
293
|
+
}
|
|
294
|
+
const index = Math.abs(hash) % COLOR_PALETTE.length;
|
|
295
|
+
return COLOR_PALETTE[index];
|
|
296
|
+
}
|
|
297
|
+
function applyFormation(nodes, formation) {
|
|
298
|
+
if (nodes.length === 0) return;
|
|
299
|
+
if (nodes.length === 1) {
|
|
300
|
+
nodes[0].x = 0;
|
|
301
|
+
nodes[0].y = 0;
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (formation === "linear-horizontal" || formation === "linear") {
|
|
305
|
+
applyLinearHorizontalLayout(nodes, { centerX: 0, centerY: 0 });
|
|
306
|
+
} else if (formation === "linear-vertical") {
|
|
307
|
+
applyLinearVerticalLayout(nodes, { centerX: 0, centerY: 0 });
|
|
308
|
+
} else {
|
|
309
|
+
const r = Math.max(250, nodes.length * 70);
|
|
310
|
+
const step = 2 * Math.PI / nodes.length;
|
|
311
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
312
|
+
nodes[i].x = r * Math.cos(i * step);
|
|
313
|
+
nodes[i].y = r * Math.sin(i * step);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function containerBBox(nodes, padding) {
|
|
318
|
+
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
319
|
+
for (const n of nodes) {
|
|
320
|
+
minX = Math.min(minX, n.x - n.width / 2);
|
|
321
|
+
maxX = Math.max(maxX, n.x + n.width / 2);
|
|
322
|
+
minY = Math.min(minY, n.y - n.height / 2);
|
|
323
|
+
maxY = Math.max(maxY, n.y + n.height / 2);
|
|
324
|
+
}
|
|
325
|
+
return { width: maxX - minX + padding * 2, height: maxY - minY + padding * 2 };
|
|
326
|
+
}
|
|
327
|
+
function proxyLinearH(proxies, gap = 180) {
|
|
328
|
+
const total = proxies.reduce((s, p) => s + p.width, 0) + gap * (proxies.length - 1);
|
|
329
|
+
let x = -total / 2;
|
|
330
|
+
for (const p of proxies) {
|
|
331
|
+
p.x = x + p.width / 2;
|
|
332
|
+
p.y = 0;
|
|
333
|
+
x += p.width + gap;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
function proxyLinearV(proxies, gap = 180) {
|
|
337
|
+
const total = proxies.reduce((s, p) => s + p.height, 0) + gap * (proxies.length - 1);
|
|
338
|
+
let y = -total / 2;
|
|
339
|
+
for (const p of proxies) {
|
|
340
|
+
p.x = 0;
|
|
341
|
+
p.y = y + p.height / 2;
|
|
342
|
+
y += p.height + gap;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
function proxyRadial(proxies, radius = 500) {
|
|
346
|
+
if (proxies.length === 1) {
|
|
347
|
+
proxies[0].x = 0;
|
|
348
|
+
proxies[0].y = 0;
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const startAngle = proxies.length === 2 ? 0 : -Math.PI / 2;
|
|
352
|
+
const step = 2 * Math.PI / proxies.length;
|
|
353
|
+
for (let i = 0; i < proxies.length; i++) {
|
|
354
|
+
const angle = startAngle + i * step;
|
|
355
|
+
proxies[i].x = radius * Math.cos(angle);
|
|
356
|
+
proxies[i].y = radius * Math.sin(angle);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function calculateNodeWidth(title) {
|
|
360
|
+
return Math.max(200, title.length * 8 + 40);
|
|
361
|
+
}
|
|
362
|
+
function makeFlatNode(nodeId, label, summary, layer, color, branchCount, x = 0, y = 0) {
|
|
363
|
+
return {
|
|
364
|
+
id: nodeId,
|
|
365
|
+
parentId: layer.parentNodeId ?? null,
|
|
366
|
+
x,
|
|
367
|
+
y,
|
|
368
|
+
level: layer.level,
|
|
369
|
+
title: label,
|
|
370
|
+
description: summary,
|
|
371
|
+
color,
|
|
372
|
+
width: calculateNodeWidth(label),
|
|
373
|
+
height: 80,
|
|
374
|
+
isExpanded: branchCount > 0,
|
|
375
|
+
branchCount,
|
|
376
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
377
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function convertLayerWithContainers(layer, doc) {
|
|
381
|
+
const PADDING = 80;
|
|
382
|
+
const flatNodes = [];
|
|
383
|
+
for (const node of layer.nodes) {
|
|
384
|
+
const label = Array.isArray(node.data.label) ? node.data.label.join(" ") : node.data.label || "Untitled";
|
|
385
|
+
const branchCount = countLayersBeneath(doc, node.id);
|
|
386
|
+
flatNodes.push(
|
|
387
|
+
makeFlatNode(
|
|
388
|
+
node.id,
|
|
389
|
+
label,
|
|
390
|
+
node.data.summary || "",
|
|
391
|
+
layer,
|
|
392
|
+
node.data.color || getRandomColorForNode(node.id),
|
|
393
|
+
branchCount
|
|
394
|
+
)
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
const byId = new Map(flatNodes.map((n) => [n.id, n]));
|
|
398
|
+
const containerNodeIds = /* @__PURE__ */ new Set();
|
|
399
|
+
const containerGroups = /* @__PURE__ */ new Map();
|
|
400
|
+
for (const container of layer.containers) {
|
|
401
|
+
const group = container.nodes.map((id) => byId.get(id)).filter((n) => !!n);
|
|
402
|
+
if (!group.length) continue;
|
|
403
|
+
container.nodes.forEach((id) => containerNodeIds.add(id));
|
|
404
|
+
const formation = container.data?.["formation"] ?? "radial";
|
|
405
|
+
applyFormation(group, formation);
|
|
406
|
+
containerGroups.set(container.id, group);
|
|
407
|
+
}
|
|
408
|
+
const proxies = [];
|
|
409
|
+
for (const node of layer.nodes) {
|
|
410
|
+
if (!containerNodeIds.has(node.id)) {
|
|
411
|
+
const nodeWidth = calculateNodeWidth(node.data.label);
|
|
412
|
+
proxies.push({ id: node.id, x: 0, y: 0, width: nodeWidth, height: 80 });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
for (const container of layer.containers) {
|
|
416
|
+
const group = containerGroups.get(container.id);
|
|
417
|
+
if (!group?.length) continue;
|
|
418
|
+
const bbox = containerBBox(group, PADDING);
|
|
419
|
+
proxies.push({ id: `__c__${container.id}`, x: 0, y: 0, width: bbox.width, height: bbox.height });
|
|
420
|
+
}
|
|
421
|
+
const layout = layer.layout || "radial";
|
|
422
|
+
if (layout === "linear-horizontal") proxyLinearH(proxies, 180);
|
|
423
|
+
else if (layout === "linear-vertical") proxyLinearV(proxies, 180);
|
|
424
|
+
else proxyRadial(proxies, 500);
|
|
425
|
+
for (const proxy of proxies) {
|
|
426
|
+
if (proxy.id.startsWith("__c__")) {
|
|
427
|
+
const group = containerGroups.get(proxy.id.slice(5));
|
|
428
|
+
group?.forEach((n) => {
|
|
429
|
+
n.x += proxy.x;
|
|
430
|
+
n.y += proxy.y;
|
|
431
|
+
});
|
|
432
|
+
} else {
|
|
433
|
+
const fn = byId.get(proxy.id);
|
|
434
|
+
if (fn) {
|
|
435
|
+
fn.x = proxy.x;
|
|
436
|
+
fn.y = proxy.y;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
resolveNodeOverlaps(flatNodes);
|
|
441
|
+
return flatNodes;
|
|
442
|
+
}
|
|
443
|
+
function convertLayerToFlatNodes(layer, doc) {
|
|
444
|
+
if ((layer.containers ?? []).length > 0) {
|
|
445
|
+
return convertLayerWithContainers(layer, doc);
|
|
446
|
+
}
|
|
447
|
+
const flatNodes = [];
|
|
448
|
+
for (const node of layer.nodes) {
|
|
449
|
+
const label = Array.isArray(node.data.label) ? node.data.label.join(" ") : node.data.label || "Untitled";
|
|
450
|
+
const branchCount = countLayersBeneath(doc, node.id);
|
|
451
|
+
flatNodes.push(
|
|
452
|
+
makeFlatNode(
|
|
453
|
+
node.id,
|
|
454
|
+
label,
|
|
455
|
+
node.data.summary || "",
|
|
456
|
+
layer,
|
|
457
|
+
node.data.color || getRandomColorForNode(node.id),
|
|
458
|
+
branchCount,
|
|
459
|
+
0,
|
|
460
|
+
0
|
|
461
|
+
)
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
if (flatNodes.length > 0) {
|
|
465
|
+
const layout = layer.layout || "radial";
|
|
466
|
+
if (layout === "linear-horizontal") {
|
|
467
|
+
applyLinearHorizontalLayout(flatNodes, { centerX: 0, centerY: 0 });
|
|
468
|
+
} else if (layout === "linear-vertical") {
|
|
469
|
+
applyLinearVerticalLayout(flatNodes, { centerX: 0, centerY: 0 });
|
|
470
|
+
} else {
|
|
471
|
+
const pct = calculateOptimalRadiusPercentage(flatNodes.length, 2e3, 2e3, 200, 30);
|
|
472
|
+
applyCircularLayout(flatNodes, {
|
|
473
|
+
radiusPercentage: pct,
|
|
474
|
+
containerWidth: 2e3,
|
|
475
|
+
containerHeight: 2e3,
|
|
476
|
+
centerX: 0,
|
|
477
|
+
centerY: 0
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
resolveNodeOverlaps(flatNodes);
|
|
482
|
+
return flatNodes;
|
|
483
|
+
}
|
|
484
|
+
function convertVisualliToFlatNodes(doc) {
|
|
485
|
+
const map = /* @__PURE__ */ new Map();
|
|
486
|
+
for (const layer of doc.layers.values()) {
|
|
487
|
+
for (const node of convertLayerToFlatNodes(layer, doc)) {
|
|
488
|
+
map.set(node.id, node);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
for (const node of map.values()) {
|
|
492
|
+
node.childrenIds = [];
|
|
493
|
+
for (const candidate of map.values()) {
|
|
494
|
+
if (candidate.parentId === node.id) node.childrenIds.push(candidate.id);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return map;
|
|
498
|
+
}
|
|
499
|
+
function getNodesForLayer(doc, layerId) {
|
|
500
|
+
const layer = doc.layers.get(layerId);
|
|
501
|
+
return layer ? convertLayerToFlatNodes(layer, doc) : [];
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/parser/mindmapUtils.ts
|
|
505
|
+
function flattenNodes(nodes) {
|
|
506
|
+
const result = [];
|
|
507
|
+
const traverse = (list) => {
|
|
508
|
+
for (const n of list) {
|
|
509
|
+
result.push(n);
|
|
510
|
+
if (n.children) traverse(n.children);
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
traverse(nodes);
|
|
514
|
+
return result;
|
|
515
|
+
}
|
|
516
|
+
function getVisibleNodes(nodes, zoom, focusedNode) {
|
|
517
|
+
const flat = flattenNodes(nodes);
|
|
518
|
+
if (focusedNode) {
|
|
519
|
+
const focused = flat.find((n) => n.id === focusedNode);
|
|
520
|
+
if (focused) {
|
|
521
|
+
return focused.children ? [focused, ...focused.children] : [focused];
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (zoom <= 0.7) return flat.filter((n) => n.level === 0);
|
|
525
|
+
const maxLevel = Math.floor((zoom - 0.7) / 0.05);
|
|
526
|
+
return flat.filter((n) => n.level <= maxLevel);
|
|
527
|
+
}
|
|
528
|
+
function getNodeConnections(nodes) {
|
|
529
|
+
const flat = flattenNodes(nodes);
|
|
530
|
+
const result = [];
|
|
531
|
+
for (const n of flat) {
|
|
532
|
+
if (!n.parent) continue;
|
|
533
|
+
const parent = flat.find((p) => p.id === n.parent);
|
|
534
|
+
if (parent) result.push({ from: parent, to: n, label: n.relationshipLabel });
|
|
535
|
+
}
|
|
536
|
+
return result;
|
|
537
|
+
}
|
|
538
|
+
function getTopLevelConnections(nodes, topLevelConnections) {
|
|
539
|
+
const flat = flattenNodes(nodes);
|
|
540
|
+
const result = [];
|
|
541
|
+
for (const conn of topLevelConnections) {
|
|
542
|
+
const from = flat.find((n) => n.id === conn.from);
|
|
543
|
+
const to = flat.find((n) => n.id === conn.to);
|
|
544
|
+
if (from && to) result.push({ from, to, label: conn.label ?? "" });
|
|
545
|
+
}
|
|
546
|
+
return result;
|
|
547
|
+
}
|
|
548
|
+
function calculateDistance(x1, y1, x2, y2) {
|
|
549
|
+
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// src/constants/design.ts
|
|
553
|
+
var BRAND_COLORS = {
|
|
554
|
+
primary: {
|
|
555
|
+
50: "#EFF6FF",
|
|
556
|
+
100: "#DBEAFE",
|
|
557
|
+
200: "#BFDBFE",
|
|
558
|
+
300: "#93C5FD",
|
|
559
|
+
400: "#60A5FA",
|
|
560
|
+
500: "#3B82F6",
|
|
561
|
+
600: "#2563EB",
|
|
562
|
+
700: "#1D4ED8",
|
|
563
|
+
800: "#1E40AF",
|
|
564
|
+
900: "#1E3A8A"
|
|
565
|
+
},
|
|
566
|
+
secondary: {
|
|
567
|
+
50: "#F0FDF4",
|
|
568
|
+
100: "#DCFCE7",
|
|
569
|
+
200: "#BBF7D0",
|
|
570
|
+
300: "#86EFAC",
|
|
571
|
+
400: "#4ADE80",
|
|
572
|
+
500: "#10B981",
|
|
573
|
+
600: "#059669",
|
|
574
|
+
700: "#047857",
|
|
575
|
+
800: "#065F46",
|
|
576
|
+
900: "#064E3B"
|
|
577
|
+
},
|
|
578
|
+
accent: {
|
|
579
|
+
purple: "#8B5CF6",
|
|
580
|
+
cyan: "#06B6D4",
|
|
581
|
+
sky: "#0EA5E9",
|
|
582
|
+
lime: "#84CC16",
|
|
583
|
+
amber: "#F59E0B",
|
|
584
|
+
red: "#EF4444"
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
var LEVEL_COLORS = {
|
|
588
|
+
level0: BRAND_COLORS.primary[500],
|
|
589
|
+
level1: BRAND_COLORS.primary[400],
|
|
590
|
+
level2: BRAND_COLORS.primary[300],
|
|
591
|
+
level3: BRAND_COLORS.primary[200],
|
|
592
|
+
level4: BRAND_COLORS.primary[300],
|
|
593
|
+
level5: BRAND_COLORS.primary[400],
|
|
594
|
+
level6: BRAND_COLORS.primary[500],
|
|
595
|
+
level7: BRAND_COLORS.primary[600],
|
|
596
|
+
level8: BRAND_COLORS.primary[700]
|
|
597
|
+
};
|
|
598
|
+
var LEVEL_COLOR_ARRAY = [
|
|
599
|
+
LEVEL_COLORS.level0,
|
|
600
|
+
LEVEL_COLORS.level1,
|
|
601
|
+
LEVEL_COLORS.level2,
|
|
602
|
+
LEVEL_COLORS.level3,
|
|
603
|
+
LEVEL_COLORS.level4,
|
|
604
|
+
LEVEL_COLORS.level5,
|
|
605
|
+
LEVEL_COLORS.level6,
|
|
606
|
+
LEVEL_COLORS.level7,
|
|
607
|
+
LEVEL_COLORS.level8
|
|
608
|
+
];
|
|
609
|
+
var SEMANTIC_COLORS = {
|
|
610
|
+
success: BRAND_COLORS.secondary[500],
|
|
611
|
+
error: BRAND_COLORS.accent.red,
|
|
612
|
+
warning: BRAND_COLORS.accent.amber,
|
|
613
|
+
info: BRAND_COLORS.primary[500]
|
|
614
|
+
};
|
|
615
|
+
var LAYOUT_SPACING = {
|
|
616
|
+
nodeSpacing: 200,
|
|
617
|
+
levelSpacing: 150,
|
|
618
|
+
containerPadding: 20,
|
|
619
|
+
gridSize: 50
|
|
620
|
+
};
|
|
621
|
+
function getColorForLevel(level) {
|
|
622
|
+
return LEVEL_COLOR_ARRAY[level % LEVEL_COLOR_ARRAY.length];
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// src/parser/configUtils.ts
|
|
626
|
+
function createMindMapConfig(nodes, topLevelConnections, title = "Untitled Mindmap") {
|
|
627
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
628
|
+
return {
|
|
629
|
+
metadata: {
|
|
630
|
+
title,
|
|
631
|
+
description: `Interactive mindmap with ${nodes.length} nodes`,
|
|
632
|
+
version: "1.0.0",
|
|
633
|
+
created: now,
|
|
634
|
+
lastModified: now
|
|
635
|
+
},
|
|
636
|
+
nodes,
|
|
637
|
+
topLevelConnections,
|
|
638
|
+
settings: {
|
|
639
|
+
defaultColors: {
|
|
640
|
+
level0: LEVEL_COLORS.level0,
|
|
641
|
+
level1: LEVEL_COLORS.level1,
|
|
642
|
+
level2: LEVEL_COLORS.level2,
|
|
643
|
+
level3: LEVEL_COLORS.level3
|
|
644
|
+
},
|
|
645
|
+
layout: {
|
|
646
|
+
nodeSpacing: LAYOUT_SPACING.nodeSpacing,
|
|
647
|
+
levelSpacing: LAYOUT_SPACING.levelSpacing
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
function generateId(prefix, level, index) {
|
|
653
|
+
return `${prefix}-l${level}-${index}`;
|
|
654
|
+
}
|
|
655
|
+
function generateLevelNodes(parentId, level, maxLevels, xOffset = 0, yOffset = 0) {
|
|
656
|
+
if (level >= maxLevels) return [];
|
|
657
|
+
const count = 5;
|
|
658
|
+
const levelSpacing = 200;
|
|
659
|
+
const nodeSpacing = 300;
|
|
660
|
+
const nodes = [];
|
|
661
|
+
for (let i = 0; i < count; i++) {
|
|
662
|
+
const nodeId = parentId ? generateId(`${parentId}-${i}`, level, i) : generateId("root", level, i);
|
|
663
|
+
const x = xOffset + (i - (count - 1) / 2) * nodeSpacing;
|
|
664
|
+
const y = yOffset + level * levelSpacing;
|
|
665
|
+
const node = {
|
|
666
|
+
id: nodeId,
|
|
667
|
+
title: `Level ${level} Node ${i + 1}`,
|
|
668
|
+
level,
|
|
669
|
+
x,
|
|
670
|
+
y,
|
|
671
|
+
color: getColorForLevel(level),
|
|
672
|
+
relationshipLabel: level > 0 ? "child" : void 0,
|
|
673
|
+
parent: parentId ?? void 0
|
|
674
|
+
};
|
|
675
|
+
const children = generateLevelNodes(nodeId, level + 1, maxLevels, x, y + levelSpacing);
|
|
676
|
+
if (children.length > 0) node.children = children;
|
|
677
|
+
nodes.push(node);
|
|
678
|
+
}
|
|
679
|
+
return nodes;
|
|
680
|
+
}
|
|
681
|
+
function generateSampleConfig(maxLevels = 9) {
|
|
682
|
+
const nodes = generateLevelNodes(null, 0, maxLevels, 0, 0);
|
|
683
|
+
const topLevelConnections = nodes.slice(0, -1).map((n, i) => ({
|
|
684
|
+
from: n.id,
|
|
685
|
+
to: nodes[i + 1].id,
|
|
686
|
+
label: "related to"
|
|
687
|
+
}));
|
|
688
|
+
return {
|
|
689
|
+
metadata: {
|
|
690
|
+
id: `mindmap-${Date.now()}`,
|
|
691
|
+
title: "Sample Mind Map",
|
|
692
|
+
description: "A sample mind map",
|
|
693
|
+
version: "1.0.0",
|
|
694
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
695
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
696
|
+
},
|
|
697
|
+
nodes,
|
|
698
|
+
topLevelConnections,
|
|
699
|
+
settings: {
|
|
700
|
+
defaultColors: {
|
|
701
|
+
level0: LEVEL_COLORS.level0,
|
|
702
|
+
level1: LEVEL_COLORS.level1,
|
|
703
|
+
level2: LEVEL_COLORS.level2,
|
|
704
|
+
level3: LEVEL_COLORS.level3,
|
|
705
|
+
level4: LEVEL_COLORS.level4,
|
|
706
|
+
level5: LEVEL_COLORS.level5,
|
|
707
|
+
level6: LEVEL_COLORS.level6,
|
|
708
|
+
level7: LEVEL_COLORS.level7,
|
|
709
|
+
level8: LEVEL_COLORS.level8
|
|
710
|
+
},
|
|
711
|
+
layout: {
|
|
712
|
+
nodeSpacing: LAYOUT_SPACING.nodeSpacing,
|
|
713
|
+
levelSpacing: LAYOUT_SPACING.levelSpacing
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
719
|
+
0 && (module.exports = {
|
|
720
|
+
VisualliParseError,
|
|
721
|
+
calculateDistance,
|
|
722
|
+
convertLayerToFlatNodes,
|
|
723
|
+
convertVisualliToFlatNodes,
|
|
724
|
+
countLayersBeneath,
|
|
725
|
+
createMindMapConfig,
|
|
726
|
+
fetchAndParseVisualli,
|
|
727
|
+
flattenNodes,
|
|
728
|
+
generateSampleConfig,
|
|
729
|
+
getChildLayers,
|
|
730
|
+
getNodeConnections,
|
|
731
|
+
getNodesForLayer,
|
|
732
|
+
getTopLevelConnections,
|
|
733
|
+
getVisibleNodes,
|
|
734
|
+
loadVisualliFileFromFile,
|
|
735
|
+
parseVisualliFile,
|
|
736
|
+
parseVisualliFromMongoDB,
|
|
737
|
+
resolveNodeOverlaps
|
|
738
|
+
});
|
|
739
|
+
//# sourceMappingURL=index.cjs.map
|