diff --git a/hbd/server/templates/plugins.html b/hbd/server/templates/plugins.html
index bca788b..7244d02 100644
--- a/hbd/server/templates/plugins.html
+++ b/hbd/server/templates/plugins.html
@@ -827,13 +827,10 @@
if (!el || pts.length < 2) { if (el) el.style.display = 'none'; return; }
const unitSuffix = opts.unitSuffix || '';
- const W = 600, H = 80, PAD = { top: 6, right: 8, bottom: 18, left: 28 };
- const cW = W - PAD.left - PAD.right;
- const cH = H - PAD.top - PAD.bottom;
+ const W = 690, H = 92, PAD = { top: 6, right: 8, bottom: 18, left: 28 };
const tMin = pts[0].t, tMax = pts[pts.length - 1].t;
const tRange = tMax - tMin || 1;
- const x = t => PAD.left + ((t - tMin) / tRange) * cW;
// Auto-scale Y axis with 10% padding, optionally clamped to opts.yDomain
const vMin = Math.min(...pts.map(p => p.v));
@@ -845,6 +842,23 @@
const yLow = Math.max(domainLow, vMin - vPad);
const yHigh = Math.min(domainHigh, vMax + vPad);
const yRange = yHigh - yLow || 1;
+
+ // Compute nice tick step for ~3-5 grid lines, then size the left
+ // margin to fit the widest label (values/units can run to 3+ digits,
+ // e.g. RTT samples above 99ms) instead of a fixed guess that clips them.
+ const rawStep = yRange / 4;
+ const mag = Math.pow(10, Math.floor(Math.log10(rawStep || 1)));
+ const niceStep = [1, 2, 5, 10].map(f => f * mag).find(s => yRange / s <= 5) || mag * 10;
+ const tickStart = Math.ceil(yLow / niceStep) * niceStep;
+ const yTicks = [];
+ for (let v = tickStart; v <= yHigh + 0.001; v += niceStep) yTicks.push(v);
+ const yTickLabels = yTicks.map(v => (Number.isInteger(v) ? v : v.toFixed(1)) + unitSuffix);
+ const maxLabelLen = yTickLabels.reduce((m, s) => Math.max(m, s.length), 0);
+ PAD.left = Math.max(28, Math.ceil(maxLabelLen * 5.5) + 10);
+
+ const cW = W - PAD.left - PAD.right;
+ const cH = H - PAD.top - PAD.bottom;
+ const x = t => PAD.left + ((t - tMin) / tRange) * cW;
const y = v => PAD.top + cH - ((v - yLow) / yRange) * cH;
// Color based on latest value
@@ -879,27 +893,29 @@
areaPaths += ``;
}
- // Compute nice tick step for ~3-5 grid lines
- const rawStep = yRange / 4;
- const mag = Math.pow(10, Math.floor(Math.log10(rawStep || 1)));
- const niceStep = [1, 2, 5, 10].map(f => f * mag).find(s => yRange / s <= 5) || mag * 10;
- const tickStart = Math.ceil(yLow / niceStep) * niceStep;
let gridLines = '';
- for (let v = tickStart; v <= yHigh + 0.001; v += niceStep) {
+ yTicks.forEach((v, i) => {
const yy = y(v).toFixed(1);
- const label = (Number.isInteger(v) ? v : v.toFixed(1)) + unitSuffix;
gridLines += ``;
- gridLines += `${label}`;
- }
+ gridLines += `${yTickLabels[i]}`;
+ });
- // X-axis time labels
+ // X-axis: start/end plus evenly spaced intermediate tickmarks + labels
const fmt = ts => {
const d = new Date(ts * 1000);
return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
};
- const xLabels = `
- ${fmt(pts[0].t)}
- ${fmt(pts[pts.length-1].t)}`;
+ const xTickCount = 5;
+ const xAxisY = (PAD.top + cH).toFixed(1);
+ let xAxisMarks = '';
+ let xLabels = '';
+ for (let i = 0; i < xTickCount; i++) {
+ const t = tMin + (tRange * i) / (xTickCount - 1);
+ const xx = x(t).toFixed(1);
+ const anchor = i === 0 ? 'start' : (i === xTickCount - 1 ? 'end' : 'middle');
+ xAxisMarks += ``;
+ xLabels += `${fmt(t)}`;
+ }
el.innerHTML = ``;
}