diff options
| author | tv <tv@krebsco.de> | 2026-10-30 18:52:43 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-30 18:52:43 +0100 |
| commit | 92f4a4548d0499a5ea32676ef04008135ecf6361 (patch) | |
| tree | b76e478f56fdcc9d8957445b967c55c5b85580ca | |
| parent | 7a1ad74ffdbdaf30862c39f930377dfefe3245d0 (diff) | |
dashboard: show hovering over nodes
| -rw-r--r-- | src/api/dashboard/dashboard.html | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html index c1d46b7..65fa95b 100644 --- a/src/api/dashboard/dashboard.html +++ b/src/api/dashboard/dashboard.html @@ -336,6 +336,19 @@ function layout(nodes, pairs, width, height) { } } +// The node under the pointer, if any. The map is drawn anew every second, so it is +// kept here rather than left to :hover. +let hovered = null; +function hover(id) { + if (hovered === id) return; + hovered = id; + if (state) renderGraph(); +} +function hoverable(element, id) { + element.addEventListener("mouseenter", () => hover(id)); + element.addEventListener("mouseleave", () => hover(null)); +} + let lastShape = ""; function renderGraph() { const root = document.getElementById("graph"); @@ -408,6 +421,11 @@ function renderGraph() { const p = positions.get(id), member = state.graph.members[id]; const reported = id in state.graph.measured; const shown = focused === null ? member.self : id === focused; + if (id === hovered) { + // Under the pointer: lighter than the focus ring. + children.push(svg("circle", { cx: p.x, cy: p.y, r: 12, fill: "var(--self)", + "fill-opacity": .12, stroke: "none" })); + } if (shown) { children.push(svg("circle", { cx: p.x, cy: p.y, r: 13, fill: "none", stroke: "var(--self)", "stroke-width": 2, "stroke-opacity": .5 })); @@ -419,10 +437,12 @@ function renderGraph() { title.textContent = id + (reported ? "" : " (no links reported)"); circle.append(title); circle.addEventListener("click", event => { event.stopPropagation(); focus(id); }); + hoverable(circle, id); const label = svg("text", { x: p.x + 10, y: p.y + 4, "font-size": 12, fill: "var(--fg)" }); label.textContent = name(id); label.style.cursor = "pointer"; label.addEventListener("click", event => { event.stopPropagation(); focus(id); }); + hoverable(label, id); children.push(circle, label); } root.replaceChildren(...children); @@ -438,7 +458,11 @@ function render() { } // A click beside the nodes: back to this node. -document.getElementById("graph").addEventListener("click", () => focus(null)); +const graph = document.getElementById("graph"); +graph.addEventListener("click", () => focus(null)); +// 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); }); +graph.addEventListener("mouseleave", () => hover(null)); // --- Events --- const connection = document.getElementById("connection"); |
