diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/dashboard/dashboard.html | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html index 5854f61..1b4c2ba 100644 --- a/src/api/dashboard/dashboard.html +++ b/src/api/dashboard/dashboard.html @@ -460,14 +460,15 @@ function idealLength(count, width, height) { return Math.min(width, height) / Math.max(2, Math.sqrt(count) * 1.5); } // `pairs`: [a, b, length], the length the link pulls towards (else `idealLength`). -function layout(nodes, pairs, width, height) { +// `only`, if given: the nodes laid out; the others stay where they are. +function layout(nodes, pairs, width, height, only) { for (const id of nodes) { if (!positions.has(id)) { positions.set(id, { x: width / 2 + (Math.random() - .5) * width / 2, y: height / 2 + (Math.random() - .5) * height / 2 }); } } - for (let round = 0; round < 120; round++) relax(nodes, pairs, width, height, 1, 10); + for (let round = 0; round < 120; round++) relax(nodes, pairs, width, height, 1, 10, only); } // One round of the layout: every node moved by `gain` of the forces on it, at most // `most` px. Returns how far the furthest moved. A gain of 1 overshoots where a node @@ -650,6 +651,13 @@ function show(root, children) { } let lastShape = ""; +// The whole map laid out again with the next render (the window or the box resized), +// not only nodes new to it. +let relayout = true; +function layoutAgain() { + relayout = true; + lastShape = ""; +} function renderGraph() { const root = document.getElementById("graph"); const width = root.clientWidth || 800, height = root.clientHeight || 560; @@ -658,13 +666,18 @@ function renderGraph() { const { intended, measured } = edges(); renderLegend(measured); const pairs = lengths(intended, measured, nodes.length, width, height); - // Laid out anew only when who's there or who links to whom changed. + // Laid out when who's there or who links to whom changed: only the nodes new to the + // map, the others staying where they are (links that came, after the first reports, + // don't move them); all of them at first, and when the map was resized. const shape = nodes.join(",") + "|" + [...intended.keys(), ...measured.keys()].sort().join(","); if (shape !== lastShape) { for (const id of [...positions.keys()]) { if (!nodes.includes(id)) { positions.delete(id); pinned.delete(id); } } - layout(nodes, pairs, width, height); + const fresh = new Set(nodes.filter(id => !positions.has(id))); + if (relayout) layout(nodes, pairs, width, height); + else if (fresh.size > 0) layout(nodes, pairs, width, height, fresh); + relayout = false; lastShape = shape; } settleTo = { nodes, pairs, width, height }; @@ -1492,7 +1505,7 @@ connection.addEventListener("click", () => { }); // Ages count on between events; nothing else changes without one. setInterval(() => { if (live) render(true); }, 1000); -window.addEventListener("resize", () => { lastShape = ""; render(); }); +window.addEventListener("resize", () => { layoutAgain(); render(); }); // --- Sizes: the space between boxes dragged to resize them, double-clicked to reset; // kept in this browser --- @@ -1575,7 +1588,7 @@ const resized = () => { if (!resizing) return; resizing = null; main.classList.remove("resize-columns", "resize-rows"); - lastShape = ""; + layoutAgain(); render(); }; main.addEventListener("pointerup", resized); @@ -1585,7 +1598,7 @@ main.addEventListener("dblclick", event => { if (!gap) return; sizes[gap] = null; applySizes(); - lastShape = ""; + layoutAgain(); render(); }); </script> |
