diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/dashboard/dashboard.html | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/src/api/dashboard/dashboard.html b/src/api/dashboard/dashboard.html index bb49dd8..db8dd15 100644 --- a/src/api/dashboard/dashboard.html +++ b/src/api/dashboard/dashboard.html @@ -104,6 +104,9 @@ box-shadow: 0 0 0 2.5px color-mix(in srgb, var(--bad) 50%, transparent); } .legend .silent::before { border-top-style: dotted; --colour: var(--muted); } .legend .hint::before { display: none; } + /* A kind of message: a dot in its colour, as on the map. */ + .legend .message::before { width: 8px; height: 8px; border: none; border-radius: 50%; + background: var(--colour); } #legends { flex: none; } /* Hides the legend, and shows it again. */ button.toggle { font: inherit; font-size: 12px; text-transform: none; letter-spacing: 0; @@ -184,6 +187,7 @@ <span class="node focus">in focus (click a node)</span> </div> <div class="legend" id="legend"></div> + <div class="legend" id="messages-legend"></div> <div class="legend"> <span class="hint">drag to pan, wheel or pinch to zoom, turn with two fingers; drag a node to move it, double-click it to pin it there or let it go</span> @@ -1472,6 +1476,7 @@ flowsToggle.addEventListener("click", () => { flowsShown = !flowsShown; try { localStorage.setItem("continuum-flows", flowsShown ? "1" : "0"); } catch (_) {} showFlowsToggle(); + showMessagesLegend(); if (!flowsShown) { flows.length = 0; document.getElementById("flows").replaceChildren(); @@ -1485,6 +1490,23 @@ function messages(byKind) { return Object.fromEntries(Object.entries(byKind || {}) .map(([kind, counter]) => [kind, { messages: counter.messages, bytes: counter.bytes }])); } +// The colour of a kind of message (`traffic`'s kinds), on the map and in the console; +// the replies as their requests. +const KIND_COLOURS = [["sync", "#ea580c"], ["blob", "#a16207"], ["hello", "#16a34a"], + ["status", "#e11d48"], ["identity", "#0d9488"], ["paths", "var(--muted)"], + ["links", "#db2777"]]; +const kindColour = kind => (KIND_COLOURS.find(([name]) => kind === name || + kind === name + "Reply") || [null, "var(--fg)"])[1]; +function showMessagesLegend() { + const legend = document.getElementById("messages-legend"); + legend.hidden = !flowsShown; + if (legend.childElementCount === 0) { + legend.append(...KIND_COLOURS.map(([kind, colour]) => + el("span", { class: "message", style: "--colour: " + colour }, + kind === "paths" ? "paths (pings)" : kind))); + } +} +showMessagesLegend(); // A dot's radius for a message of `bytes`: grows with the size's logarithm, from 1.5 // (a ping) to 8. const dotRadius = bytes => Math.min(8, Math.max(1.5, 1.5 + 1.1 * Math.log10(1 + bytes / 32))); @@ -1555,16 +1577,20 @@ const size = bytes => bytes < 1024 ? bytes + " B" : bytes < 1048576 ? (bytes / 1024).toFixed(1) + " KiB" : (bytes / 1048576).toFixed(1) + " MiB"; // The lines, kept while the box is collapsed and drawn when it's opened (`showConsole`). const consoleLines = []; -function consoleLine([when, text]) { - return el("div", {}, el("span", { class: "when" }, when + " "), text); +// A line: when, what, and the messages by kind, each kind in its colour. +function consoleLine([when, text, kinds]) { + const parts = []; + for (const [kind, count] of kinds) { + if (parts.length) parts.push(", "); + parts.push(el("span", { style: "color: " + kindColour(kind) }, kind), " " + count); + } + return el("div", {}, el("span", { class: "when" }, when + " "), text, " (", ...parts, ")"); } function logTraffic(way, peer, total, kinds) { - const parts = Object.entries(kinds).map(([kind, grown]) => kind + " " + grown.messages) - .join(", "); const bytes = Object.values(kinds).reduce((sum, grown) => sum + grown.bytes, 0); const line = [new Date().toLocaleTimeString(), - (way === "sent" ? "→ " : "← ") + name(peer) + ": " + total + ", " + size(bytes) + - " (" + parts + ")"]; + (way === "sent" ? "→ " : "← ") + name(peer) + ": " + total + ", " + size(bytes), + Object.entries(kinds).map(([kind, grown]) => [kind, grown.messages])]; consoleLines.push(line); if (consoleLines.length > CONSOLE_LINES) consoleLines.shift(); if (hidden(document.getElementById("console-box"))) return; @@ -1592,7 +1618,7 @@ function drawFlows() { const p = positions.get(flow.from), q = positions.get(flow.to); if (now < flow.start || !p || !q) continue; const t = (now - flow.start) / FLOW_MS; - dots.push({ x: p.x + (q.x - p.x) * t, y: p.y + (q.y - p.y) * t, r: flow.r, + dots.push({ x: p.x + (q.x - p.x) * t, y: p.y + (q.y - p.y) * t, r: flow.r, kind: flow.kind, opacity: Math.sin(Math.PI * t) }); } while (layer.children.length < dots.length) layer.append(svg("circle")); @@ -1602,7 +1628,7 @@ function drawFlows() { circle.setAttribute("cx", dot.x); circle.setAttribute("cy", dot.y); circle.setAttribute("r", dot.r.toFixed(1)); - circle.setAttribute("fill", "var(--self)"); + circle.setAttribute("fill", kindColour(dot.kind)); circle.setAttribute("opacity", dot.opacity.toFixed(2)); }); if (flows.length > 0) flowFrame = requestAnimationFrame(drawFlows); |
