优化一点东西 懒得写了

This commit is contained in:
CN-JS-HuiBai
2026-04-04 22:35:05 +08:00
parent 286eb1687d
commit e77bdbcc9e
3 changed files with 217 additions and 98 deletions

View File

@@ -278,7 +278,7 @@ class MetricChart {
constructor(canvas, unit = '') {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.data = { timestamps: [], values: [] };
this.data = { timestamps: [], values: [], series: null };
this.unit = unit; // '%', 'B/s', etc.
this.dpr = window.devicePixelRatio || 1;
this.padding = { top: 10, right: 10, bottom: 20, left: 60 };
@@ -305,7 +305,7 @@ class MetricChart {
}
setData(data) {
this.data = data || { timestamps: [], values: [] };
this.data = data || { timestamps: [], values: [], series: null };
this.animate();
}
@@ -333,7 +333,7 @@ class MetricChart {
ctx.clearRect(0, 0, w, h);
const { timestamps, values } = this.data;
const { timestamps, values, series } = this.data;
if (!timestamps || timestamps.length < 2) {
ctx.fillStyle = '#5a6380';
ctx.font = '11px sans-serif';
@@ -342,15 +342,21 @@ class MetricChart {
return;
}
// Find max with cushion
let maxVal = Math.max(...values, 0.1);
if (this.unit === '%' && maxVal <= 100) {
if (maxVal > 80) maxVal = 100;
else if (maxVal > 40) maxVal = 80;
else if (maxVal > 20) maxVal = 50;
else maxVal = 25;
// Determine Y max
let maxVal = 0;
if (series) {
// For stacked CPU, max sum should be 100
maxVal = 100;
} else {
maxVal = maxVal * 1.25;
maxVal = Math.max(...values, 0.1);
if (this.unit === '%' && maxVal <= 100) {
if (maxVal > 80) maxVal = 100;
else if (maxVal > 40) maxVal = 80;
else if (maxVal > 20) maxVal = 50;
else maxVal = 25;
} else {
maxVal = maxVal * 1.25;
}
}
const len = timestamps.length;
@@ -382,41 +388,102 @@ class MetricChart {
ctx.fillText(label, p.left - 8, y + 3);
}
// Path
ctx.beginPath();
ctx.moveTo(getX(0), getY(values[0]));
for (let i = 1; i < len; i++) {
const prevX = getX(i - 1);
const currX = getX(i);
const prevY = getY(values[i - 1]);
const currY = getY(values[i]);
const midX = (prevX + currX) / 2;
ctx.bezierCurveTo(midX, prevY, midX, currY, currX, currY);
}
// Stroke
ctx.strokeStyle = '#6366f1';
ctx.lineWidth = 2;
ctx.lineJoin = 'round';
ctx.stroke();
if (series) {
// Draw Stacked Area
const modes = [
{ name: 'idle', color: 'rgba(100, 116, 139, 0.4)', stroke: '#64748b' }, // Slate
{ name: 'other', color: 'rgba(168, 85, 247, 0.5)', stroke: '#a855f7' }, // Purple
{ name: 'irq', color: 'rgba(234, 179, 8, 0.5)', stroke: '#eab308' }, // Yellow
{ name: 'iowait', color: 'rgba(239, 68, 68, 0.5)', stroke: '#ef4444' }, // Red
{ name: 'system', color: 'rgba(6, 182, 212, 0.5)', stroke: '#06b6d4' }, // Cyan
{ name: 'user', color: 'rgba(99, 102, 241, 0.5)', stroke: '#6366f1' } // Indigo
];
// Fill
ctx.lineTo(getX(len - 1), p.top + chartH);
ctx.lineTo(getX(0), p.top + chartH);
ctx.closePath();
const grad = ctx.createLinearGradient(0, p.top, 0, p.top + chartH);
grad.addColorStop(0, 'rgba(99, 102, 241, 0.15)');
grad.addColorStop(1, 'rgba(99, 102, 241, 0)');
ctx.fillStyle = grad;
ctx.fill();
// Last point pulse
const lastX = getX(len - 1);
const lastY = getY(values[len - 1]);
ctx.beginPath();
ctx.arc(lastX, lastY, 3, 0, Math.PI * 2);
ctx.fillStyle = '#6366f1';
ctx.fill();
let currentBase = new Array(len).fill(0);
modes.forEach(mode => {
const vals = series[mode.name];
if (!vals) return;
ctx.beginPath();
ctx.moveTo(getX(0), getY(currentBase[0] + vals[0]));
for (let i = 1; i < len; i++) {
ctx.lineTo(getX(i), getY(currentBase[i] + vals[i]));
}
ctx.lineTo(getX(len - 1), getY(currentBase[len - 1]));
for (let i = len - 1; i >= 0; i--) {
ctx.lineTo(getX(i), getY(currentBase[i]));
}
ctx.closePath();
ctx.fillStyle = mode.color;
ctx.fill();
// Stroke
ctx.beginPath();
ctx.moveTo(getX(0), getY(currentBase[0] + vals[0]));
for (let i = 1; i < len; i++) {
ctx.lineTo(getX(i), getY(currentBase[i] + vals[i]));
}
ctx.strokeStyle = mode.stroke;
ctx.lineWidth = 1;
ctx.stroke();
// Update base
for (let i = 0; i < len; i++) {
currentBase[i] += vals[i];
}
});
// Add Legend at bottom right
ctx.font = '9px sans-serif';
ctx.textAlign = 'right';
let lx = w - 10;
let ly = h - 5;
[...modes].reverse().forEach(m => {
ctx.fillStyle = m.stroke;
ctx.fillRect(lx - 10, ly - 8, 8, 8);
ctx.fillStyle = '#5a6380';
ctx.fillText(m.name.charAt(0).toUpperCase() + m.name.slice(1), lx - 15, ly - 1);
lx -= 60;
});
} else {
// Draw Single Line Path
ctx.beginPath();
ctx.moveTo(getX(0), getY(values[0]));
for (let i = 1; i < len; i++) {
const prevX = getX(i - 1);
const currX = getX(i);
const prevY = getY(values[i - 1]);
const currY = getY(values[i]);
const midX = (prevX + currX) / 2;
ctx.bezierCurveTo(midX, prevY, midX, currY, currX, currY);
}
// Stroke
ctx.strokeStyle = '#6366f1';
ctx.lineWidth = 2;
ctx.lineJoin = 'round';
ctx.stroke();
// Fill
ctx.lineTo(getX(len - 1), p.top + chartH);
ctx.lineTo(getX(0), p.top + chartH);
ctx.closePath();
const grad = ctx.createLinearGradient(0, p.top, 0, p.top + chartH);
grad.addColorStop(0, 'rgba(99, 102, 241, 0.15)');
grad.addColorStop(1, 'rgba(99, 102, 241, 0)');
ctx.fillStyle = grad;
ctx.fill();
// Last point pulse
const lastX = getX(len - 1);
const lastY = getY(values[len - 1]);
ctx.beginPath();
ctx.arc(lastX, lastY, 3, 0, Math.PI * 2);
ctx.fillStyle = '#6366f1';
ctx.fill();
}
}
destroy() {