优化Again
This commit is contained in:
@@ -74,6 +74,7 @@ class AreaChart {
|
|||||||
const ctx = this.ctx;
|
const ctx = this.ctx;
|
||||||
const w = this.width;
|
const w = this.width;
|
||||||
const h = this.height;
|
const h = this.height;
|
||||||
|
this.padding = { top: 20, right: 16, bottom: 32, left: 64 };
|
||||||
const p = this.padding;
|
const p = this.padding;
|
||||||
const chartW = w - p.left - p.right;
|
const chartW = w - p.left - p.right;
|
||||||
const chartH = h - p.top - p.bottom;
|
const chartH = h - p.top - p.bottom;
|
||||||
@@ -89,22 +90,48 @@ class AreaChart {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find max
|
// Find max raw value
|
||||||
let maxVal = 0;
|
let maxDataVal = 0;
|
||||||
for (let i = 0; i < rx.length; i++) {
|
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 len = timestamps.length;
|
||||||
const xStep = chartW / (len - 1);
|
const xStep = chartW / (len - 1);
|
||||||
|
|
||||||
// Helper to get point
|
// Helper to get point
|
||||||
const getX = (i) => p.left + i * xStep;
|
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
|
// Draw grid lines
|
||||||
ctx.strokeStyle = 'rgba(99, 102, 241, 0.06)';
|
ctx.strokeStyle = 'rgba(99, 102, 241, 0.08)';
|
||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 1;
|
||||||
const gridLines = 4;
|
const gridLines = 4;
|
||||||
for (let i = 0; i <= gridLines; i++) {
|
for (let i = 0; i <= gridLines; i++) {
|
||||||
@@ -114,12 +141,15 @@ class AreaChart {
|
|||||||
ctx.lineTo(p.left + chartW, y);
|
ctx.lineTo(p.left + chartW, y);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
// Y-axis labels
|
// Y-axis labels - share the same unit for readability
|
||||||
const val = maxVal * (1 - i / gridLines);
|
const valInUnit = niceMaxInUnit * (1 - i / gridLines);
|
||||||
ctx.fillStyle = '#5a6380';
|
ctx.fillStyle = '#5a6380';
|
||||||
ctx.font = '10px "JetBrains Mono", monospace';
|
ctx.font = '10px "JetBrains Mono", monospace';
|
||||||
ctx.textAlign = 'right';
|
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)
|
// X-axis labels (every ~4 hours)
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ function formatBytes(bytes, decimals = 2) {
|
|||||||
if (!bytes || bytes === 0) return '0 B';
|
if (!bytes || bytes === 0) return '0 B';
|
||||||
const k = 1024;
|
const k = 1024;
|
||||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
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);
|
const value = bytes / Math.pow(k, i);
|
||||||
return value.toFixed(decimals) + ' ' + sizes[i];
|
return value.toFixed(decimals) + ' ' + sizes[i];
|
||||||
}
|
}
|
||||||
@@ -21,7 +22,8 @@ function formatBandwidth(bytesPerSec, decimals = 2) {
|
|||||||
if (!bytesPerSec || bytesPerSec === 0) return '0 B/s';
|
if (!bytesPerSec || bytesPerSec === 0) return '0 B/s';
|
||||||
const k = 1024;
|
const k = 1024;
|
||||||
const sizes = ['B/s', 'KB/s', 'MB/s', 'GB/s', 'TB/s'];
|
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);
|
const value = bytesPerSec / Math.pow(k, i);
|
||||||
return value.toFixed(decimals) + ' ' + sizes[i];
|
return value.toFixed(decimals) + ' ' + sizes[i];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user