forked from wrenn/wrenn
Split CPU and RAM into separate side-by-side charts
CPU (vCPUs) and RAM (GB) use different units and scales, so combining them on a dual-axis chart was misleading. Each now has its own chart card, laid out side-by-side.
This commit is contained in:
@ -16,11 +16,14 @@
|
|||||||
let error = $state<string | null>(null);
|
let error = $state<string | null>(null);
|
||||||
|
|
||||||
let canvasRunning: HTMLCanvasElement;
|
let canvasRunning: HTMLCanvasElement;
|
||||||
let canvasResource: HTMLCanvasElement;
|
let canvasCpu: HTMLCanvasElement;
|
||||||
|
let canvasRam: HTMLCanvasElement;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
let chartRunning: any = null;
|
let chartRunning: any = null;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
let chartResource: any = null;
|
let chartCpu: any = null;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
let chartRam: any = null;
|
||||||
|
|
||||||
let pollInterval: ReturnType<typeof setInterval> | null = null;
|
let pollInterval: ReturnType<typeof setInterval> | null = null;
|
||||||
|
|
||||||
@ -48,11 +51,15 @@
|
|||||||
chartRunning.data.datasets[0].data = Array.from(stats.series.running);
|
chartRunning.data.datasets[0].data = Array.from(stats.series.running);
|
||||||
chartRunning.update();
|
chartRunning.update();
|
||||||
}
|
}
|
||||||
if (chartResource) {
|
if (chartCpu) {
|
||||||
chartResource.data.labels = labels;
|
chartCpu.data.labels = labels;
|
||||||
chartResource.data.datasets[0].data = Array.from(stats.series.vcpus);
|
chartCpu.data.datasets[0].data = Array.from(stats.series.vcpus);
|
||||||
chartResource.data.datasets[1].data = Array.from(stats.series.memory_mb).map((mb) => +(mb / 1024).toFixed(2));
|
chartCpu.update();
|
||||||
chartResource.update();
|
}
|
||||||
|
if (chartRam) {
|
||||||
|
chartRam.data.labels = labels;
|
||||||
|
chartRam.data.datasets[0].data = Array.from(stats.series.memory_mb).map((mb) => +(mb / 1024).toFixed(2));
|
||||||
|
chartRam.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,63 +161,61 @@
|
|||||||
options: BASE_CHART_OPTIONS,
|
options: BASE_CHART_OPTIONS,
|
||||||
});
|
});
|
||||||
|
|
||||||
chartResource = new Chart(canvasResource, {
|
chartCpu = new Chart(canvasCpu, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: {
|
data: {
|
||||||
labels: [],
|
labels: [],
|
||||||
datasets: [
|
datasets: [{
|
||||||
{
|
|
||||||
label: 'vCPUs',
|
|
||||||
data: [],
|
data: [],
|
||||||
borderColor: C_BLUE,
|
borderColor: C_BLUE,
|
||||||
backgroundColor: C_BLUE_FILL,
|
backgroundColor: C_BLUE_FILL,
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
fill: false,
|
fill: true,
|
||||||
tension: 0,
|
tension: 0,
|
||||||
pointRadius: 0,
|
pointRadius: 0,
|
||||||
pointHoverRadius: 4,
|
pointHoverRadius: 4,
|
||||||
pointHoverBackgroundColor: C_BLUE,
|
pointHoverBackgroundColor: C_BLUE,
|
||||||
yAxisID: 'y',
|
}],
|
||||||
},
|
},
|
||||||
{
|
options: {
|
||||||
label: 'RAM (GB)',
|
...BASE_CHART_OPTIONS,
|
||||||
|
scales: {
|
||||||
|
...BASE_CHART_OPTIONS.scales,
|
||||||
|
y: {
|
||||||
|
...BASE_CHART_OPTIONS.scales.y,
|
||||||
|
ticks: {
|
||||||
|
...BASE_CHART_OPTIONS.scales.y.ticks,
|
||||||
|
callback: (v: number) => `${v}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
chartRam = new Chart(canvasRam, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: [],
|
||||||
|
datasets: [{
|
||||||
data: [],
|
data: [],
|
||||||
borderColor: C_AMBER,
|
borderColor: C_AMBER,
|
||||||
backgroundColor: C_AMBER_FILL,
|
backgroundColor: C_AMBER_FILL,
|
||||||
borderWidth: 1.5,
|
borderWidth: 1.5,
|
||||||
fill: false,
|
fill: true,
|
||||||
tension: 0,
|
tension: 0,
|
||||||
pointRadius: 0,
|
pointRadius: 0,
|
||||||
pointHoverRadius: 4,
|
pointHoverRadius: 4,
|
||||||
pointHoverBackgroundColor: C_AMBER,
|
pointHoverBackgroundColor: C_AMBER,
|
||||||
yAxisID: 'yRam',
|
}],
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
...BASE_CHART_OPTIONS,
|
...BASE_CHART_OPTIONS,
|
||||||
plugins: {
|
plugins: {
|
||||||
...BASE_CHART_OPTIONS.plugins,
|
...BASE_CHART_OPTIONS.plugins,
|
||||||
legend: {
|
|
||||||
display: true,
|
|
||||||
position: 'top' as const,
|
|
||||||
align: 'end' as const,
|
|
||||||
labels: {
|
|
||||||
color: C_TICK,
|
|
||||||
font: { family: FONT_MONO, size: 10 },
|
|
||||||
boxWidth: 12,
|
|
||||||
padding: 12,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tooltip: {
|
tooltip: {
|
||||||
...BASE_CHART_OPTIONS.plugins.tooltip,
|
...BASE_CHART_OPTIONS.plugins.tooltip,
|
||||||
callbacks: {
|
callbacks: {
|
||||||
label: (ctx: { dataset: { label?: string }; parsed: { y: number } }) => {
|
label: (ctx: { parsed: { y: number } }) => ` ${ctx.parsed.y.toFixed(1)} GB`,
|
||||||
if (ctx.dataset.label === 'RAM (GB)') {
|
|
||||||
return ` RAM: ${ctx.parsed.y.toFixed(1)} GB`;
|
|
||||||
}
|
|
||||||
return ` vCPUs: ${ctx.parsed.y}`;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -218,16 +223,10 @@
|
|||||||
...BASE_CHART_OPTIONS.scales,
|
...BASE_CHART_OPTIONS.scales,
|
||||||
y: {
|
y: {
|
||||||
...BASE_CHART_OPTIONS.scales.y,
|
...BASE_CHART_OPTIONS.scales.y,
|
||||||
position: 'left' as const,
|
ticks: {
|
||||||
title: { display: true, text: 'vCPUs', color: C_TICK, font: { family: FONT_MONO, size: 10 } },
|
...BASE_CHART_OPTIONS.scales.y.ticks,
|
||||||
|
callback: (v: number) => `${(+v).toFixed(1)} GB`,
|
||||||
},
|
},
|
||||||
yRam: {
|
|
||||||
grid: { color: C_GRID },
|
|
||||||
ticks: { color: C_TICK, font: { family: FONT_MONO, size: 10 } },
|
|
||||||
border: { color: C_GRID },
|
|
||||||
beginAtZero: true,
|
|
||||||
position: 'right' as const,
|
|
||||||
title: { display: true, text: 'GB', color: C_TICK, font: { family: FONT_MONO, size: 10 } },
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -242,7 +241,8 @@
|
|||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
if (pollInterval) clearInterval(pollInterval);
|
if (pollInterval) clearInterval(pollInterval);
|
||||||
chartRunning?.destroy();
|
chartRunning?.destroy();
|
||||||
chartResource?.destroy();
|
chartCpu?.destroy();
|
||||||
|
chartRam?.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
function fmtGB(mb: number): string {
|
function fmtGB(mb: number): string {
|
||||||
@ -391,26 +391,37 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Reserved CPU & RAM -->
|
<!-- CPU & RAM side by side -->
|
||||||
|
<div class="grid grid-cols-2 gap-5">
|
||||||
|
|
||||||
|
<!-- CPU -->
|
||||||
<div class="flex flex-col rounded-[var(--radius-card)] border border-[var(--color-border)] bg-[var(--color-bg-2)]">
|
<div class="flex flex-col rounded-[var(--radius-card)] border border-[var(--color-border)] bg-[var(--color-bg-2)]">
|
||||||
<div class="border-b border-[var(--color-border)] px-6 py-4">
|
<div class="border-b border-[var(--color-border)] px-6 py-4">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-2">
|
||||||
<span class="flex items-center gap-1.5">
|
|
||||||
<span class="h-[6px] w-[6px] rounded-full" style="background: #5a9fd4"></span>
|
<span class="h-[6px] w-[6px] rounded-full" style="background: #5a9fd4"></span>
|
||||||
<span class="text-label font-semibold uppercase tracking-[0.06em] text-[var(--color-text-tertiary)]">CPU</span>
|
<span class="text-label font-semibold uppercase tracking-[0.06em] text-[var(--color-text-tertiary)]">CPU · vCPUs</span>
|
||||||
</span>
|
|
||||||
<span class="text-label text-[var(--color-text-muted)]">/</span>
|
|
||||||
<span class="flex items-center gap-1.5">
|
|
||||||
<span class="h-[6px] w-[6px] rounded-full" style="background: #d4a73c"></span>
|
|
||||||
<span class="text-label font-semibold uppercase tracking-[0.06em] text-[var(--color-text-tertiary)]">RAM</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative flex-1 px-5 pb-5 pt-3" style="min-height: 220px">
|
<div class="relative flex-1 px-5 pb-5 pt-3" style="min-height: 220px">
|
||||||
<canvas bind:this={canvasResource}></canvas>
|
<canvas bind:this={canvasCpu}></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- RAM -->
|
||||||
|
<div class="flex flex-col rounded-[var(--radius-card)] border border-[var(--color-border)] bg-[var(--color-bg-2)]">
|
||||||
|
<div class="border-b border-[var(--color-border)] px-6 py-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="h-[6px] w-[6px] rounded-full" style="background: #d4a73c"></span>
|
||||||
|
<span class="text-label font-semibold uppercase tracking-[0.06em] text-[var(--color-text-tertiary)]">RAM · GB</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="relative flex-1 px-5 pb-5 pt-3" style="min-height: 220px">
|
||||||
|
<canvas bind:this={canvasRam}></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user