fix: fix RTT y-axis label clipping, add x-axis tickmarks, enlarge charts
Y-axis labels on the RTT chart were truncated above 99ms because the left margin was a fixed guess; it's now sized to the widest tick label. The x-axis only showed start/end timestamps; added evenly spaced intermediate tickmarks and labels. Plot area enlarged 15%. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -827,13 +827,10 @@
|
|||||||
if (!el || pts.length < 2) { if (el) el.style.display = 'none'; return; }
|
if (!el || pts.length < 2) { if (el) el.style.display = 'none'; return; }
|
||||||
|
|
||||||
const unitSuffix = opts.unitSuffix || '';
|
const unitSuffix = opts.unitSuffix || '';
|
||||||
const W = 600, H = 80, PAD = { top: 6, right: 8, bottom: 18, left: 28 };
|
const W = 690, H = 92, PAD = { top: 6, right: 8, bottom: 18, left: 28 };
|
||||||
const cW = W - PAD.left - PAD.right;
|
|
||||||
const cH = H - PAD.top - PAD.bottom;
|
|
||||||
|
|
||||||
const tMin = pts[0].t, tMax = pts[pts.length - 1].t;
|
const tMin = pts[0].t, tMax = pts[pts.length - 1].t;
|
||||||
const tRange = tMax - tMin || 1;
|
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
|
// Auto-scale Y axis with 10% padding, optionally clamped to opts.yDomain
|
||||||
const vMin = Math.min(...pts.map(p => p.v));
|
const vMin = Math.min(...pts.map(p => p.v));
|
||||||
@@ -845,6 +842,23 @@
|
|||||||
const yLow = Math.max(domainLow, vMin - vPad);
|
const yLow = Math.max(domainLow, vMin - vPad);
|
||||||
const yHigh = Math.min(domainHigh, vMax + vPad);
|
const yHigh = Math.min(domainHigh, vMax + vPad);
|
||||||
const yRange = yHigh - yLow || 1;
|
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;
|
const y = v => PAD.top + cH - ((v - yLow) / yRange) * cH;
|
||||||
|
|
||||||
// Color based on latest value
|
// Color based on latest value
|
||||||
@@ -879,27 +893,29 @@
|
|||||||
areaPaths += `<path d="${segArea}" fill="${fillColor}" opacity="0.6"/>`;
|
areaPaths += `<path d="${segArea}" fill="${fillColor}" opacity="0.6"/>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 = '';
|
let gridLines = '';
|
||||||
for (let v = tickStart; v <= yHigh + 0.001; v += niceStep) {
|
yTicks.forEach((v, i) => {
|
||||||
const yy = y(v).toFixed(1);
|
const yy = y(v).toFixed(1);
|
||||||
const label = (Number.isInteger(v) ? v : v.toFixed(1)) + unitSuffix;
|
|
||||||
gridLines += `<line x1="${PAD.left}" y1="${yy}" x2="${PAD.left + cW}" y2="${yy}" stroke="#e0e0e0" stroke-width="1"/>`;
|
gridLines += `<line x1="${PAD.left}" y1="${yy}" x2="${PAD.left + cW}" y2="${yy}" stroke="#e0e0e0" stroke-width="1"/>`;
|
||||||
gridLines += `<text x="${(PAD.left - 3).toFixed(1)}" y="${yy}" text-anchor="end" dominant-baseline="middle" font-size="8" fill="#999">${label}</text>`;
|
gridLines += `<text x="${(PAD.left - 3).toFixed(1)}" y="${yy}" text-anchor="end" dominant-baseline="middle" font-size="8" fill="#999">${yTickLabels[i]}</text>`;
|
||||||
}
|
});
|
||||||
|
|
||||||
// X-axis time labels
|
// X-axis: start/end plus evenly spaced intermediate tickmarks + labels
|
||||||
const fmt = ts => {
|
const fmt = ts => {
|
||||||
const d = new Date(ts * 1000);
|
const d = new Date(ts * 1000);
|
||||||
return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||||
};
|
};
|
||||||
const xLabels = `
|
const xTickCount = 5;
|
||||||
<text x="${PAD.left}" y="${H - 2}" text-anchor="start" font-size="8" fill="#999">${fmt(pts[0].t)}</text>
|
const xAxisY = (PAD.top + cH).toFixed(1);
|
||||||
<text x="${PAD.left + cW}" y="${H - 2}" text-anchor="end" font-size="8" fill="#999">${fmt(pts[pts.length-1].t)}</text>`;
|
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 += `<line x1="${xx}" y1="${xAxisY}" x2="${xx}" y2="${(PAD.top + cH + 3).toFixed(1)}" stroke="#ccc" stroke-width="1"/>`;
|
||||||
|
xLabels += `<text x="${xx}" y="${H - 2}" text-anchor="${anchor}" font-size="8" fill="#999">${fmt(t)}</text>`;
|
||||||
|
}
|
||||||
|
|
||||||
el.innerHTML = `<svg viewBox="0 0 ${W} ${H}" preserveAspectRatio="none"
|
el.innerHTML = `<svg viewBox="0 0 ${W} ${H}" preserveAspectRatio="none"
|
||||||
style="width:100%;height:${H}px;display:block;">
|
style="width:100%;height:${H}px;display:block;">
|
||||||
@@ -915,6 +931,7 @@
|
|||||||
${areaPaths}
|
${areaPaths}
|
||||||
${linePolylines}
|
${linePolylines}
|
||||||
</g>
|
</g>
|
||||||
|
${xAxisMarks}
|
||||||
${xLabels}
|
${xLabels}
|
||||||
</svg>`;
|
</svg>`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user