From 78b750f8934b948e8c2c0ccc1188004dceccd433 Mon Sep 17 00:00:00 2001 From: tv Date: Thu, 5 Nov 2026 02:06:06 +0100 Subject: dashboard: unpin nodes don't move on static graph --- src/api/dashboard/dashboard.html | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'src/api') diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html index 8fbbe96..d07f190 100644 --- a/src/api/dashboard/dashboard.html +++ b/src/api/dashboard/dashboard.html @@ -791,7 +791,9 @@ function layout(nodes, pairs, width, height, only) { // `most` px. Returns how far the furthest moved. A gain of 1 overshoots where a node // has several links (the pulls add up): it gets close fast, then swings about its // place; well below 1, it comes to rest. `only`, if given: the nodes that move. -function relax(nodes, pairs, width, height, gain, most, only) { +// `placing`: a layout (`layout`), which places the nodes no live link holds too; else +// they stay where they are, sticky, unless none is held. +function relax(nodes, pairs, width, height, gain, most, only, placing) { const ideal = idealLength(nodes.length, width, height); { const force = new Map(nodes.map(id => [id, { x: 0, y: 0 }])); @@ -815,6 +817,7 @@ function relax(nodes, pairs, width, height, gain, most, only) { force.get(b).x -= dx * pull; force.get(b).y -= dy * pull; } let moved = 0; + const sticky = id => held.size > 0 && !held.has(id) && !placing; for (const id of nodes) { if (pinned.has(id) || id === grabbed || (only && !only.has(id))) continue; const p = positions.get(id), f = force.get(id); @@ -876,24 +879,20 @@ function lengths(intended, measured, count, width, height) { } // What `settle` moves the map towards: the latest render's nodes and lengths. let settling = false, settleTo = null, lastLengths = ""; -// Nodes let go (`unpin`) on a static map: the only ones `settle` moves there, to -// their places among the others. -const freed = new Set(); function settle() { if (settling) return; settling = true; let frames = 0; const step = () => { - // Static again: where they are now (but those let go). - if (!byRtt && freed.size === 0) { settling = false; return; } + // Static again: where they are now. + if (!byRtt) { settling = false; return; } const { nodes, pairs, width, height } = settleTo; // Damped: the swings of the layout's rounds die down instead of going on. - const moved = relax(nodes, pairs, width, height, .15, 2, byRtt ? null : freed); + const moved = relax(nodes, pairs, width, height, .15, 2); renderGraph(); if (moved > .1 && ++frames < 600 && !document.hidden) requestAnimationFrame(step); else { settling = false; - freed.clear(); // Hidden: on again with the next render. if (document.hidden) lastLengths = ""; } @@ -2034,13 +2033,12 @@ function pin(id) { pinned.add(id); renderGraph(); } -// A node let go: it moves to its place among the others, smoothly (`settle`); on a -// static map, only it moves. +// A node let go: on a dynamic map, it moves to its place among the others, smoothly +// (`settle`); on a static one, it stays where it is, as every node there does. function unpin(id) { if (!pinned.delete(id)) return; - freed.add(id); renderGraph(); - settle(); + if (byRtt) settle(); } // Beside the nodes, or off the map: nothing hovered (the element left may be gone). graph.addEventListener("mousemove", event => { if (event.target === graph) hover(null); }); -- cgit v1.3.1