@visualli/core 0.1.5 → 0.1.7
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 +7 -2
- 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 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/parser/index.ts","../../src/parser/visualliParser.ts","../../src/layout/circularLayout.ts","../../src/layout/linearLayout.ts","../../src/parser/visualliConverter.ts","../../src/parser/mindmapUtils.ts","../../src/constants/design.ts","../../src/parser/configUtils.ts"],"sourcesContent":["export * from './visualliParser.js';\nexport * from './visualliConverter.js';\nexport * from './mindmapUtils.js';\nexport * from './configUtils.js';\n","// ─── .visualli File Parser ────────────────────────────────────────────────────\n//\n// Reads JSONL (JSON Lines) format and parses into a structured VisualliDocument.\n\nimport type { VisualliDocument } from '../types/document.js';\nimport type { VisualliMeta } from '../types/meta.js';\nimport type { VisualliLayer } from '../types/layer.js';\nimport type { Layer } from '../types/schema.js';\n\n/**\n * Convert schema Layer to VisualliLayer by ensuring required arrays exist.\n */\nfunction toVisualliLayer(schemaLayer: Layer): VisualliLayer {\n return {\n type: 'layer',\n id: schemaLayer.id,\n level: schemaLayer.level,\n parentLayerId: schemaLayer.parentLayerId,\n parentNodeId: schemaLayer.parentNodeId,\n layout: schemaLayer.layout,\n nodes: schemaLayer.nodes ?? [],\n connections: schemaLayer.connections ?? [],\n containers: schemaLayer.containers ?? [],\n };\n}\n\nexport class VisualliParseError extends Error {\n constructor(message: string, public readonly lineNumber?: number) {\n super(message);\n this.name = 'VisualliParseError';\n }\n}\n\n/**\n * Parse a .visualli file content (JSONL format) into a VisualliDocument.\n *\n * @throws VisualliParseError on malformed input\n */\nexport function parseVisualliFile(content: string): VisualliDocument {\n const lines = content.trim().split('\\n');\n\n const doc: VisualliDocument = {\n meta: null as unknown as VisualliMeta,\n layers: new Map(),\n layersByLevel: new Map(),\n rootLayer: null,\n };\n\n let lineNumber = 0;\n\n for (const line of lines) {\n lineNumber++;\n if (!line.trim()) continue;\n\n let obj: Record<string, unknown>;\n try {\n obj = JSON.parse(line) as Record<string, unknown>;\n } catch (err) {\n throw new VisualliParseError(\n `Failed to parse JSON at line ${lineNumber}: ${err}`,\n lineNumber,\n );\n }\n\n if (!obj['type']) {\n throw new VisualliParseError(\n `Missing 'type' field at line ${lineNumber}`,\n lineNumber,\n );\n }\n\n switch (obj['type']) {\n case 'meta':\n doc.meta = obj as unknown as VisualliMeta;\n break;\n\n case 'layer': {\n // Convert schema Layer to VisualliLayer\n const schemaLayer = obj as unknown as Layer;\n const layer = toVisualliLayer(schemaLayer);\n \n doc.layers.set(layer.id, layer);\n\n if (!doc.layersByLevel.has(layer.level)) {\n doc.layersByLevel.set(layer.level, []);\n }\n doc.layersByLevel.get(layer.level)!.push(layer);\n\n if (layer.level === 0) {\n doc.rootLayer = layer;\n }\n break;\n }\n\n default:\n // Unknown type — silently skip\n break;\n }\n }\n\n if (!doc.meta) throw new VisualliParseError('Missing required meta section');\n if (!doc.rootLayer) throw new VisualliParseError('Missing root layer (level 0)');\n\n return doc;\n}\n\nexport async function fetchAndParseVisualli(url: string): Promise<VisualliDocument> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n return parseVisualliFile(await response.text());\n}\n\n/**\n * Parse .visualli JSONL data as returned from the MongoDB `visualli` field.\n *\n * @throws VisualliParseError\n */\nexport function parseVisualliFromMongoDB(visualliJsonl: string): VisualliDocument {\n if (!visualliJsonl || typeof visualliJsonl !== 'string') {\n throw new VisualliParseError('Invalid visualli data: expected a JSONL string');\n }\n const trimmed = visualliJsonl.trim();\n if (!trimmed) throw new VisualliParseError('Empty visualli data from MongoDB');\n return parseVisualliFile(trimmed);\n}\n\n/**\n * Parse a .visualli file from a browser `File` object.\n * (Browser-only – requires `FileReader`.)\n */\nexport function loadVisualliFileFromFile(file: File): Promise<VisualliDocument> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = e => {\n try {\n resolve(parseVisualliFile(e.target?.result as string));\n } catch (err) {\n reject(err);\n }\n };\n reader.onerror = () => reject(new Error('Failed to read file'));\n reader.readAsText(file);\n });\n}\n\n// ── Tree Helpers ──────────────────────────────────────────────────────────────\n\n/** Return all layers whose `parentNodeId` matches the given node ID. */\nexport function getChildLayers(\n doc: VisualliDocument,\n nodeId: string,\n): VisualliLayer[] {\n const result: VisualliLayer[] = [];\n for (const layer of doc.layers.values()) {\n if (layer.parentNodeId === nodeId) result.push(layer);\n }\n return result;\n}\n\n/**\n * Count the maximum depth of layers beneath a node (its \"magnitude\").\n * Returns 0 when the node has no child layers.\n */\nexport function countLayersBeneath(\n doc: VisualliDocument,\n nodeId: string,\n visited = new Set<string>(),\n): number {\n if (visited.has(nodeId)) return 0;\n visited.add(nodeId);\n\n const children = getChildLayers(doc, nodeId);\n if (children.length === 0) return 0;\n\n let maxDepth = 0;\n for (const layer of children) {\n let depth = 1;\n for (const node of layer.nodes) {\n depth = Math.max(depth, 1 + countLayersBeneath(doc, node.id, visited));\n }\n maxDepth = Math.max(maxDepth, depth);\n }\n return maxDepth;\n}\n","// ─── Circular Layout Algorithm ────────────────────────────────────────────────\n//\n// Positions nodes in a uniform circle with equal angular spacing.\n// PATTERN : Uniform circular distribution (polar coordinates)\n// SPACING : Equal angular intervals (2π/n)\n// ORIGIN : Configurable center (default 0, 0)\n// RADIUS : Configurable percentage of container (default 13.5%)\n\nimport type { FlatNode } from '../types/mindmap.js';\n\nexport interface CircularLayoutOptions {\n /** Radius as a fraction of the container's minimum dimension (0–1). Default: 0.135 */\n radiusPercentage?: number;\n /** Container width used to calculate absolute radius. Default: 2000 */\n containerWidth?: number;\n /** Container height used to calculate absolute radius. Default: 2000 */\n containerHeight?: number;\n /** World-space X of the circle centre. Default: 0 */\n centerX?: number;\n /** World-space Y of the circle centre. Default: 0 */\n centerY?: number;\n}\n\n/**\n * Apply circular layout to a set of nodes.\n * Mutates the `x` / `y` properties of each node and returns the same array.\n */\nexport function applyCircularLayout(\n nodes: FlatNode[],\n options: CircularLayoutOptions = {},\n): FlatNode[] {\n const {\n radiusPercentage = 0.135,\n containerWidth = 2000,\n containerHeight = 2000,\n centerX = 0,\n centerY = 0,\n } = options;\n\n if (nodes.length === 0) return nodes;\n\n if (nodes.length === 1) {\n nodes[0].x = centerX;\n nodes[0].y = centerY;\n return nodes;\n }\n\n const radius = Math.min(containerWidth, containerHeight) * radiusPercentage;\n\n // n=2 → horizontal; n≥3 → start at 12 o'clock\n const startAngle = nodes.length === 2 ? 0 : -Math.PI / 2;\n const angleStep = (2 * Math.PI) / nodes.length;\n\n for (let i = 0; i < nodes.length; i++) {\n const angle = startAngle + i * angleStep;\n nodes[i].x = centerX + radius * Math.cos(angle);\n nodes[i].y = centerY + radius * Math.sin(angle);\n }\n\n return nodes;\n}\n\n/**\n * Calculate the minimum radius needed to prevent node boxes from overlapping.\n *\n * Uses the chord-length formula: `chord = 2r · sin(θ/2)`, solved for `r`.\n */\nexport function calculateMinimumRadius(\n nodeCount: number,\n nodeWidth = 200,\n nodePadding = 150,\n): number {\n if (nodeCount <= 1) return 0;\n const angleStep = (2 * Math.PI) / nodeCount;\n const minChordLength = nodeWidth + nodePadding;\n return minChordLength / (2 * Math.sin(angleStep / 2));\n}\n\n/**\n * Calculate the optimal radius percentage for a given node count,\n * ensuring sufficient spacing for edge labels.\n *\n * @returns A value in [0.135, 0.45]\n */\nexport function calculateOptimalRadiusPercentage(\n nodeCount: number,\n containerWidth = 2000,\n containerHeight = 2000,\n nodeWidth = 200,\n nodePadding = 120,\n): number {\n const minRadius = calculateMinimumRadius(nodeCount, nodeWidth, nodePadding);\n const minDimension = Math.min(containerWidth, containerHeight);\n return Math.min(0.45, Math.max(0.135, minRadius / minDimension));\n}\n","// ─── Linear Layout Algorithms ─────────────────────────────────────────────────\n//\n// Positions nodes in a straight line without overlap, with enough gap between\n// node edges for edge-label text to render cleanly.\n//\n// linear-horizontal → left-to-right along X-axis\n// linear-vertical → top-to-bottom along Y-axis\n\nimport type { FlatNode } from '../types/mindmap.js';\n\nexport interface LinearLayoutOptions {\n /** Logical node width (px). Default: 200 */\n nodeWidth?: number;\n /** Logical node height (px). Default: 80 */\n nodeHeight?: number;\n /** Gap between node edges for horizontal layout (px). Default: 180 */\n hGap?: number;\n /** Gap between node edges for vertical layout (px). Default: 220 */\n vGap?: number;\n /** World X of the layout midpoint. Default: 0 */\n centerX?: number;\n /** World Y of the layout midpoint. Default: 0 */\n centerY?: number;\n}\n\n/**\n * Arrange nodes in a horizontal row (shared Y, varying X).\n * Row is centred on (`centerX`, `centerY`).\n */\nexport function applyLinearHorizontalLayout(\n nodes: FlatNode[],\n options: LinearLayoutOptions = {},\n): FlatNode[] {\n const { nodeWidth = 200, hGap = 180, centerX = 0, centerY = 0 } = options;\n\n if (nodes.length === 0) return nodes;\n\n if (nodes.length === 1) {\n nodes[0].x = centerX;\n nodes[0].y = centerY;\n return nodes;\n }\n\n const spacing = nodeWidth + hGap;\n const totalWidth = (nodes.length - 1) * spacing;\n const startX = centerX - totalWidth / 2;\n\n for (let i = 0; i < nodes.length; i++) {\n nodes[i].x = startX + i * spacing;\n nodes[i].y = centerY;\n }\n\n return nodes;\n}\n\n/**\n * Arrange nodes in a vertical column (shared X, varying Y).\n * Column is centred on (`centerX`, `centerY`).\n */\nexport function applyLinearVerticalLayout(\n nodes: FlatNode[],\n options: LinearLayoutOptions = {},\n): FlatNode[] {\n const { nodeHeight = 80, vGap = 220, centerX = 0, centerY = 0 } = options;\n\n if (nodes.length === 0) return nodes;\n\n if (nodes.length === 1) {\n nodes[0].x = centerX;\n nodes[0].y = centerY;\n return nodes;\n }\n\n const spacing = nodeHeight + vGap;\n const totalHeight = (nodes.length - 1) * spacing;\n const startY = centerY - totalHeight / 2;\n\n for (let i = 0; i < nodes.length; i++) {\n nodes[i].x = centerX;\n nodes[i].y = startY + i * spacing;\n }\n\n return nodes;\n}\n","// ─── .visualli → FlatNode Converter ──────────────────────────────────────────\n//\n// Transforms the layer-based .visualli format into the flat Map<id, FlatNode>\n// structure consumed by the canvas renderer.\n\nimport type { VisualliDocument } from '../types/document.js';\nimport type { VisualliLayer } from '../types/layer.js';\nimport type { FlatNode, NodeMap } from '../types/mindmap.js';\nimport { countLayersBeneath } from './visualliParser.js';\nimport { applyCircularLayout, calculateOptimalRadiusPercentage } from '../layout/circularLayout.js';\nimport { applyLinearHorizontalLayout, applyLinearVerticalLayout } from '../layout/linearLayout.js';\n\n// ── Overlap Resolution ────────────────────────────────────────────────────────\n\nfunction doNodesOverlap(n1: FlatNode, n2: FlatNode, padding = 20): boolean {\n return !(\n n1.x + n1.width / 2 + padding < n2.x - n2.width / 2 - padding ||\n n1.x - n1.width / 2 - padding > n2.x + n2.width / 2 + padding ||\n n1.y + n1.height / 2 + padding < n2.y - n2.height / 2 - padding ||\n n1.y - n1.height / 2 - padding > n2.y + n2.height / 2 + padding\n );\n}\n\n/** Iteratively push overlapping nodes apart using symmetric force separation. */\nexport function resolveNodeOverlaps(nodes: FlatNode[], maxIterations = 10): void {\n const padding = 150;\n\n for (let iter = 0; iter < maxIterations; iter++) {\n let any = false;\n for (let i = 0; i < nodes.length; i++) {\n for (let j = i + 1; j < nodes.length; j++) {\n const n1 = nodes[i];\n const n2 = nodes[j];\n if (!doNodesOverlap(n1, n2, padding)) continue;\n\n any = true;\n const dx = n2.x - n1.x;\n const dy = n2.y - n1.y;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < 1) {\n n2.x += n2.width / 2 + padding;\n continue;\n }\n\n const minDist = (n1.width + n2.width) / 2 + padding;\n if (dist < minDist) {\n const push = (minDist - dist) / 2;\n n1.x -= (dx / dist) * push;\n n1.y -= (dy / dist) * push;\n n2.x += (dx / dist) * push;\n n2.y += (dy / dist) * push;\n }\n }\n }\n if (!any) break;\n }\n}\n\n// ── Color Helpers ─────────────────────────────────────────────────────────────\n\nconst COLOR_PALETTE = [\n '#12C7D3', '#325E8C', '#8A70A6', '#F54A57', '#FF6C4D',\n '#F28C16', '#FFD347', '#12C7D3', '#7F7F7F', '#8D8D8D', '#12C7D3',\n];\n\n/**\n * Get a deterministic random color from palette based on node ID\n */\nfunction getRandomColorForNode(nodeId: string): string {\n // Simple hash function to convert string to number\n let hash = 0;\n for (let i = 0; i < nodeId.length; i++) {\n hash = nodeId.charCodeAt(i) + ((hash << 5) - hash);\n }\n \n // Use absolute value and modulo to get palette index\n const index = Math.abs(hash) % COLOR_PALETTE.length;\n return COLOR_PALETTE[index];\n}\n\n// ── Container-formation Layout ────────────────────────────────────────────────\n\ninterface Proxy { id: string; x: number; y: number; width: number; height: number }\n\nfunction applyFormation(nodes: FlatNode[], formation: string): void {\n if (nodes.length === 0) return;\n if (nodes.length === 1) { nodes[0].x = 0; nodes[0].y = 0; return; }\n if (formation === 'linear-horizontal' || formation === 'linear') {\n applyLinearHorizontalLayout(nodes, { centerX: 0, centerY: 0 });\n } else if (formation === 'linear-vertical') {\n applyLinearVerticalLayout(nodes, { centerX: 0, centerY: 0 });\n } else {\n const r = Math.max(250, nodes.length * 70);\n const step = (2 * Math.PI) / nodes.length;\n for (let i = 0; i < nodes.length; i++) {\n nodes[i].x = r * Math.cos(i * step);\n nodes[i].y = r * Math.sin(i * step);\n }\n }\n}\n\nfunction containerBBox(nodes: FlatNode[], padding: number): { width: number; height: number } {\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const n of nodes) {\n minX = Math.min(minX, n.x - n.width / 2);\n maxX = Math.max(maxX, n.x + n.width / 2);\n minY = Math.min(minY, n.y - n.height / 2);\n maxY = Math.max(maxY, n.y + n.height / 2);\n }\n return { width: maxX - minX + padding * 2, height: maxY - minY + padding * 2 };\n}\n\nfunction proxyLinearH(proxies: Proxy[], gap = 180): void {\n const total = proxies.reduce((s, p) => s + p.width, 0) + gap * (proxies.length - 1);\n let x = -total / 2;\n for (const p of proxies) { p.x = x + p.width / 2; p.y = 0; x += p.width + gap; }\n}\n\nfunction proxyLinearV(proxies: Proxy[], gap = 180): void {\n const total = proxies.reduce((s, p) => s + p.height, 0) + gap * (proxies.length - 1);\n let y = -total / 2;\n for (const p of proxies) { p.x = 0; p.y = y + p.height / 2; y += p.height + gap; }\n}\n\nfunction proxyRadial(proxies: Proxy[], radius = 500): void {\n if (proxies.length === 1) { proxies[0].x = 0; proxies[0].y = 0; return; }\n // Start at top (12 o'clock) for n>=3, horizontal for n=2 (matches circular layout)\n const startAngle = proxies.length === 2 ? 0 : -Math.PI / 2;\n const step = (2 * Math.PI) / proxies.length;\n for (let i = 0; i < proxies.length; i++) {\n const angle = startAngle + i * step;\n proxies[i].x = radius * Math.cos(angle);\n proxies[i].y = radius * Math.sin(angle);\n }\n}\n\n// ── Layer Conversion ──────────────────────────────────────────────────────────\n\n/**\n * Calculate dynamic node width based on title length.\n * Formula matches visualli.ai: max(200, title.length * 8 + 40)\n */\nfunction calculateNodeWidth(title: string): number {\n return Math.max(200, title.length * 8 + 40);\n}\n\nfunction makeFlatNode(\n nodeId: string,\n label: string,\n summary: string,\n layer: VisualliLayer,\n color: string,\n branchCount: number,\n x = 0,\n y = 0,\n): FlatNode {\n return {\n id: nodeId,\n parentId: layer.parentNodeId ?? null,\n x,\n y,\n level: layer.level,\n title: label,\n description: summary,\n color,\n width: calculateNodeWidth(label),\n height: 80,\n isExpanded: branchCount > 0,\n branchCount,\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n}\n\nfunction convertLayerWithContainers(\n layer: VisualliLayer,\n doc: VisualliDocument,\n): FlatNode[] {\n const PADDING = 80;\n const flatNodes: FlatNode[] = [];\n\n for (const node of layer.nodes) {\n const label = Array.isArray(node.data.label)\n ? (node.data.label as string[]).join(' ')\n : (node.data.label || 'Untitled');\n const branchCount = countLayersBeneath(doc, node.id);\n flatNodes.push(\n makeFlatNode(\n node.id, label, node.data.summary || '', layer,\n node.data.color || getRandomColorForNode(node.id), branchCount,\n ),\n );\n }\n\n const byId = new Map(flatNodes.map((n: FlatNode) => [n.id, n]));\n const containerNodeIds = new Set<string>();\n const containerGroups = new Map<string, FlatNode[]>();\n\n for (const container of layer.containers) {\n const group = container.nodes.map((id: string) => byId.get(id)).filter((n: FlatNode | undefined): n is FlatNode => !!n);\n if (!group.length) continue;\n container.nodes.forEach((id: string) => containerNodeIds.add(id));\n const formation = ((container.data as unknown as Record<string, unknown> | undefined)?.['formation'] as string | undefined) ?? 'radial';\n applyFormation(group, formation);\n containerGroups.set(container.id, group);\n }\n\n const proxies: Proxy[] = [];\n for (const node of layer.nodes) {\n if (!containerNodeIds.has(node.id)) {\n const nodeWidth = calculateNodeWidth(node.data.label);\n proxies.push({ id: node.id, x: 0, y: 0, width: nodeWidth, height: 80 });\n }\n }\n for (const container of layer.containers) {\n const group = containerGroups.get(container.id);\n if (!group?.length) continue;\n const bbox = containerBBox(group, PADDING);\n proxies.push({ id: `__c__${container.id}`, x: 0, y: 0, width: bbox.width, height: bbox.height });\n }\n\n const layout = layer.layout || 'radial';\n if (layout === 'linear-horizontal') proxyLinearH(proxies, 180);\n else if (layout === 'linear-vertical') proxyLinearV(proxies, 180);\n else proxyRadial(proxies, 500);\n\n for (const proxy of proxies) {\n if (proxy.id.startsWith('__c__')) {\n const group = containerGroups.get(proxy.id.slice(5));\n group?.forEach(n => { n.x += proxy.x; n.y += proxy.y; });\n } else {\n const fn = byId.get(proxy.id);\n if (fn) { fn.x = proxy.x; fn.y = proxy.y; }\n }\n }\n\n resolveNodeOverlaps(flatNodes);\n\n return flatNodes;\n}\n\n/**\n * Convert a single layer to an array of FlatNode objects.\n * Layout algorithm is determined by `layer.layout` (default: radial).\n */\nexport function convertLayerToFlatNodes(\n layer: VisualliLayer,\n doc: VisualliDocument,\n): FlatNode[] {\n if ((layer.containers ?? []).length > 0) {\n return convertLayerWithContainers(layer, doc);\n }\n\n const flatNodes: FlatNode[] = [];\n\n for (const node of layer.nodes) {\n const label = Array.isArray(node.data.label)\n ? (node.data.label as string[]).join(' ')\n : (node.data.label || 'Untitled');\n const branchCount = countLayersBeneath(doc, node.id);\n flatNodes.push(\n makeFlatNode(\n node.id, label, node.data.summary || '', layer,\n node.data.color || getRandomColorForNode(node.id), branchCount,\n 0, 0,\n ),\n );\n }\n\n if (flatNodes.length > 0) {\n const layout = layer.layout || 'radial';\n if (layout === 'linear-horizontal') {\n applyLinearHorizontalLayout(flatNodes, { centerX: 0, centerY: 0 });\n } else if (layout === 'linear-vertical') {\n applyLinearVerticalLayout(flatNodes, { centerX: 0, centerY: 0 });\n } else {\n const pct = calculateOptimalRadiusPercentage(flatNodes.length, 2000, 2000, 200, 30);\n applyCircularLayout(flatNodes, {\n radiusPercentage: pct,\n containerWidth: 2000,\n containerHeight: 2000,\n centerX: 0,\n centerY: 0,\n });\n }\n }\n\n resolveNodeOverlaps(flatNodes);\n\n return flatNodes;\n}\n\n/**\n * Convert an entire .visualli document to a flat NodeMap.\n * All layers are converted and a children-index is built for O(1) tree traversal.\n */\nexport function convertVisualliToFlatNodes(doc: VisualliDocument): NodeMap {\n const map: NodeMap = new Map();\n\n for (const layer of doc.layers.values()) {\n for (const node of convertLayerToFlatNodes(layer, doc)) {\n map.set(node.id, node);\n }\n }\n\n // Build children index\n for (const node of map.values()) {\n node.childrenIds = [];\n for (const candidate of map.values()) {\n if (candidate.parentId === node.id) node.childrenIds.push(candidate.id);\n }\n }\n\n return map;\n}\n\n/**\n * Get flat nodes for a specific layer only.\n *\n * @param doc - Parsed .visualli document\n * @param layerId - Layer ID to extract\n * @returns FlatNode array, or empty array if layer not found\n */\nexport function getNodesForLayer(doc: VisualliDocument, layerId: string): FlatNode[] {\n const layer = doc.layers.get(layerId);\n return layer ? convertLayerToFlatNodes(layer, doc) : [];\n}\n","// ─── Mindmap Tree Utilities ───────────────────────────────────────────────────\n\nimport type { MindMapNode, TopLevelConnection } from '../types/mindmap.js';\n\n/** Flatten a nested MindMapNode tree into a depth-first array. */\nexport function flattenNodes(nodes: MindMapNode[]): MindMapNode[] {\n const result: MindMapNode[] = [];\n const traverse = (list: MindMapNode[]) => {\n for (const n of list) {\n result.push(n);\n if (n.children) traverse(n.children);\n }\n };\n traverse(nodes);\n return result;\n}\n\n/**\n * Return nodes visible at the given zoom level.\n *\n * At lower zoom values only top-level nodes are shown; each 5% zoom increment\n * reveals one additional hierarchy level.\n */\nexport function getVisibleNodes(\n nodes: MindMapNode[],\n zoom: number,\n focusedNode?: string,\n): MindMapNode[] {\n const flat = flattenNodes(nodes);\n\n if (focusedNode) {\n const focused = flat.find(n => n.id === focusedNode);\n if (focused) {\n return focused.children ? [focused, ...focused.children] : [focused];\n }\n }\n\n // Map zoom to max visible level (level 0 at ≤70%, +1 level per 5% increment)\n if (zoom <= 0.70) return flat.filter(n => n.level === 0);\n const maxLevel = Math.floor((zoom - 0.70) / 0.05);\n return flat.filter(n => n.level <= maxLevel);\n}\n\n/** Build parent→child connection pairs from the node tree. */\nexport function getNodeConnections(\n nodes: MindMapNode[],\n): Array<{ from: MindMapNode; to: MindMapNode; label?: string }> {\n const flat = flattenNodes(nodes);\n const result: Array<{ from: MindMapNode; to: MindMapNode; label?: string }> = [];\n for (const n of flat) {\n if (!n.parent) continue;\n const parent = flat.find(p => p.id === n.parent);\n if (parent) result.push({ from: parent, to: n, label: n.relationshipLabel });\n }\n return result;\n}\n\n/** Resolve top-level cross-connections to node pairs. */\nexport function getTopLevelConnections(\n nodes: MindMapNode[],\n topLevelConnections: TopLevelConnection[],\n): Array<{ from: MindMapNode; to: MindMapNode; label: string }> {\n const flat = flattenNodes(nodes);\n const result: Array<{ from: MindMapNode; to: MindMapNode; label: string }> = [];\n for (const conn of topLevelConnections) {\n const from = flat.find(n => n.id === conn.from);\n const to = flat.find(n => n.id === conn.to);\n if (from && to) result.push({ from, to, label: conn.label ?? '' });\n }\n return result;\n}\n\n/** Euclidean distance between two world-space points. */\nexport function calculateDistance(x1: number, y1: number, x2: number, y2: number): number {\n return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);\n}\n","// ─── Design System Constants ──────────────────────────────────────────────────\n//\n// Single source of truth for all color tokens, typography, spacing, and\n// visual design constants used across the SDK and consuming apps.\n//\n// ## Color Priority\n// 1. Data file values (node.color, layer.backgroundColor)\n// 2. Fall back to these constants\n\n// ── Visualli Design System v2 ─────────────────────────────────────────────────\n\nexport const DS_COLORS = {\n light: {\n bgApp: '#F0EDE6',\n bgSurface: '#FAF8F4',\n bgInput: '#FFFFFF',\n border: '#DDD9D0',\n borderDivider: '#E8E4DC',\n primary: '#1B2D4F',\n primaryHover: '#243B68',\n textPrimary: '#1A1A18',\n textSecondary: '#6B6860',\n textMuted: '#747270',\n textOnPrimary: '#FAF8F4',\n hoverItem: 'rgba(27,45,79,0.07)',\n focusRing: 'rgba(27,45,79,0.40)',\n btnMuted: '#8E8C88',\n },\n dark: {\n bgApp: '#141412',\n bgSurface: '#1C1C1A',\n bgInput: '#262622',\n border: '#333330',\n borderDivider: '#2A2A28',\n primary: '#BB532D',\n primaryHover: '#CC6440',\n textPrimary: '#F0EDE6',\n textSecondary: '#B0ABA3',\n textMuted: '#8E8C88',\n textOnPrimary: '#FAF8F4',\n hoverItem: 'rgba(198,94,56,0.12)',\n focusRing: 'rgba(198,94,56,0.50)',\n btnMuted: '#4A4845',\n },\n} as const;\n\nexport const DS_TYPOGRAPHY = {\n fontDisplay: \"'Nunito', sans-serif\",\n fontBody: \"'Nunito Sans', sans-serif\",\n logo: { size: '20px', weight: 800, letterSpacing: '0.04em' },\n heading: { size: '16px', weight: 700, letterSpacing: '-0.2px' },\n cta: { size: '11px', weight: 800, letterSpacing: '0.12em', transform: 'uppercase' as const },\n body: { size: '13px', weight: 400 },\n input: { size: '13px', weight: 300, style: 'italic' as const },\n search: { size: '12px', weight: 400 },\n username: { size: '13px', weight: 600 },\n avatar: { size: '11px', weight: 700 },\n footer: { size: '12px', weight: 400 },\n empty: { size: '11px', weight: 300, style: 'italic' as const },\n} as const;\n\nexport const DS_RADII = {\n sidebar: 16,\n input: 8,\n cta: 7,\n item: 6,\n swatch: 10,\n} as const;\n\n// ── Brand Colors ──────────────────────────────────────────────────────────────\n\nexport const BRAND_COLORS = {\n primary: {\n 50: '#EFF6FF',\n 100: '#DBEAFE',\n 200: '#BFDBFE',\n 300: '#93C5FD',\n 400: '#60A5FA',\n 500: '#3B82F6',\n 600: '#2563EB',\n 700: '#1D4ED8',\n 800: '#1E40AF',\n 900: '#1E3A8A',\n },\n secondary: {\n 50: '#F0FDF4',\n 100: '#DCFCE7',\n 200: '#BBF7D0',\n 300: '#86EFAC',\n 400: '#4ADE80',\n 500: '#10B981',\n 600: '#059669',\n 700: '#047857',\n 800: '#065F46',\n 900: '#064E3B',\n },\n accent: {\n purple: '#8B5CF6',\n cyan: '#06B6D4',\n sky: '#0EA5E9',\n lime: '#84CC16',\n amber: '#F59E0B',\n red: '#EF4444',\n },\n} as const;\n\n// ── Level Colors ──────────────────────────────────────────────────────────────\n\nexport const LEVEL_COLORS = {\n level0: BRAND_COLORS.primary[500],\n level1: BRAND_COLORS.primary[400],\n level2: BRAND_COLORS.primary[300],\n level3: BRAND_COLORS.primary[200],\n level4: BRAND_COLORS.primary[300],\n level5: BRAND_COLORS.primary[400],\n level6: BRAND_COLORS.primary[500],\n level7: BRAND_COLORS.primary[600],\n level8: BRAND_COLORS.primary[700],\n} as const;\n\nexport const LEVEL_COLOR_ARRAY = [\n LEVEL_COLORS.level0,\n LEVEL_COLORS.level1,\n LEVEL_COLORS.level2,\n LEVEL_COLORS.level3,\n LEVEL_COLORS.level4,\n LEVEL_COLORS.level5,\n LEVEL_COLORS.level6,\n LEVEL_COLORS.level7,\n LEVEL_COLORS.level8,\n] as const;\n\nexport const PARENT_FALLBACK_COLORS = [\n '#12C7D3', '#325E8C', '#8A70A6', '#F54A57', '#FF6C4D',\n '#F28C16', '#FFD347', '#7F7F7F', '#8D8D8D',\n] as const;\n\nexport const SEMANTIC_COLORS = {\n success: BRAND_COLORS.secondary[500],\n error: BRAND_COLORS.accent.red,\n warning: BRAND_COLORS.accent.amber,\n info: BRAND_COLORS.primary[500],\n} as const;\n\n// ── Theme Colors ──────────────────────────────────────────────────────────────\n\nexport const THEME_COLORS = {\n light: {\n background: { primary: '#FAF8F4', secondary: '#F0EDE6', tertiary: '#FFFFFF' },\n text: { primary: '#1A1A18', secondary: '#6B6860', tertiary: '#747270' },\n border: { primary: '#DDD9D0', secondary: '#E8E4DC' },\n },\n dark: {\n background: { primary: '#1C1C1A', secondary: '#141412', tertiary: '#262622' },\n text: { primary: '#F0EDE6', secondary: '#B0ABA3', tertiary: '#8E8C88' },\n border: { primary: '#333330', secondary: '#2A2A28' },\n },\n} as const;\n\n// ── Canvas Node Colors ────────────────────────────────────────────────────────\n\nexport const CANVAS_COLORS = {\n node: {\n border: '#FFFFFF',\n titleColor: '#1e1b4b',\n badgeBackground: '#FFC107',\n badgeStroke: '#fcd34d',\n },\n} as const;\n\n// ── Spacing ───────────────────────────────────────────────────────────────────\n\nexport const SPACING = {\n xs: 4,\n sm: 8,\n md: 16,\n lg: 24,\n xl: 32,\n '2xl': 48,\n '3xl': 64,\n '4xl': 96,\n} as const;\n\nexport const LAYOUT_SPACING = {\n nodeSpacing: 200,\n levelSpacing: 150,\n containerPadding: 20,\n gridSize: 50,\n} as const;\n\n// ── Typography ────────────────────────────────────────────────────────────────\n\nexport const FONTS = {\n primary: \"'Inter', sans-serif\",\n secondary: \"'Poppins', sans-serif\",\n mono: \"'Roboto Mono', monospace\",\n} as const;\n\nexport const FONT_SIZES = {\n xs: '0.75rem',\n sm: '0.875rem',\n base: '1rem',\n lg: '1.125rem',\n xl: '1.25rem',\n '2xl': '1.5rem',\n '3xl': '1.875rem',\n '4xl': '2.25rem',\n} as const;\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\n/** Get a level color, cycling back to level 0 for levels > 8. */\nexport function getColorForLevel(level: number): string {\n return LEVEL_COLOR_ARRAY[level % LEVEL_COLOR_ARRAY.length];\n}\n\n/**\n * Darken a hex color by reducing HSL lightness.\n * Returns a monochromatic darker version — used for border/stroke colors.\n * Falls back to the original string if parsing fails.\n */\nexport function darkenHexColor(hex: string, amount: number = 0.22): string {\n if (!hex || !hex.startsWith('#')) return hex;\n let r: number, g: number, b: number;\n if (hex.length === 4) {\n r = parseInt(hex[1] + hex[1], 16);\n g = parseInt(hex[2] + hex[2], 16);\n b = parseInt(hex[3] + hex[3], 16);\n } else if (hex.length === 7) {\n r = parseInt(hex.slice(1, 3), 16);\n g = parseInt(hex.slice(3, 5), 16);\n b = parseInt(hex.slice(5, 7), 16);\n } else {\n return hex;\n }\n if (isNaN(r) || isNaN(g) || isNaN(b)) return hex;\n const rn = r / 255, gn = g / 255, bn = b / 255;\n const cmax = Math.max(rn, gn, bn), cmin = Math.min(rn, gn, bn);\n const d = cmax - cmin;\n const l = (cmax + cmin) / 2;\n const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));\n let h = 0;\n if (d !== 0) {\n const seg = cmax === rn ? (gn - bn) / d : cmax === gn ? (bn - rn) / d + 2 : (rn - gn) / d + 4;\n h = ((seg * 60) + 360) % 360;\n }\n const newL = Math.max(0, l - amount);\n const c2 = (1 - Math.abs(2 * newL - 1)) * s;\n const x2 = c2 * (1 - Math.abs(((h / 60) % 2) - 1));\n const m2 = newL - c2 / 2;\n let r1 = 0, g1 = 0, b1 = 0;\n if (h < 60) { r1 = c2; g1 = x2; b1 = 0; }\n else if (h < 120) { r1 = x2; g1 = c2; b1 = 0; }\n else if (h < 180) { r1 = 0; g1 = c2; b1 = x2; }\n else if (h < 240) { r1 = 0; g1 = x2; b1 = c2; }\n else if (h < 300) { r1 = x2; g1 = 0; b1 = c2; }\n else { r1 = c2; g1 = 0; b1 = x2; }\n const toHex = (v: number) => Math.round((v + m2) * 255).toString(16).padStart(2, '0');\n return `#${toHex(r1)}${toHex(g1)}${toHex(b1)}`;\n}\n\nexport function getThemeBackground(\n isDark: boolean,\n variant: 'primary' | 'secondary' | 'tertiary' = 'primary',\n): string {\n return isDark ? THEME_COLORS.dark.background[variant] : THEME_COLORS.light.background[variant];\n}\n\nexport function getThemeText(\n isDark: boolean,\n variant: 'primary' | 'secondary' | 'tertiary' = 'primary',\n): string {\n return isDark ? THEME_COLORS.dark.text[variant] : THEME_COLORS.light.text[variant];\n}\n\nexport function getThemeBorder(\n isDark: boolean,\n variant: 'primary' | 'secondary' = 'primary',\n): string {\n return isDark ? THEME_COLORS.dark.border[variant] : THEME_COLORS.light.border[variant];\n}\n","// ─── MindMapConfig Utilities ──────────────────────────────────────────────────\n//\n// Helpers for creating and generating MindMapConfig objects (pure data, no UI).\n\nimport type { MindMapNode, MindMapConfig, TopLevelConnection } from '../types/mindmap.js';\nimport { LEVEL_COLORS, LAYOUT_SPACING, getColorForLevel } from '../constants/design.js';\n\nexport function createMindMapConfig(\n nodes: MindMapNode[],\n topLevelConnections: TopLevelConnection[],\n title = 'Untitled Mindmap',\n): MindMapConfig {\n const now = new Date().toISOString();\n return {\n metadata: {\n title,\n description: `Interactive mindmap with ${nodes.length} nodes`,\n version: '1.0.0',\n created: now,\n lastModified: now,\n },\n nodes,\n topLevelConnections,\n settings: {\n defaultColors: {\n level0: LEVEL_COLORS.level0,\n level1: LEVEL_COLORS.level1,\n level2: LEVEL_COLORS.level2,\n level3: LEVEL_COLORS.level3,\n },\n layout: {\n nodeSpacing: LAYOUT_SPACING.nodeSpacing,\n levelSpacing: LAYOUT_SPACING.levelSpacing,\n },\n },\n };\n}\n\n// ── Sample Data Generator ─────────────────────────────────────────────────────\n\nfunction generateId(prefix: string, level: number, index: number): string {\n return `${prefix}-l${level}-${index}`;\n}\n\nfunction generateLevelNodes(\n parentId: string | null,\n level: number,\n maxLevels: number,\n xOffset = 0,\n yOffset = 0,\n): MindMapNode[] {\n if (level >= maxLevels) return [];\n\n const count = 5;\n const levelSpacing = 200;\n const nodeSpacing = 300;\n const nodes: MindMapNode[] = [];\n\n for (let i = 0; i < count; i++) {\n const nodeId = parentId\n ? generateId(`${parentId}-${i}`, level, i)\n : generateId('root', level, i);\n\n const x = xOffset + (i - (count - 1) / 2) * nodeSpacing;\n const y = yOffset + level * levelSpacing;\n\n const node: MindMapNode = {\n id: nodeId,\n title: `Level ${level} Node ${i + 1}`,\n level,\n x,\n y,\n color: getColorForLevel(level),\n relationshipLabel: level > 0 ? 'child' : undefined,\n parent: parentId ?? undefined,\n };\n\n const children = generateLevelNodes(nodeId, level + 1, maxLevels, x, y + levelSpacing);\n if (children.length > 0) node.children = children;\n\n nodes.push(node);\n }\n\n return nodes;\n}\n\n/**\n * Generate a sample MindMapConfig with `maxLevels` of hierarchy.\n * Useful for testing and demos.\n */\nexport function generateSampleConfig(maxLevels = 9): MindMapConfig {\n const nodes = generateLevelNodes(null, 0, maxLevels, 0, 0);\n\n const topLevelConnections: TopLevelConnection[] = nodes.slice(0, -1).map((n, i) => ({\n from: n.id,\n to: nodes[i + 1].id,\n label: 'related to',\n }));\n\n return {\n metadata: {\n id: `mindmap-${Date.now()}`,\n title: 'Sample Mind Map',\n description: 'A sample mind map',\n version: '1.0.0',\n created: new Date().toISOString(),\n lastModified: new Date().toISOString(),\n },\n nodes,\n topLevelConnections,\n settings: {\n defaultColors: {\n level0: LEVEL_COLORS.level0,\n level1: LEVEL_COLORS.level1,\n level2: LEVEL_COLORS.level2,\n level3: LEVEL_COLORS.level3,\n level4: LEVEL_COLORS.level4,\n level5: LEVEL_COLORS.level5,\n level6: LEVEL_COLORS.level6,\n level7: LEVEL_COLORS.level7,\n level8: LEVEL_COLORS.level8,\n },\n layout: {\n nodeSpacing: LAYOUT_SPACING.nodeSpacing,\n levelSpacing: LAYOUT_SPACING.levelSpacing,\n },\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { V as VisualliDocument, a as VisualliLayer } from '../document-B3hnNr-F.cjs';
|
|
2
|
+
import { F as FlatNode, d as NodeMap, c as MindMapNode, T as TopLevelConnection, a as MindMapConfig } from '../mindmap-DWS0WZT_.cjs';
|
|
3
|
+
import '@visualli/bindings';
|
|
4
|
+
|
|
5
|
+
declare class VisualliParseError extends Error {
|
|
6
|
+
readonly lineNumber?: number | undefined;
|
|
7
|
+
constructor(message: string, lineNumber?: number | undefined);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Parse a .visualli file content (JSONL format) into a VisualliDocument.
|
|
11
|
+
*
|
|
12
|
+
* @throws VisualliParseError on malformed input
|
|
13
|
+
*/
|
|
14
|
+
declare function parseVisualliFile(content: string): VisualliDocument;
|
|
15
|
+
declare function fetchAndParseVisualli(url: string): Promise<VisualliDocument>;
|
|
16
|
+
/**
|
|
17
|
+
* Parse .visualli JSONL data as returned from the MongoDB `visualli` field.
|
|
18
|
+
*
|
|
19
|
+
* @throws VisualliParseError
|
|
20
|
+
*/
|
|
21
|
+
declare function parseVisualliFromMongoDB(visualliJsonl: string): VisualliDocument;
|
|
22
|
+
/**
|
|
23
|
+
* Parse a .visualli file from a browser `File` object.
|
|
24
|
+
* (Browser-only – requires `FileReader`.)
|
|
25
|
+
*/
|
|
26
|
+
declare function loadVisualliFileFromFile(file: File): Promise<VisualliDocument>;
|
|
27
|
+
/** Return all layers whose `parentNodeId` matches the given node ID. */
|
|
28
|
+
declare function getChildLayers(doc: VisualliDocument, nodeId: string): VisualliLayer[];
|
|
29
|
+
/**
|
|
30
|
+
* Count the maximum depth of layers beneath a node (its "magnitude").
|
|
31
|
+
* Returns 0 when the node has no child layers.
|
|
32
|
+
*/
|
|
33
|
+
declare function countLayersBeneath(doc: VisualliDocument, nodeId: string, visited?: Set<string>): number;
|
|
34
|
+
|
|
35
|
+
/** Iteratively push overlapping nodes apart using symmetric force separation. */
|
|
36
|
+
declare function resolveNodeOverlaps(nodes: FlatNode[], maxIterations?: number): void;
|
|
37
|
+
/**
|
|
38
|
+
* Convert a single layer to an array of FlatNode objects.
|
|
39
|
+
* Layout algorithm is determined by `layer.layout` (default: radial).
|
|
40
|
+
*/
|
|
41
|
+
declare function convertLayerToFlatNodes(layer: VisualliLayer, doc: VisualliDocument): FlatNode[];
|
|
42
|
+
/**
|
|
43
|
+
* Convert an entire .visualli document to a flat NodeMap.
|
|
44
|
+
* All layers are converted and a children-index is built for O(1) tree traversal.
|
|
45
|
+
*/
|
|
46
|
+
declare function convertVisualliToFlatNodes(doc: VisualliDocument): NodeMap;
|
|
47
|
+
/**
|
|
48
|
+
* Get flat nodes for a specific layer only.
|
|
49
|
+
*
|
|
50
|
+
* @param doc - Parsed .visualli document
|
|
51
|
+
* @param layerId - Layer ID to extract
|
|
52
|
+
* @returns FlatNode array, or empty array if layer not found
|
|
53
|
+
*/
|
|
54
|
+
declare function getNodesForLayer(doc: VisualliDocument, layerId: string): FlatNode[];
|
|
55
|
+
|
|
56
|
+
/** Flatten a nested MindMapNode tree into a depth-first array. */
|
|
57
|
+
declare function flattenNodes(nodes: MindMapNode[]): MindMapNode[];
|
|
58
|
+
/**
|
|
59
|
+
* Return nodes visible at the given zoom level.
|
|
60
|
+
*
|
|
61
|
+
* At lower zoom values only top-level nodes are shown; each 5% zoom increment
|
|
62
|
+
* reveals one additional hierarchy level.
|
|
63
|
+
*/
|
|
64
|
+
declare function getVisibleNodes(nodes: MindMapNode[], zoom: number, focusedNode?: string): MindMapNode[];
|
|
65
|
+
/** Build parent→child connection pairs from the node tree. */
|
|
66
|
+
declare function getNodeConnections(nodes: MindMapNode[]): Array<{
|
|
67
|
+
from: MindMapNode;
|
|
68
|
+
to: MindMapNode;
|
|
69
|
+
label?: string;
|
|
70
|
+
}>;
|
|
71
|
+
/** Resolve top-level cross-connections to node pairs. */
|
|
72
|
+
declare function getTopLevelConnections(nodes: MindMapNode[], topLevelConnections: TopLevelConnection[]): Array<{
|
|
73
|
+
from: MindMapNode;
|
|
74
|
+
to: MindMapNode;
|
|
75
|
+
label: string;
|
|
76
|
+
}>;
|
|
77
|
+
/** Euclidean distance between two world-space points. */
|
|
78
|
+
declare function calculateDistance(x1: number, y1: number, x2: number, y2: number): number;
|
|
79
|
+
|
|
80
|
+
declare function createMindMapConfig(nodes: MindMapNode[], topLevelConnections: TopLevelConnection[], title?: string): MindMapConfig;
|
|
81
|
+
/**
|
|
82
|
+
* Generate a sample MindMapConfig with `maxLevels` of hierarchy.
|
|
83
|
+
* Useful for testing and demos.
|
|
84
|
+
*/
|
|
85
|
+
declare function generateSampleConfig(maxLevels?: number): MindMapConfig;
|
|
86
|
+
|
|
87
|
+
export { VisualliParseError, calculateDistance, convertLayerToFlatNodes, convertVisualliToFlatNodes, countLayersBeneath, createMindMapConfig, fetchAndParseVisualli, flattenNodes, generateSampleConfig, getChildLayers, getNodeConnections, getNodesForLayer, getTopLevelConnections, getVisibleNodes, loadVisualliFileFromFile, parseVisualliFile, parseVisualliFromMongoDB, resolveNodeOverlaps };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { V as VisualliDocument, a as VisualliLayer } from '../document-B3hnNr-F.js';
|
|
2
|
+
import { F as FlatNode, d as NodeMap, c as MindMapNode, T as TopLevelConnection, a as MindMapConfig } from '../mindmap-DWS0WZT_.js';
|
|
3
|
+
import '@visualli/bindings';
|
|
4
|
+
|
|
5
|
+
declare class VisualliParseError extends Error {
|
|
6
|
+
readonly lineNumber?: number | undefined;
|
|
7
|
+
constructor(message: string, lineNumber?: number | undefined);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Parse a .visualli file content (JSONL format) into a VisualliDocument.
|
|
11
|
+
*
|
|
12
|
+
* @throws VisualliParseError on malformed input
|
|
13
|
+
*/
|
|
14
|
+
declare function parseVisualliFile(content: string): VisualliDocument;
|
|
15
|
+
declare function fetchAndParseVisualli(url: string): Promise<VisualliDocument>;
|
|
16
|
+
/**
|
|
17
|
+
* Parse .visualli JSONL data as returned from the MongoDB `visualli` field.
|
|
18
|
+
*
|
|
19
|
+
* @throws VisualliParseError
|
|
20
|
+
*/
|
|
21
|
+
declare function parseVisualliFromMongoDB(visualliJsonl: string): VisualliDocument;
|
|
22
|
+
/**
|
|
23
|
+
* Parse a .visualli file from a browser `File` object.
|
|
24
|
+
* (Browser-only – requires `FileReader`.)
|
|
25
|
+
*/
|
|
26
|
+
declare function loadVisualliFileFromFile(file: File): Promise<VisualliDocument>;
|
|
27
|
+
/** Return all layers whose `parentNodeId` matches the given node ID. */
|
|
28
|
+
declare function getChildLayers(doc: VisualliDocument, nodeId: string): VisualliLayer[];
|
|
29
|
+
/**
|
|
30
|
+
* Count the maximum depth of layers beneath a node (its "magnitude").
|
|
31
|
+
* Returns 0 when the node has no child layers.
|
|
32
|
+
*/
|
|
33
|
+
declare function countLayersBeneath(doc: VisualliDocument, nodeId: string, visited?: Set<string>): number;
|
|
34
|
+
|
|
35
|
+
/** Iteratively push overlapping nodes apart using symmetric force separation. */
|
|
36
|
+
declare function resolveNodeOverlaps(nodes: FlatNode[], maxIterations?: number): void;
|
|
37
|
+
/**
|
|
38
|
+
* Convert a single layer to an array of FlatNode objects.
|
|
39
|
+
* Layout algorithm is determined by `layer.layout` (default: radial).
|
|
40
|
+
*/
|
|
41
|
+
declare function convertLayerToFlatNodes(layer: VisualliLayer, doc: VisualliDocument): FlatNode[];
|
|
42
|
+
/**
|
|
43
|
+
* Convert an entire .visualli document to a flat NodeMap.
|
|
44
|
+
* All layers are converted and a children-index is built for O(1) tree traversal.
|
|
45
|
+
*/
|
|
46
|
+
declare function convertVisualliToFlatNodes(doc: VisualliDocument): NodeMap;
|
|
47
|
+
/**
|
|
48
|
+
* Get flat nodes for a specific layer only.
|
|
49
|
+
*
|
|
50
|
+
* @param doc - Parsed .visualli document
|
|
51
|
+
* @param layerId - Layer ID to extract
|
|
52
|
+
* @returns FlatNode array, or empty array if layer not found
|
|
53
|
+
*/
|
|
54
|
+
declare function getNodesForLayer(doc: VisualliDocument, layerId: string): FlatNode[];
|
|
55
|
+
|
|
56
|
+
/** Flatten a nested MindMapNode tree into a depth-first array. */
|
|
57
|
+
declare function flattenNodes(nodes: MindMapNode[]): MindMapNode[];
|
|
58
|
+
/**
|
|
59
|
+
* Return nodes visible at the given zoom level.
|
|
60
|
+
*
|
|
61
|
+
* At lower zoom values only top-level nodes are shown; each 5% zoom increment
|
|
62
|
+
* reveals one additional hierarchy level.
|
|
63
|
+
*/
|
|
64
|
+
declare function getVisibleNodes(nodes: MindMapNode[], zoom: number, focusedNode?: string): MindMapNode[];
|
|
65
|
+
/** Build parent→child connection pairs from the node tree. */
|
|
66
|
+
declare function getNodeConnections(nodes: MindMapNode[]): Array<{
|
|
67
|
+
from: MindMapNode;
|
|
68
|
+
to: MindMapNode;
|
|
69
|
+
label?: string;
|
|
70
|
+
}>;
|
|
71
|
+
/** Resolve top-level cross-connections to node pairs. */
|
|
72
|
+
declare function getTopLevelConnections(nodes: MindMapNode[], topLevelConnections: TopLevelConnection[]): Array<{
|
|
73
|
+
from: MindMapNode;
|
|
74
|
+
to: MindMapNode;
|
|
75
|
+
label: string;
|
|
76
|
+
}>;
|
|
77
|
+
/** Euclidean distance between two world-space points. */
|
|
78
|
+
declare function calculateDistance(x1: number, y1: number, x2: number, y2: number): number;
|
|
79
|
+
|
|
80
|
+
declare function createMindMapConfig(nodes: MindMapNode[], topLevelConnections: TopLevelConnection[], title?: string): MindMapConfig;
|
|
81
|
+
/**
|
|
82
|
+
* Generate a sample MindMapConfig with `maxLevels` of hierarchy.
|
|
83
|
+
* Useful for testing and demos.
|
|
84
|
+
*/
|
|
85
|
+
declare function generateSampleConfig(maxLevels?: number): MindMapConfig;
|
|
86
|
+
|
|
87
|
+
export { VisualliParseError, calculateDistance, convertLayerToFlatNodes, convertVisualliToFlatNodes, countLayersBeneath, createMindMapConfig, fetchAndParseVisualli, flattenNodes, generateSampleConfig, getChildLayers, getNodeConnections, getNodesForLayer, getTopLevelConnections, getVisibleNodes, loadVisualliFileFromFile, parseVisualliFile, parseVisualliFromMongoDB, resolveNodeOverlaps };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VisualliParseError,
|
|
3
|
+
calculateDistance,
|
|
4
|
+
convertLayerToFlatNodes,
|
|
5
|
+
convertVisualliToFlatNodes,
|
|
6
|
+
countLayersBeneath,
|
|
7
|
+
createMindMapConfig,
|
|
8
|
+
fetchAndParseVisualli,
|
|
9
|
+
flattenNodes,
|
|
10
|
+
generateSampleConfig,
|
|
11
|
+
getChildLayers,
|
|
12
|
+
getNodeConnections,
|
|
13
|
+
getNodesForLayer,
|
|
14
|
+
getTopLevelConnections,
|
|
15
|
+
getVisibleNodes,
|
|
16
|
+
loadVisualliFileFromFile,
|
|
17
|
+
parseVisualliFile,
|
|
18
|
+
parseVisualliFromMongoDB,
|
|
19
|
+
resolveNodeOverlaps
|
|
20
|
+
} from "../chunk-6NXADJK2.js";
|
|
21
|
+
import "../chunk-G5H3P4YZ.js";
|
|
22
|
+
import "../chunk-GQMFBYLK.js";
|
|
23
|
+
export {
|
|
24
|
+
VisualliParseError,
|
|
25
|
+
calculateDistance,
|
|
26
|
+
convertLayerToFlatNodes,
|
|
27
|
+
convertVisualliToFlatNodes,
|
|
28
|
+
countLayersBeneath,
|
|
29
|
+
createMindMapConfig,
|
|
30
|
+
fetchAndParseVisualli,
|
|
31
|
+
flattenNodes,
|
|
32
|
+
generateSampleConfig,
|
|
33
|
+
getChildLayers,
|
|
34
|
+
getNodeConnections,
|
|
35
|
+
getNodesForLayer,
|
|
36
|
+
getTopLevelConnections,
|
|
37
|
+
getVisibleNodes,
|
|
38
|
+
loadVisualliFileFromFile,
|
|
39
|
+
parseVisualliFile,
|
|
40
|
+
parseVisualliFromMongoDB,
|
|
41
|
+
resolveNodeOverlaps
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,167 @@
|
|
|
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/performance/index.ts
|
|
21
|
+
var performance_exports = {};
|
|
22
|
+
__export(performance_exports, {
|
|
23
|
+
FPSMonitor: () => FPSMonitor,
|
|
24
|
+
MemoryMonitor: () => MemoryMonitor,
|
|
25
|
+
PerformanceProfiler: () => PerformanceProfiler
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(performance_exports);
|
|
28
|
+
|
|
29
|
+
// src/constants/performanceConstants.ts
|
|
30
|
+
var FPS_TARGET = 60;
|
|
31
|
+
var TARGET_FRAME_TIME = 1e3 / FPS_TARGET;
|
|
32
|
+
var FPS_SAMPLE_WINDOW = 60;
|
|
33
|
+
var MEMORY_CHECK_INTERVAL = 5e3;
|
|
34
|
+
|
|
35
|
+
// src/performance/performanceMonitor.ts
|
|
36
|
+
var FPSMonitor = class {
|
|
37
|
+
constructor() {
|
|
38
|
+
this.frameTimes = [];
|
|
39
|
+
this.lastTime = 0;
|
|
40
|
+
this.currentFPS = FPS_TARGET;
|
|
41
|
+
this.rafId = null;
|
|
42
|
+
}
|
|
43
|
+
start() {
|
|
44
|
+
if (this.rafId !== null) return;
|
|
45
|
+
const measure = (ts) => {
|
|
46
|
+
if (this.lastTime > 0) {
|
|
47
|
+
this.frameTimes.push(ts - this.lastTime);
|
|
48
|
+
if (this.frameTimes.length > FPS_SAMPLE_WINDOW) this.frameTimes.shift();
|
|
49
|
+
this.currentFPS = this.calc();
|
|
50
|
+
}
|
|
51
|
+
this.lastTime = ts;
|
|
52
|
+
this.rafId = requestAnimationFrame(measure);
|
|
53
|
+
};
|
|
54
|
+
this.rafId = requestAnimationFrame(measure);
|
|
55
|
+
}
|
|
56
|
+
stop() {
|
|
57
|
+
if (this.rafId !== null) {
|
|
58
|
+
cancelAnimationFrame(this.rafId);
|
|
59
|
+
this.rafId = null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
calc() {
|
|
63
|
+
if (this.frameTimes.length === 0) return FPS_TARGET;
|
|
64
|
+
const avg = this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length;
|
|
65
|
+
return Math.round(1e3 / avg);
|
|
66
|
+
}
|
|
67
|
+
getFPS() {
|
|
68
|
+
return this.currentFPS;
|
|
69
|
+
}
|
|
70
|
+
getAverageFPS() {
|
|
71
|
+
return this.currentFPS;
|
|
72
|
+
}
|
|
73
|
+
getP95FrameTime() {
|
|
74
|
+
if (this.frameTimes.length === 0) return 0;
|
|
75
|
+
const sorted = [...this.frameTimes].sort((a, b) => a - b);
|
|
76
|
+
return sorted[Math.floor(sorted.length * 0.95)];
|
|
77
|
+
}
|
|
78
|
+
reset() {
|
|
79
|
+
this.frameTimes = [];
|
|
80
|
+
this.currentFPS = FPS_TARGET;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var MemoryMonitor = class {
|
|
84
|
+
constructor() {
|
|
85
|
+
this.timer = null;
|
|
86
|
+
this.current = 0;
|
|
87
|
+
}
|
|
88
|
+
start(onUpdate) {
|
|
89
|
+
if (this.timer !== null) return;
|
|
90
|
+
this.timer = setInterval(() => {
|
|
91
|
+
this.current = this.measure();
|
|
92
|
+
onUpdate?.(this.current);
|
|
93
|
+
}, MEMORY_CHECK_INTERVAL);
|
|
94
|
+
}
|
|
95
|
+
stop() {
|
|
96
|
+
if (this.timer !== null) {
|
|
97
|
+
clearInterval(this.timer);
|
|
98
|
+
this.timer = null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
measure() {
|
|
102
|
+
const mem = performance["memory"];
|
|
103
|
+
return mem ? mem["usedJSHeapSize"] / (1024 * 1024) : 0;
|
|
104
|
+
}
|
|
105
|
+
getMemoryMB() {
|
|
106
|
+
return this.current;
|
|
107
|
+
}
|
|
108
|
+
getStats() {
|
|
109
|
+
const mem = performance["memory"];
|
|
110
|
+
if (!mem) return null;
|
|
111
|
+
return {
|
|
112
|
+
usedJSHeapSize: mem["usedJSHeapSize"],
|
|
113
|
+
totalJSHeapSize: mem["totalJSHeapSize"],
|
|
114
|
+
jsHeapSizeLimit: mem["jsHeapSizeLimit"],
|
|
115
|
+
heapUsagePercent: mem["usedJSHeapSize"] / mem["jsHeapSizeLimit"] * 100
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
static isSupported() {
|
|
119
|
+
return !!performance["memory"];
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
var PerformanceProfiler = class {
|
|
123
|
+
constructor() {
|
|
124
|
+
this.marks = /* @__PURE__ */ new Map();
|
|
125
|
+
this.measures = /* @__PURE__ */ new Map();
|
|
126
|
+
}
|
|
127
|
+
mark(label) {
|
|
128
|
+
this.marks.set(label, performance.now());
|
|
129
|
+
}
|
|
130
|
+
measure(label) {
|
|
131
|
+
const start = this.marks.get(label);
|
|
132
|
+
if (start === void 0) return 0;
|
|
133
|
+
const duration = performance.now() - start;
|
|
134
|
+
const list = this.measures.get(label) ?? [];
|
|
135
|
+
list.push(duration);
|
|
136
|
+
this.measures.set(label, list);
|
|
137
|
+
this.marks.delete(label);
|
|
138
|
+
return duration;
|
|
139
|
+
}
|
|
140
|
+
getAverage(label) {
|
|
141
|
+
const list = this.measures.get(label);
|
|
142
|
+
if (!list?.length) return 0;
|
|
143
|
+
return list.reduce((a, b) => a + b, 0) / list.length;
|
|
144
|
+
}
|
|
145
|
+
getP95(label) {
|
|
146
|
+
const list = this.measures.get(label);
|
|
147
|
+
if (!list?.length) return 0;
|
|
148
|
+
const sorted = [...list].sort((a, b) => a - b);
|
|
149
|
+
return sorted[Math.floor(sorted.length * 0.95)];
|
|
150
|
+
}
|
|
151
|
+
clear(label) {
|
|
152
|
+
if (label) {
|
|
153
|
+
this.marks.delete(label);
|
|
154
|
+
this.measures.delete(label);
|
|
155
|
+
} else {
|
|
156
|
+
this.marks.clear();
|
|
157
|
+
this.measures.clear();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
162
|
+
0 && (module.exports = {
|
|
163
|
+
FPSMonitor,
|
|
164
|
+
MemoryMonitor,
|
|
165
|
+
PerformanceProfiler
|
|
166
|
+
});
|
|
167
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/performance/index.ts","../../src/constants/performanceConstants.ts","../../src/performance/performanceMonitor.ts"],"sourcesContent":["export * from './performanceMonitor.js';\n","// ─── Performance & Rendering Constants ───────────────────────────────────────\n\n// ── FPS ───────────────────────────────────────────────────────────────────────\n\nexport const FPS_TARGET = 60;\nexport const FPS_WARNING_THRESHOLD = 45;\nexport const FPS_CRITICAL_THRESHOLD = 30;\nexport const TARGET_FRAME_TIME = 1000 / FPS_TARGET; // ~16.67 ms\nexport const MAX_FRAME_TIME = 18; // p95 threshold\n\n/** Legacy frame-rate targets kept for backward compatibility. */\nexport const FPS_TARGETS = {\n PAN_MIN: 30,\n ZOOM_TARGET: 60,\n WARNING_THRESHOLD: 20,\n} as const;\n\n// ── Timing Thresholds (ms) ────────────────────────────────────────────────────\n\nexport const TIMING_THRESHOLDS = {\n VIEWPORT_QUERY_MAX: 5,\n SPATIAL_UPDATE_MAX: 10,\n DRAG_RESPONSE_MAX: 16,\n LOAD_5K_TARGET: 2000,\n LOAD_10K_TARGET: 3000,\n VIEWPORT_DEBOUNCE: 100,\n SPATIAL_INDEX_BUILD: 50,\n} as const;\n\n// ── Memory Limits (MB) ────────────────────────────────────────────────────────\n\nexport const MEMORY_TARGET_MB = 500;\nexport const MEMORY_WARNING_MB = 600;\nexport const MEMORY_CRITICAL_MB = 800;\n\nexport const MEMORY_LIMITS = {\n MAX_10K_NODES: 500,\n MAX_GROWTH_PERCENT: 20,\n WARNING_THRESHOLD: 400,\n} as const;\n\n// ── Viewport Culling ──────────────────────────────────────────────────────────\n\nexport const VIEWPORT_MARGIN = 0.1;\nexport const MAX_VISIBLE_NODES = 800;\nexport const CULLING_QUERY_TIME_BUDGET = 5;\n\n// ── Spatial Index ─────────────────────────────────────────────────────────────\n\nexport const RBUSH_MAX_ENTRIES = 16;\nexport const SPATIAL_INDEX_BUILD_BUDGET = 50;\n\n// ── Node Dimensions ───────────────────────────────────────────────────────────\n\nexport const NODE_MIN_WIDTH = 200;\nexport const NODE_HEIGHT = 80;\nexport const NODE_PADDING = 40;\nexport const CHAR_WIDTH = 8;\nexport const TITLE_MAX_LENGTH = 150;\n\n// ── Visual Styling ────────────────────────────────────────────────────────────\n\nexport const CORNER_RADIUS = 8;\nexport const BORDER_WIDTH_NORMAL = 2;\nexport const BORDER_WIDTH_SELECTED = 3;\n\nexport const COLOR_SELECTED = '#1B2D4F';\nexport const COLOR_BORDER_LIGHT = '#4A3728';\nexport const COLOR_BORDER_DARK = '#FAF6F1';\nexport const COLOR_DEFAULT_NODE = '#FAF6F1';\n\n// ── Zoom Constraints ──────────────────────────────────────────────────────────\n\nexport const ZOOM_MIN = 0.05;\nexport const ZOOM_MAX = 5.0;\nexport const ZOOM_DEFAULT = 1.0;\nexport const ZOOM_STEP = 0.1;\nexport const ZOOM_WHEEL_SENSITIVITY = 0.001;\n\nexport const ZOOM_NAV_IN_THRESHOLD = 2.7;\nexport const ZOOM_NAV_OUT_THRESHOLD = 0.4;\nexport const TEXT_LABEL_HIDE_BELOW_ZOOM = 0.3;\n\n// ── Quality Level Presets ─────────────────────────────────────────────────────\n\nexport const QUALITY_HIGH = {\n shadows: true,\n bezierCurves: true,\n animations: true,\n textQuality: 'high' as const,\n antialiasing: true,\n};\n\nexport const QUALITY_MEDIUM = {\n shadows: false,\n bezierCurves: true,\n animations: true,\n textQuality: 'medium' as const,\n antialiasing: true,\n};\n\nexport const QUALITY_LOW = {\n shadows: false,\n bezierCurves: false,\n animations: false,\n textQuality: 'low' as const,\n antialiasing: false,\n};\n\n// ── Performance Monitoring ────────────────────────────────────────────────────\n\nexport const FPS_SAMPLE_WINDOW = 60;\nexport const FPS_UPDATE_INTERVAL = 1000;\nexport const MEMORY_CHECK_INTERVAL = 5000;\nexport const PERFORMANCE_TOAST_COOLDOWN = 10000;\n\n// ── Auto-Adjustment ───────────────────────────────────────────────────────────\n\nexport const FPS_DOWNGRADE_THRESHOLD = 45;\nexport const FPS_UPGRADE_THRESHOLD = 58;\nexport const FPS_STABILIZATION_FRAMES = 180;\n\n// ── Canvas Dimensions ─────────────────────────────────────────────────────────\n\nexport const DEFAULT_CANVAS_WIDTH = 1920;\nexport const DEFAULT_CANVAS_HEIGHT = 1080;\n\n// ── Interaction ───────────────────────────────────────────────────────────────\n\nexport const CLICK_THRESHOLD = 5;\nexport const DOUBLE_CLICK_DELAY = 300;\nexport const DRAG_START_DISTANCE = 10;\n\n// ── Data Validation ───────────────────────────────────────────────────────────\n\nexport const MAX_NODES = 20000;\nexport const CIRCULAR_REFERENCE_MAX_DEPTH = 1000;\n\n// ── Debounce / Throttle ───────────────────────────────────────────────────────\n\nexport const RESIZE_DEBOUNCE = 300;\nexport const SCROLL_THROTTLE = 16;\nexport const SEARCH_DEBOUNCE = 500;\n\n/** Node count thresholds that gate optimisation strategies. */\nexport const NODE_COUNT_THRESHOLDS = {\n SPATIAL_INDEX_MIN: 100,\n VIEWPORT_CULLING_MIN: 500,\n CANVAS_RENDERING_MIN: 2000,\n DOM_RENDERING_MAX: 5000,\n} as const;\n\n/** Viewport buffer configuration. */\nexport const VIEWPORT_CONFIG = {\n BUFFER_PERCENT: 0.2,\n MIN_VISIBLE_NODES: 10,\n} as const;\n","// ─── Performance Monitors ─────────────────────────────────────────────────────\n//\n// FPSMonitor – tracks frame rate via requestAnimationFrame (browser)\n// MemoryMonitor – polls performance.memory (Chrome)\n// PerformanceProfiler – mark / measure utility for arbitrary operations\n\nimport {\n FPS_TARGET,\n FPS_SAMPLE_WINDOW,\n MEMORY_CHECK_INTERVAL,\n} from '../constants/performanceConstants.js';\n\n// ── FPS Monitor ───────────────────────────────────────────────────────────────\n\nexport class FPSMonitor {\n private frameTimes: number[] = [];\n private lastTime = 0;\n private currentFPS = FPS_TARGET;\n private rafId: number | null = null;\n\n start(): void {\n if (this.rafId !== null) return;\n\n const measure = (ts: number) => {\n if (this.lastTime > 0) {\n this.frameTimes.push(ts - this.lastTime);\n if (this.frameTimes.length > FPS_SAMPLE_WINDOW) this.frameTimes.shift();\n this.currentFPS = this.calc();\n }\n this.lastTime = ts;\n this.rafId = requestAnimationFrame(measure);\n };\n\n this.rafId = requestAnimationFrame(measure);\n }\n\n stop(): void {\n if (this.rafId !== null) { cancelAnimationFrame(this.rafId); this.rafId = null; }\n }\n\n private calc(): number {\n if (this.frameTimes.length === 0) return FPS_TARGET;\n const avg = this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length;\n return Math.round(1000 / avg);\n }\n\n getFPS(): number { return this.currentFPS; }\n getAverageFPS(): number { return this.currentFPS; }\n\n getP95FrameTime(): number {\n if (this.frameTimes.length === 0) return 0;\n const sorted = [...this.frameTimes].sort((a, b) => a - b);\n return sorted[Math.floor(sorted.length * 0.95)];\n }\n\n reset(): void { this.frameTimes = []; this.currentFPS = FPS_TARGET; }\n}\n\n// ── Memory Monitor ────────────────────────────────────────────────────────────\n\nexport interface MemoryStats {\n usedJSHeapSize: number;\n totalJSHeapSize: number;\n jsHeapSizeLimit: number;\n heapUsagePercent: number;\n}\n\nexport class MemoryMonitor {\n private timer: ReturnType<typeof setInterval> | null = null;\n private current = 0;\n\n start(onUpdate?: (mb: number) => void): void {\n if (this.timer !== null) return;\n this.timer = setInterval(() => {\n this.current = this.measure();\n onUpdate?.(this.current);\n }, MEMORY_CHECK_INTERVAL);\n }\n\n stop(): void {\n if (this.timer !== null) { clearInterval(this.timer); this.timer = null; }\n }\n\n private measure(): number {\n const mem = (performance as unknown as Record<string, unknown>)['memory'] as Record<string, number> | undefined;\n return mem ? mem['usedJSHeapSize'] / (1024 * 1024) : 0;\n }\n\n getMemoryMB(): number { return this.current; }\n\n getStats(): MemoryStats | null {\n const mem = (performance as unknown as Record<string, unknown>)['memory'] as Record<string, number> | undefined;\n if (!mem) return null;\n return {\n usedJSHeapSize: mem['usedJSHeapSize'],\n totalJSHeapSize: mem['totalJSHeapSize'],\n jsHeapSizeLimit: mem['jsHeapSizeLimit'],\n heapUsagePercent: (mem['usedJSHeapSize'] / mem['jsHeapSizeLimit']) * 100,\n };\n }\n\n static isSupported(): boolean {\n return !!(performance as unknown as Record<string, unknown>)['memory'];\n }\n}\n\n// ── Performance Profiler ──────────────────────────────────────────────────────\n\nexport class PerformanceProfiler {\n private marks: Map<string, number> = new Map();\n private measures: Map<string, number[]> = new Map();\n\n mark(label: string): void {\n this.marks.set(label, performance.now());\n }\n\n measure(label: string): number {\n const start = this.marks.get(label);\n if (start === undefined) return 0;\n const duration = performance.now() - start;\n const list = this.measures.get(label) ?? [];\n list.push(duration);\n this.measures.set(label, list);\n this.marks.delete(label);\n return duration;\n }\n\n getAverage(label: string): number {\n const list = this.measures.get(label);\n if (!list?.length) return 0;\n return list.reduce((a, b) => a + b, 0) / list.length;\n }\n\n getP95(label: string): number {\n const list = this.measures.get(label);\n if (!list?.length) return 0;\n const sorted = [...list].sort((a, b) => a - b);\n return sorted[Math.floor(sorted.length * 0.95)];\n }\n\n clear(label?: string): void {\n if (label) { this.marks.delete(label); this.measures.delete(label); }\n else { this.marks.clear(); this.measures.clear(); }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
declare class FPSMonitor {
|
|
2
|
+
private frameTimes;
|
|
3
|
+
private lastTime;
|
|
4
|
+
private currentFPS;
|
|
5
|
+
private rafId;
|
|
6
|
+
start(): void;
|
|
7
|
+
stop(): void;
|
|
8
|
+
private calc;
|
|
9
|
+
getFPS(): number;
|
|
10
|
+
getAverageFPS(): number;
|
|
11
|
+
getP95FrameTime(): number;
|
|
12
|
+
reset(): void;
|
|
13
|
+
}
|
|
14
|
+
interface MemoryStats {
|
|
15
|
+
usedJSHeapSize: number;
|
|
16
|
+
totalJSHeapSize: number;
|
|
17
|
+
jsHeapSizeLimit: number;
|
|
18
|
+
heapUsagePercent: number;
|
|
19
|
+
}
|
|
20
|
+
declare class MemoryMonitor {
|
|
21
|
+
private timer;
|
|
22
|
+
private current;
|
|
23
|
+
start(onUpdate?: (mb: number) => void): void;
|
|
24
|
+
stop(): void;
|
|
25
|
+
private measure;
|
|
26
|
+
getMemoryMB(): number;
|
|
27
|
+
getStats(): MemoryStats | null;
|
|
28
|
+
static isSupported(): boolean;
|
|
29
|
+
}
|
|
30
|
+
declare class PerformanceProfiler {
|
|
31
|
+
private marks;
|
|
32
|
+
private measures;
|
|
33
|
+
mark(label: string): void;
|
|
34
|
+
measure(label: string): number;
|
|
35
|
+
getAverage(label: string): number;
|
|
36
|
+
getP95(label: string): number;
|
|
37
|
+
clear(label?: string): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { FPSMonitor, MemoryMonitor, type MemoryStats, PerformanceProfiler };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
declare class FPSMonitor {
|
|
2
|
+
private frameTimes;
|
|
3
|
+
private lastTime;
|
|
4
|
+
private currentFPS;
|
|
5
|
+
private rafId;
|
|
6
|
+
start(): void;
|
|
7
|
+
stop(): void;
|
|
8
|
+
private calc;
|
|
9
|
+
getFPS(): number;
|
|
10
|
+
getAverageFPS(): number;
|
|
11
|
+
getP95FrameTime(): number;
|
|
12
|
+
reset(): void;
|
|
13
|
+
}
|
|
14
|
+
interface MemoryStats {
|
|
15
|
+
usedJSHeapSize: number;
|
|
16
|
+
totalJSHeapSize: number;
|
|
17
|
+
jsHeapSizeLimit: number;
|
|
18
|
+
heapUsagePercent: number;
|
|
19
|
+
}
|
|
20
|
+
declare class MemoryMonitor {
|
|
21
|
+
private timer;
|
|
22
|
+
private current;
|
|
23
|
+
start(onUpdate?: (mb: number) => void): void;
|
|
24
|
+
stop(): void;
|
|
25
|
+
private measure;
|
|
26
|
+
getMemoryMB(): number;
|
|
27
|
+
getStats(): MemoryStats | null;
|
|
28
|
+
static isSupported(): boolean;
|
|
29
|
+
}
|
|
30
|
+
declare class PerformanceProfiler {
|
|
31
|
+
private marks;
|
|
32
|
+
private measures;
|
|
33
|
+
mark(label: string): void;
|
|
34
|
+
measure(label: string): number;
|
|
35
|
+
getAverage(label: string): number;
|
|
36
|
+
getP95(label: string): number;
|
|
37
|
+
clear(label?: string): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { FPSMonitor, MemoryMonitor, type MemoryStats, PerformanceProfiler };
|