From 9b113b698673b98fb064ca3d9e4916753800741e Mon Sep 17 00:00:00 2001 From: CN-JS-HuiBai Date: Sat, 4 Apr 2026 19:56:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96Again?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/chart.js | 48 +++++++++++++++++++++++++++++++++++++--------- public/js/utils.js | 6 ++++-- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/public/js/chart.js b/public/js/chart.js index 38e8b1e..9f39b65 100644 --- a/public/js/chart.js +++ b/public/js/chart.js @@ -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) diff --git a/public/js/utils.js b/public/js/utils.js index e8bf4e9..9d0fdc1 100644 --- a/public/js/utils.js +++ b/public/js/utils.js @@ -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]; }