aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-05 02:06:06 +0100
committertv <tv@krebsco.de>2026-11-05 02:06:06 +0100
commit78b750f8934b948e8c2c0ccc1188004dceccd433 (patch)
tree91b3eed15fe2495d0a463545488aa71c96a4bd6d
parenteb2da5d09818e86ed99d0dc967c50ab07fbd679b (diff)
dashboard: unpin nodes don't move on static graph
-rw-r--r--docs/dashboard.md4
-rw-r--r--src/api/dashboard/dashboard.html22
2 files changed, 12 insertions, 14 deletions
diff --git a/docs/dashboard.md b/docs/dashboard.md
index 8cc0b6a..8c3b007 100644
--- a/docs/dashboard.md
+++ b/docs/dashboard.md
@@ -177,8 +177,8 @@ measured.
halo flashes red and "no dashboard" rises from it, fading out.
* **Middle-click a node**: pin it where it is (a dot in its middle): the layout leaves
it there. Dragged with the middle button, it is pinned where it's dropped.
- Middle-clicked again, it's let go, and moves to its place among the others (on a
- static map, only it moves).
+ Middle-clicked again, it's let go: on a dynamic map it moves to its place among the
+ others; on a static one it stays where it is.
The map is laid out when the page opens. Resized (the window, or the boxes), it stays as
it is, scaled about its middle as the box's area is (resized back, it's as before). A
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); });