优化Again

This commit is contained in:
CN-JS-HuiBai
2026-04-04 19:56:03 +08:00
parent 694f5b5031
commit 9b113b6986
2 changed files with 43 additions and 11 deletions

View File

@@ -74,6 +74,7 @@ class AreaChart {
const ctx = this.ctx;
const w = this.width;
const h = this.height;
this.padding = { top: 20, right: 16, bottom: 32, left: 64 };
const p = this.padding;
const chartW = w - p.left - p.right;
const chartH = h - p.top - p.bottom;
@@ -89,22 +90,48 @@ class AreaChart {
return;
}
// Find max
let maxVal = 0;
// Find max raw value
let maxDataVal = 0;
for (let i = 0; i < rx.length; i++) {
maxVal = Math.max(maxVal, rx[i] || 0, tx[i] || 0);
maxDataVal = Math.max(maxDataVal, rx[i] || 0, tx[i] || 0);
}
maxVal = maxVal * 1.15 || 1;
// Determine consistent unit based on max data value
const k = 1024;
const sizes = ['B/s', 'KB/s', 'MB/s', 'GB/s', 'TB/s'];
let unitIdx = Math.floor(Math.log(Math.max(1, maxDataVal)) / Math.log(k));
unitIdx = Math.max(0, Math.min(unitIdx, sizes.length - 1));
const unitFactor = Math.pow(k, unitIdx);
const unitLabel = sizes[unitIdx];
// Get value in current units and find a "nice" round max
// Use 1.15 cushion
const rawValInUnit = (maxDataVal * 1.15) / unitFactor;
let niceMaxInUnit;
if (rawValInUnit <= 1) niceMaxInUnit = 1;
else if (rawValInUnit <= 2) niceMaxInUnit = 2;
else if (rawValInUnit <= 5) niceMaxInUnit = 5;
else if (rawValInUnit <= 10) niceMaxInUnit = 10;
else if (rawValInUnit <= 20) niceMaxInUnit = 20;
else if (rawValInUnit <= 50) niceMaxInUnit = 50;
else if (rawValInUnit <= 100) niceMaxInUnit = 100;
else if (rawValInUnit <= 200) niceMaxInUnit = 200;
else if (rawValInUnit <= 500) niceMaxInUnit = 500;
else if (rawValInUnit <= 1000) niceMaxInUnit = 1000;
else niceMaxInUnit = Math.ceil(rawValInUnit / 100) * 100;
const maxVal = niceMaxInUnit * unitFactor;
const len = timestamps.length;
const xStep = chartW / (len - 1);
// Helper to get point
const getX = (i) => p.left + i * xStep;
const getY = (val) => p.top + chartH - (val / maxVal) * chartH * this.animProgress;
const getY = (val) => p.top + chartH - (val / (maxVal || 1)) * chartH * this.animProgress;
// Draw grid lines
ctx.strokeStyle = 'rgba(99, 102, 241, 0.06)';
ctx.strokeStyle = 'rgba(99, 102, 241, 0.08)';
ctx.lineWidth = 1;
const gridLines = 4;
for (let i = 0; i <= gridLines; i++) {
@@ -114,12 +141,15 @@ class AreaChart {
ctx.lineTo(p.left + chartW, y);
ctx.stroke();
// Y-axis labels
const val = maxVal * (1 - i / gridLines);
// Y-axis labels - share the same unit for readability
const valInUnit = niceMaxInUnit * (1 - i / gridLines);
ctx.fillStyle = '#5a6380';
ctx.font = '10px "JetBrains Mono", monospace';
ctx.textAlign = 'right';
ctx.fillText(formatBandwidth(val, 1), p.left - 8, y + 3);
// Format: "X.X MB/s" or "X MB/s"
const label = (valInUnit % 1 === 0 ? valInUnit : valInUnit.toFixed(1)) + ' ' + unitLabel;
ctx.fillText(label, p.left - 10, y + 3);
}
// X-axis labels (every ~4 hours)

View File

@@ -9,7 +9,8 @@ function formatBytes(bytes, decimals = 2) {
if (!bytes || bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k));
let i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k));
i = Math.max(0, Math.min(i, sizes.length - 1));
const value = bytes / Math.pow(k, i);
return value.toFixed(decimals) + ' ' + sizes[i];
}
@@ -21,7 +22,8 @@ function formatBandwidth(bytesPerSec, decimals = 2) {
if (!bytesPerSec || bytesPerSec === 0) return '0 B/s';
const k = 1024;
const sizes = ['B/s', 'KB/s', 'MB/s', 'GB/s', 'TB/s'];
const i = Math.floor(Math.log(Math.abs(bytesPerSec)) / Math.log(k));
let i = Math.floor(Math.log(Math.abs(bytesPerSec)) / Math.log(k));
i = Math.max(0, Math.min(i, sizes.length - 1));
const value = bytesPerSec / Math.pow(k, i);
return value.toFixed(decimals) + ' ' + sizes[i];
}