feat: auto-scale CPU history graph Y axis
Y axis now fits the actual data range with 10% padding rather than fixed 0-100%. Grid lines use nice tick steps (1/2/5/10 × magnitude). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -975,7 +975,16 @@
|
|||||||
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;
|
const x = t => PAD.left + ((t - tMin) / tRange) * cW;
|
||||||
const y = v => PAD.top + cH - (Math.min(v, 100) / 100) * cH;
|
|
||||||
|
// Auto-scale Y axis with 10% padding, clamped to [0, 100]
|
||||||
|
const vMin = Math.min(...pts.map(p => p.v));
|
||||||
|
const vMax = Math.max(...pts.map(p => p.v));
|
||||||
|
const vRange = vMax - vMin || 1;
|
||||||
|
const vPad = Math.max(vRange * 0.1, 1);
|
||||||
|
const yLow = Math.max(0, vMin - vPad);
|
||||||
|
const yHigh = Math.min(100, vMax + vPad);
|
||||||
|
const yRange = yHigh - yLow || 1;
|
||||||
|
const y = v => PAD.top + cH - ((v - yLow) / yRange) * cH;
|
||||||
|
|
||||||
// Build polyline points and filled area path
|
// Build polyline points and filled area path
|
||||||
const linePoints = pts.map(p => `${x(p.t).toFixed(1)},${y(p.v).toFixed(1)}`).join(' ');
|
const linePoints = pts.map(p => `${x(p.t).toFixed(1)},${y(p.v).toFixed(1)}`).join(' ');
|
||||||
@@ -983,17 +992,22 @@
|
|||||||
pts.map(p => `L${x(p.t).toFixed(1)},${y(p.v).toFixed(1)}`).join(' ') +
|
pts.map(p => `L${x(p.t).toFixed(1)},${y(p.v).toFixed(1)}`).join(' ') +
|
||||||
` L${x(pts[pts.length-1].t).toFixed(1)},${(PAD.top + cH).toFixed(1)} Z`;
|
` L${x(pts[pts.length-1].t).toFixed(1)},${(PAD.top + cH).toFixed(1)} Z`;
|
||||||
|
|
||||||
// Color based on latest value
|
// Color based on latest absolute CPU %
|
||||||
const latest = pts[pts.length - 1].v;
|
const latest = pts[pts.length - 1].v;
|
||||||
const strokeColor = latest > 90 ? '#e53935' : latest > 70 ? '#fb8c00' : '#43a047';
|
const strokeColor = latest > 90 ? '#e53935' : latest > 70 ? '#fb8c00' : '#43a047';
|
||||||
const fillColor = latest > 90 ? '#ffcdd2' : latest > 70 ? '#ffe0b2' : '#c8e6c9';
|
const fillColor = latest > 90 ? '#ffcdd2' : latest > 70 ? '#ffe0b2' : '#c8e6c9';
|
||||||
|
|
||||||
// Y-axis grid lines at 25, 50, 75, 100
|
// 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 (const pct of [25, 50, 75, 100]) {
|
for (let v = tickStart; v <= yHigh + 0.001; v += niceStep) {
|
||||||
const yy = y(pct).toFixed(1);
|
const yy = y(v).toFixed(1);
|
||||||
|
const label = Number.isInteger(v) ? v : v.toFixed(1);
|
||||||
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">${pct}</text>`;
|
gridLines += `<text x="${(PAD.left - 3).toFixed(1)}" y="${yy}" text-anchor="end" dominant-baseline="middle" font-size="8" fill="#999">${label}</text>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// X-axis time labels
|
// X-axis time labels
|
||||||
|
|||||||
Reference in New Issue
Block a user