diff --git a/packages/foam-vscode/src/features/panels/dataviz.ts b/packages/foam-vscode/src/features/panels/dataviz.ts index 1cbc7ad3..d7c3a8ea 100644 --- a/packages/foam-vscode/src/features/panels/dataviz.ts +++ b/packages/foam-vscode/src/features/panels/dataviz.ts @@ -139,6 +139,7 @@ async function createGraphPanel( type: 'didUpdateStyle', payload: styles, }); + updateGraph(panel, foam); break; } diff --git a/packages/foam-vscode/static/dataviz/graph.css b/packages/foam-vscode/static/dataviz/graph.css index 375721dc..780b76b7 100644 --- a/packages/foam-vscode/static/dataviz/graph.css +++ b/packages/foam-vscode/static/dataviz/graph.css @@ -1,14 +1,10 @@ body { overflow: hidden; } - -.dg .c { - width: 10%; -} - -.dg .property-name { - width: 90%; -} +/* + [INFO] Custom width rules for dat.GUI controls (10% for controls, 90% for labels) were intentionally removed. + This change was made to better accommodate new sliders, and to use dat.GUI's default proportions, which allocate more space to controls. If you notice any display issues (especially with type filter checkboxes), please verify in both light and dark VS Code themes. +*/ .vscode-light .dg.main.taller-than-window .close-button { border-top: 1px solid #ddd; diff --git a/packages/foam-vscode/static/dataviz/graph.js b/packages/foam-vscode/static/dataviz/graph.js index 48f55c36..690beaba 100644 --- a/packages/foam-vscode/static/dataviz/graph.js +++ b/packages/foam-vscode/static/dataviz/graph.js @@ -4,6 +4,18 @@ const initGUI = () => { const gui = new dat.gui.GUI(); const nodeTypeFilterFolder = gui.addFolder('Filter by type'); const nodeTypeFilterControllers = new Map(); + const selectionFolder = gui.addFolder('Selection'); + + selectionFolder + .add(model.selection, 'neighborDepth', 1, 5) + .step(1) + .name('Neighbor Depth') + .onFinishChange(() => { + update(m => m); + }); + + selectionFolder.add(model.selection, 'enableRefocus').name('Refocus Enable'); + selectionFolder.add(model.selection, 'enableZoom').name('Zoom Enable'); return { /** @@ -91,11 +103,39 @@ let model = { note: true, tag: true, }, + + selection: { + neighborDepth: 1, + enableRefocus: true, + enableZoom: true, + } }; const graph = ForceGraph(); const gui = initGUI(); +function getNeighbors(nodeId, depth) { + let neighbors = new Set([nodeId]); + for (let i = 0; i < depth; i++) { + let newNeighbors = new Set(); + for (const neighborId of neighbors) { + if (model.graph.nodeInfo[neighborId]) { + for (const n of model.graph.nodeInfo[neighborId].neighbors) { + newNeighbors.add(n); + } + } else { + // Node is missing from nodeInfo (e.g., has been deleted). Skipping. + // This may make debugging difficult if nodes are unexpectedly missing from highlights. + console.debug(`getNeighbors: node '${neighborId}' not found in nodeInfo, skipping.`); + } + } + for (const newNeighbor of newNeighbors) { + neighbors.add(newNeighbor); + } + } + return neighbors; +} + function update(patch) { const startTime = performance.now(); // Apply the patch function to the model.. @@ -105,20 +145,20 @@ function update(patch) { // compute highlighted elements const focusNodes = new Set(); const focusLinks = new Set(); - if (model.hoverNode) { - focusNodes.add(model.hoverNode); - const info = model.graph.nodeInfo[model.hoverNode]; - info.neighbors.forEach(neighborId => focusNodes.add(neighborId)); - info.links.forEach(link => focusLinks.add(link)); - } - if (model.selectedNodes) { - model.selectedNodes.forEach(nodeId => { - focusNodes.add(nodeId); - const info = model.graph.nodeInfo[nodeId]; - info.neighbors.forEach(neighborId => focusNodes.add(neighborId)); - info.links.forEach(link => focusLinks.add(link)); - }); - } + + const nodesToProcess = new Set([...model.selectedNodes, model.hoverNode].filter(Boolean)); + + nodesToProcess.forEach(nodeId => { + const neighbors = getNeighbors(nodeId, model.selection.neighborDepth); + neighbors.forEach(neighbor => focusNodes.add(neighbor)); + }); + + model.graph.links.forEach(link => { + if (focusNodes.has(getLinkNodeId(link.source)) && focusNodes.has(getLinkNodeId(link.target))) { + focusLinks.add(link); + } + }); + model.focusNodes = focusNodes; model.focusLinks = focusLinks; @@ -569,7 +609,12 @@ try { const noteId = message.payload; const node = graph.graphData().nodes.find(node => node.id === noteId); if (node) { - graph.centerAt(node.x, node.y, 300).zoom(3, 300); + if (model.selection.enableRefocus) { + graph.centerAt(node.x, node.y, 300); + } + if (model.selection.enableZoom) { + graph.zoom(3, 300); + } Actions.selectNode(noteId); } break;