project-graph-mcp 2.2.6 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +81 -0
- package/CHANGELOG.md +57 -0
- package/README.md +9 -4
- package/package.json +6 -13
- package/src/compact/expand.js +1 -1
- package/src/core/graph-builder.js +2 -2
- package/src/core/parser.js +2 -2
- package/src/network/server.js +1 -2
- package/vendor/symbiote-node/CHANGELOG.md +31 -0
- package/vendor/symbiote-node/LICENSE +21 -0
- package/vendor/symbiote-node/README.md +206 -0
- package/vendor/symbiote-node/canvas/AutoLayout.js +725 -0
- package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.css.js +73 -0
- package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.js +93 -0
- package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.tpl.js +9 -0
- package/vendor/symbiote-node/canvas/CanvasConnectionRenderer.js +962 -0
- package/vendor/symbiote-node/canvas/ConnectionRenderer.js +1468 -0
- package/vendor/symbiote-node/canvas/FlowSimulator.js +323 -0
- package/vendor/symbiote-node/canvas/ForceLayout.js +189 -0
- package/vendor/symbiote-node/canvas/ForceWorker.js +1325 -0
- package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.css.js +97 -0
- package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.js +176 -0
- package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.tpl.js +12 -0
- package/vendor/symbiote-node/canvas/LODManager.js +88 -0
- package/vendor/symbiote-node/canvas/Minimap/Minimap.css.js +71 -0
- package/vendor/symbiote-node/canvas/Minimap/Minimap.js +207 -0
- package/vendor/symbiote-node/canvas/Minimap/Minimap.tpl.js +9 -0
- package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.css.js +261 -0
- package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.js +1840 -0
- package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.tpl.js +22 -0
- package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.css.js +97 -0
- package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.js +132 -0
- package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.tpl.js +21 -0
- package/vendor/symbiote-node/canvas/NodeViewManager.js +584 -0
- package/vendor/symbiote-node/canvas/PinExpansion.js +131 -0
- package/vendor/symbiote-node/canvas/PseudoConnection.js +80 -0
- package/vendor/symbiote-node/canvas/SubgraphManager.js +201 -0
- package/vendor/symbiote-node/canvas/SubgraphRouter.js +443 -0
- package/vendor/symbiote-node/canvas/ViewportActions.js +446 -0
- package/vendor/symbiote-node/core/Connection.js +45 -0
- package/vendor/symbiote-node/core/Editor.js +451 -0
- package/vendor/symbiote-node/core/Frame.js +31 -0
- package/vendor/symbiote-node/core/GraphMermaid.js +348 -0
- package/vendor/symbiote-node/core/GraphText.js +210 -0
- package/vendor/symbiote-node/core/Node.js +143 -0
- package/vendor/symbiote-node/core/Portal.js +104 -0
- package/vendor/symbiote-node/core/Socket.js +185 -0
- package/vendor/symbiote-node/core/SubgraphNode.js +125 -0
- package/vendor/symbiote-node/index.js +103 -0
- package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.css.js +361 -0
- package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.js +332 -0
- package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.tpl.js +96 -0
- package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.css.js +104 -0
- package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.js +133 -0
- package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.tpl.js +33 -0
- package/vendor/symbiote-node/interactions/ConnectFlow.js +307 -0
- package/vendor/symbiote-node/interactions/Drag.js +102 -0
- package/vendor/symbiote-node/interactions/Selector.js +132 -0
- package/vendor/symbiote-node/interactions/SnapGrid.js +65 -0
- package/vendor/symbiote-node/interactions/Zoom.js +140 -0
- package/vendor/symbiote-node/layout/ActionZone/ActionZone.css.js +88 -0
- package/vendor/symbiote-node/layout/ActionZone/ActionZone.js +254 -0
- package/vendor/symbiote-node/layout/ActionZone/ActionZone.tpl.js +11 -0
- package/vendor/symbiote-node/layout/Layout/Layout.css.js +88 -0
- package/vendor/symbiote-node/layout/Layout/Layout.js +622 -0
- package/vendor/symbiote-node/layout/Layout/Layout.tpl.js +25 -0
- package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.css.js +293 -0
- package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.js +467 -0
- package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.tpl.js +33 -0
- package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.css.js +46 -0
- package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.js +102 -0
- package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.tpl.js +6 -0
- package/vendor/symbiote-node/layout/LayoutRouter/LayoutRouter.js +156 -0
- package/vendor/symbiote-node/layout/LayoutRouter/routerSync.js +250 -0
- package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.css.js +379 -0
- package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.js +263 -0
- package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.tpl.js +20 -0
- package/vendor/symbiote-node/layout/LayoutSidebar/SidebarSection.js +183 -0
- package/vendor/symbiote-node/layout/LayoutTree.js +246 -0
- package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.css.js +43 -0
- package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.js +89 -0
- package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.tpl.js +14 -0
- package/vendor/symbiote-node/layout/index.js +16 -0
- package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.css.js +61 -0
- package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.js +79 -0
- package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.tpl.js +19 -0
- package/vendor/symbiote-node/node/CtrlItem/CtrlItem.css.js +41 -0
- package/vendor/symbiote-node/node/CtrlItem/CtrlItem.js +24 -0
- package/vendor/symbiote-node/node/CtrlItem/CtrlItem.tpl.js +16 -0
- package/vendor/symbiote-node/node/GraphFrame/GraphFrame.css.js +65 -0
- package/vendor/symbiote-node/node/GraphFrame/GraphFrame.js +29 -0
- package/vendor/symbiote-node/node/GraphFrame/GraphFrame.tpl.js +13 -0
- package/vendor/symbiote-node/node/GraphNode/GraphNode.css.js +683 -0
- package/vendor/symbiote-node/node/GraphNode/GraphNode.js +92 -0
- package/vendor/symbiote-node/node/GraphNode/GraphNode.tpl.js +17 -0
- package/vendor/symbiote-node/node/NodeSocket/NodeSocket.js +25 -0
- package/vendor/symbiote-node/node/NodeSocket/NodeSocket.tpl.js +7 -0
- package/vendor/symbiote-node/node/PortItem/PortItem.css.js +90 -0
- package/vendor/symbiote-node/node/PortItem/PortItem.js +87 -0
- package/vendor/symbiote-node/node/PortItem/PortItem.tpl.js +10 -0
- package/vendor/symbiote-node/package.json +59 -0
- package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.css.js +143 -0
- package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.js +131 -0
- package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.tpl.js +16 -0
- package/vendor/symbiote-node/plugins/History.js +384 -0
- package/vendor/symbiote-node/plugins/Readonly.js +59 -0
- package/vendor/symbiote-node/shapes/CircleShape.js +80 -0
- package/vendor/symbiote-node/shapes/CommentShape.js +35 -0
- package/vendor/symbiote-node/shapes/DiamondShape.js +115 -0
- package/vendor/symbiote-node/shapes/NodeShape.js +80 -0
- package/vendor/symbiote-node/shapes/PillShape.js +91 -0
- package/vendor/symbiote-node/shapes/RectShape.js +72 -0
- package/vendor/symbiote-node/shapes/SVGShape.js +494 -0
- package/vendor/symbiote-node/shapes/index.js +53 -0
- package/vendor/symbiote-node/themes/Palette.js +32 -0
- package/vendor/symbiote-node/themes/Skin.js +113 -0
- package/vendor/symbiote-node/themes/Theme.js +84 -0
- package/vendor/symbiote-node/themes/carbon.js +137 -0
- package/vendor/symbiote-node/themes/dark.js +137 -0
- package/vendor/symbiote-node/themes/ebook.js +138 -0
- package/vendor/symbiote-node/themes/grey.js +137 -0
- package/vendor/symbiote-node/themes/light.js +137 -0
- package/vendor/symbiote-node/themes/neon.js +138 -0
- package/vendor/symbiote-node/themes/pcb.js +273 -0
- package/vendor/symbiote-node/themes/synthwave.js +137 -0
- package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.css.js +86 -0
- package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.js +128 -0
- package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.tpl.js +29 -0
- package/web/app.js +6 -5
- package/web/components/canvas-graph.js +1666 -0
- package/web/components/event-feed/CodeWidget.js +32 -0
- package/web/components/event-feed/EventWidget.js +97 -0
- package/web/components/event-feed/ListWidget.js +57 -0
- package/web/components/event-feed/MiniGraphWidget.js +69 -0
- package/web/dashboard.js +1 -1
- package/web/index.html +4 -0
- package/web/panels/ActionBoard/ActionBoard.js +1 -1
- package/web/panels/SettingsPanel/SettingsPanel.tpl.js +1 -1
- package/web/panels/code-viewer.js +50 -15
- package/web/panels/dep-graph.js +2712 -7
- package/web/panels/file-tree.js +5 -2
- package/web/panels/live-monitor.js +75 -3
- package/web/style.css +33 -0
- package/docs/img/explorer-compact.jpg +0 -0
- package/docs/img/explorer-expanded.jpg +0 -0
- package/src/.contextignore +0 -22
- package/src/.project-graph-cache.json +0 -1
- package/src/compact/.project-graph-cache.json +0 -1
- package/web/.project-graph-cache.json +0 -1
- package/web/panels/SettingsPanel/.project-graph-cache.json +0 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PseudoConnection — temporary connection line during drag
|
|
3
|
+
*
|
|
4
|
+
* Renders dashed Bézier path + plus indicator at endpoint.
|
|
5
|
+
* Extracted from NodeCanvas to reduce complexity.
|
|
6
|
+
*
|
|
7
|
+
* @module symbiote-node/canvas/PseudoConnection
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export class PseudoConnection {
|
|
11
|
+
|
|
12
|
+
/** @type {SVGPathElement|null} */
|
|
13
|
+
#path = null;
|
|
14
|
+
|
|
15
|
+
/** @type {SVGGElement|null} */
|
|
16
|
+
#plusIndicator = null;
|
|
17
|
+
|
|
18
|
+
/** @type {SVGElement} */
|
|
19
|
+
#svg;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {SVGElement} svgLayer - pseudo SVG overlay
|
|
23
|
+
*/
|
|
24
|
+
constructor(svgLayer) {
|
|
25
|
+
this.#svg = svgLayer;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Show pseudo-connection between two world-space points.
|
|
30
|
+
* pseudo-svg is inside .content which applies CSS transform (zoom+pan),
|
|
31
|
+
* so coordinates must be in world-space (same as ConnectionRenderer dots).
|
|
32
|
+
* @param {number} sx - Start X (world space)
|
|
33
|
+
* @param {number} sy - Start Y (world space)
|
|
34
|
+
* @param {number} ex - End X (world space)
|
|
35
|
+
* @param {number} ey - End Y (world space)
|
|
36
|
+
*/
|
|
37
|
+
show(sx, sy, ex, ey) {
|
|
38
|
+
if (!this.#path) {
|
|
39
|
+
this.#path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
40
|
+
this.#path.setAttribute('class', 'pseudo-path');
|
|
41
|
+
this.#svg.appendChild(this.#path);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const dx = Math.abs(ex - sx) * 0.5;
|
|
45
|
+
const d = `M ${sx} ${sy} C ${sx + dx} ${sy}, ${ex - dx} ${ey}, ${ex} ${ey}`;
|
|
46
|
+
this.#path.setAttribute('d', d);
|
|
47
|
+
|
|
48
|
+
// Plus indicator at endpoint
|
|
49
|
+
if (!this.#plusIndicator) {
|
|
50
|
+
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
51
|
+
g.setAttribute('class', 'plus-indicator');
|
|
52
|
+
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
|
|
53
|
+
circle.setAttribute('r', '8');
|
|
54
|
+
const h = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
55
|
+
h.setAttribute('x1', '-4'); h.setAttribute('y1', '0');
|
|
56
|
+
h.setAttribute('x2', '4'); h.setAttribute('y2', '0');
|
|
57
|
+
const v = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
58
|
+
v.setAttribute('x1', '0'); v.setAttribute('y1', '-4');
|
|
59
|
+
v.setAttribute('x2', '0'); v.setAttribute('y2', '4');
|
|
60
|
+
g.appendChild(circle);
|
|
61
|
+
g.appendChild(h);
|
|
62
|
+
g.appendChild(v);
|
|
63
|
+
this.#svg.appendChild(g);
|
|
64
|
+
this.#plusIndicator = g;
|
|
65
|
+
}
|
|
66
|
+
this.#plusIndicator.setAttribute('transform', `translate(${ex}, ${ey})`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Hide and clean up pseudo-connection */
|
|
70
|
+
hide() {
|
|
71
|
+
if (this.#path) {
|
|
72
|
+
this.#path.remove();
|
|
73
|
+
this.#path = null;
|
|
74
|
+
}
|
|
75
|
+
if (this.#plusIndicator) {
|
|
76
|
+
this.#plusIndicator.remove();
|
|
77
|
+
this.#plusIndicator = null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubgraphManager — Navigation stack for subgraph drill-down
|
|
3
|
+
*
|
|
4
|
+
* Manages a stack of editor contexts. When drilling into a subgraph,
|
|
5
|
+
* the current state is saved and the inner editor is loaded.
|
|
6
|
+
* Breadcrumb navigation allows jumping back to any level.
|
|
7
|
+
*
|
|
8
|
+
* @module symbiote-node/canvas/SubgraphManager
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Object} NavEntry
|
|
13
|
+
* @property {import('../core/Editor.js').NodeEditor} editor
|
|
14
|
+
* @property {Object<string, { x: number, y: number }>} positions
|
|
15
|
+
* @property {{ panX: number, panY: number, zoom: number }} transform
|
|
16
|
+
* @property {string} label - Display label for breadcrumb
|
|
17
|
+
* @property {string|null} subgraphNodeId - SubgraphNode ID in parent (null for root)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export class SubgraphManager {
|
|
21
|
+
/** @type {NavEntry[]} */
|
|
22
|
+
#stack = [];
|
|
23
|
+
|
|
24
|
+
/** @type {import('./NodeCanvas.js').NodeCanvas|null} */
|
|
25
|
+
#canvas = null;
|
|
26
|
+
|
|
27
|
+
/** @type {function|null} */
|
|
28
|
+
#onNavigate = null;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initialize with canvas and root editor
|
|
32
|
+
* @param {*} canvas - NodeCanvas element
|
|
33
|
+
* @param {import('../core/Editor.js').NodeEditor} rootEditor
|
|
34
|
+
*/
|
|
35
|
+
initialize(canvas, rootEditor) {
|
|
36
|
+
this.#canvas = canvas;
|
|
37
|
+
this.#stack = [{
|
|
38
|
+
editor: rootEditor,
|
|
39
|
+
positions: {},
|
|
40
|
+
transform: { panX: 0, panY: 0, zoom: 1 },
|
|
41
|
+
label: 'Root',
|
|
42
|
+
subgraphNodeId: null,
|
|
43
|
+
}];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Set navigation callback (for breadcrumb updates)
|
|
48
|
+
* @param {function} callback - (path: string[]) => void
|
|
49
|
+
*/
|
|
50
|
+
onNavigate(callback) {
|
|
51
|
+
this.#onNavigate = callback;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Drill down into a SubgraphNode
|
|
56
|
+
* @param {import('../core/SubgraphNode.js').SubgraphNode} subgraphNode
|
|
57
|
+
*/
|
|
58
|
+
drillDown(subgraphNode) {
|
|
59
|
+
if (!subgraphNode?._isSubgraph || !this.#canvas) return;
|
|
60
|
+
|
|
61
|
+
// Save current state
|
|
62
|
+
const current = this.#stack[this.#stack.length - 1];
|
|
63
|
+
current.positions = this.#capturePositions(current.editor, current.positions);
|
|
64
|
+
current.transform = this.#captureTransform();
|
|
65
|
+
|
|
66
|
+
// Push inner editor
|
|
67
|
+
this.#stack.push({
|
|
68
|
+
editor: subgraphNode.getInnerEditor(),
|
|
69
|
+
positions: subgraphNode.innerPositions,
|
|
70
|
+
transform: subgraphNode.innerTransform,
|
|
71
|
+
label: subgraphNode.label,
|
|
72
|
+
subgraphNodeId: subgraphNode.id,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Switch canvas to inner editor
|
|
76
|
+
this.#applyLevel(this.#stack.length - 1);
|
|
77
|
+
this.#notifyNavigate();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Navigate up to a specific level
|
|
82
|
+
* @param {number} level - 0 = root
|
|
83
|
+
*/
|
|
84
|
+
drillUp(level) {
|
|
85
|
+
if (level === undefined) level = this.#stack.length - 2;
|
|
86
|
+
if (level < 0 || level >= this.#stack.length || !this.#canvas) return;
|
|
87
|
+
|
|
88
|
+
// Save state of levels being popped (persist inner positions)
|
|
89
|
+
for (let i = this.#stack.length - 1; i > level; i--) {
|
|
90
|
+
const entry = this.#stack[i];
|
|
91
|
+
const parentEntry = this.#stack[i - 1];
|
|
92
|
+
if (entry.subgraphNodeId) {
|
|
93
|
+
const subNode = parentEntry.editor.getNode(entry.subgraphNodeId);
|
|
94
|
+
if (subNode?._isSubgraph) {
|
|
95
|
+
subNode.setInnerPositions(this.#capturePositions(entry.editor, entry.positions));
|
|
96
|
+
subNode.setInnerTransform(entry.transform);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Save current deep level positions before truncating
|
|
102
|
+
const currentEntry = this.#stack[this.#stack.length - 1];
|
|
103
|
+
currentEntry.positions = this.#capturePositions(currentEntry.editor, currentEntry.positions);
|
|
104
|
+
currentEntry.transform = this.#captureTransform();
|
|
105
|
+
|
|
106
|
+
// Truncate stack
|
|
107
|
+
this.#stack.length = level + 1;
|
|
108
|
+
|
|
109
|
+
// Switch canvas
|
|
110
|
+
this.#applyLevel(level);
|
|
111
|
+
this.#notifyNavigate();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get current breadcrumb path
|
|
116
|
+
* @returns {Array<{ label: string, level: number }>}
|
|
117
|
+
*/
|
|
118
|
+
getPath() {
|
|
119
|
+
return this.#stack.map((entry, i) => ({
|
|
120
|
+
label: entry.label,
|
|
121
|
+
level: i,
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get current depth (0 = root)
|
|
127
|
+
* @returns {number}
|
|
128
|
+
*/
|
|
129
|
+
get depth() {
|
|
130
|
+
return this.#stack.length - 1;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get current editor
|
|
135
|
+
* @returns {import('../core/Editor.js').NodeEditor}
|
|
136
|
+
*/
|
|
137
|
+
get currentEditor() {
|
|
138
|
+
return this.#stack[this.#stack.length - 1].editor;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Apply a stack level to the canvas
|
|
143
|
+
* @param {number} level
|
|
144
|
+
*/
|
|
145
|
+
#applyLevel(level) {
|
|
146
|
+
const entry = this.#stack[level];
|
|
147
|
+
if (!entry || !this.#canvas) return;
|
|
148
|
+
|
|
149
|
+
// Rebind editor
|
|
150
|
+
this.#canvas.setEditor(entry.editor);
|
|
151
|
+
|
|
152
|
+
// Restore positions
|
|
153
|
+
for (const [nodeId, pos] of Object.entries(entry.positions)) {
|
|
154
|
+
this.#canvas.setNodePosition(nodeId, pos.x, pos.y);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Restore transform
|
|
158
|
+
this.#canvas.$.panX = entry.transform.panX;
|
|
159
|
+
this.#canvas.$.panY = entry.transform.panY;
|
|
160
|
+
this.#canvas.$.zoom = entry.transform.zoom;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Capture current node positions from editor.
|
|
165
|
+
* Falls back to existing entry positions when DOM elements
|
|
166
|
+
* have already been cleared (e.g. during setEditor transitions).
|
|
167
|
+
* @param {import('../core/Editor.js').NodeEditor} editor
|
|
168
|
+
* @param {Object<string, { x: number, y: number }>} [fallback={}]
|
|
169
|
+
* @returns {Object<string, { x: number, y: number }>}
|
|
170
|
+
*/
|
|
171
|
+
#capturePositions(editor, fallback = {}) {
|
|
172
|
+
const positions = { ...fallback };
|
|
173
|
+
if (!this.#canvas) return positions;
|
|
174
|
+
for (const node of editor.getNodes()) {
|
|
175
|
+
const el = this.#canvas.getNodeView?.(node.id);
|
|
176
|
+
if (el?._position) {
|
|
177
|
+
positions[node.id] = { ...el._position };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return positions;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Capture current viewport transform
|
|
185
|
+
* @returns {{ panX: number, panY: number, zoom: number }}
|
|
186
|
+
*/
|
|
187
|
+
#captureTransform() {
|
|
188
|
+
if (!this.#canvas) return { panX: 0, panY: 0, zoom: 1 };
|
|
189
|
+
return {
|
|
190
|
+
panX: this.#canvas.$.panX ?? 0,
|
|
191
|
+
panY: this.#canvas.$.panY ?? 0,
|
|
192
|
+
zoom: this.#canvas.$.zoom ?? 1,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
#notifyNavigate() {
|
|
197
|
+
if (this.#onNavigate) {
|
|
198
|
+
this.#onNavigate(this.getPath());
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|