refactor: Implement reactive chart rendering and cleanup using Svelte's $effect on the analytics page.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import Chart from "chart.js/auto";
|
||||
import Card from "$lib/components/ui/Card.svelte";
|
||||
@@ -9,10 +8,15 @@
|
||||
let { data } = $props();
|
||||
let analytics = $derived(data.analytics);
|
||||
|
||||
// svelte-ignore non_reactive_update
|
||||
let timelineCanvas: HTMLCanvasElement;
|
||||
// svelte-ignore non_reactive_update
|
||||
let pieCanvas: HTMLCanvasElement;
|
||||
// svelte-ignore non_reactive_update
|
||||
let electricityCanvas: HTMLCanvasElement;
|
||||
// svelte-ignore non_reactive_update
|
||||
let costCanvas: HTMLCanvasElement;
|
||||
// svelte-ignore non_reactive_update
|
||||
let printerCanvas: HTMLCanvasElement;
|
||||
|
||||
// Time range options
|
||||
@@ -23,10 +27,9 @@
|
||||
{ value: "365", label: "1 Year" },
|
||||
{ value: "all", label: "All Time" },
|
||||
];
|
||||
let selectedRange = $state(analytics.range);
|
||||
let selectedRange = $derived(analytics.range);
|
||||
|
||||
function changeRange(range: string) {
|
||||
selectedRange = range;
|
||||
goto(`/analytics?range=${range}`);
|
||||
}
|
||||
|
||||
@@ -49,7 +52,21 @@
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i];
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
// Chart instances
|
||||
let timelineChart: Chart | null = null;
|
||||
let pieChart: Chart | null = null;
|
||||
let electricityChart: Chart | null = null;
|
||||
let costChart: Chart | null = null;
|
||||
let printerChart: Chart | null = null;
|
||||
|
||||
$effect(() => {
|
||||
// Cleanup previous charts
|
||||
if (timelineChart) timelineChart.destroy();
|
||||
if (pieChart) pieChart.destroy();
|
||||
if (electricityChart) electricityChart.destroy();
|
||||
if (costChart) costChart.destroy();
|
||||
if (printerChart) printerChart.destroy();
|
||||
|
||||
const chartColors = [
|
||||
"#3b82f6",
|
||||
"#8b5cf6",
|
||||
@@ -60,10 +77,11 @@
|
||||
];
|
||||
|
||||
// 1. Timeline Chart - Filament Usage
|
||||
if (timelineCanvas) {
|
||||
const dates = Object.keys(analytics.usageByDate).slice(-30);
|
||||
const weights = dates.map((d) => analytics.usageByDate[d]);
|
||||
|
||||
new Chart(timelineCanvas, {
|
||||
timelineChart = new Chart(timelineCanvas, {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: dates.map((d) =>
|
||||
@@ -101,12 +119,14 @@
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Material Pie Chart
|
||||
if (pieCanvas) {
|
||||
const materials = Object.keys(analytics.materialUsage);
|
||||
const matWeights = materials.map((m) => analytics.materialUsage[m]);
|
||||
|
||||
new Chart(pieCanvas, {
|
||||
pieChart = new Chart(pieCanvas, {
|
||||
type: "doughnut",
|
||||
data: {
|
||||
labels: materials,
|
||||
@@ -122,20 +142,25 @@
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: { position: "right", labels: { color: "#94a3b8" } },
|
||||
legend: {
|
||||
position: "right",
|
||||
labels: { color: "#94a3b8" },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 3. Electricity Usage Chart
|
||||
const electricDates = Object.keys(analytics.electricityByDate).slice(
|
||||
-30,
|
||||
);
|
||||
if (electricityCanvas) {
|
||||
const electricDates = Object.keys(
|
||||
analytics.electricityByDate,
|
||||
).slice(-30);
|
||||
const electricityWh = electricDates.map(
|
||||
(d) => analytics.electricityByDate[d] / 1000,
|
||||
);
|
||||
|
||||
new Chart(electricityCanvas, {
|
||||
electricityChart = new Chart(electricityCanvas, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: electricDates.map((d) =>
|
||||
@@ -165,7 +190,11 @@
|
||||
y: {
|
||||
grid: { color: "rgba(255,255,255,0.1)" },
|
||||
ticks: { color: "#94a3b8" },
|
||||
title: { display: true, text: "kWh", color: "#94a3b8" },
|
||||
title: {
|
||||
display: true,
|
||||
text: "kWh",
|
||||
color: "#94a3b8",
|
||||
},
|
||||
},
|
||||
x: {
|
||||
grid: { display: false },
|
||||
@@ -174,12 +203,14 @@
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 4. Cost Chart
|
||||
if (costCanvas) {
|
||||
const costDates = Object.keys(analytics.costByDate).slice(-30);
|
||||
const costs = costDates.map((d) => analytics.costByDate[d]);
|
||||
|
||||
new Chart(costCanvas, {
|
||||
costChart = new Chart(costCanvas, {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: costDates.map((d) =>
|
||||
@@ -220,10 +251,11 @@
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 5. Printer Usage Chart
|
||||
if (analytics.printerStats.length > 0) {
|
||||
new Chart(printerCanvas, {
|
||||
if (printerCanvas && analytics.printerStats.length > 0) {
|
||||
printerChart = new Chart(printerCanvas, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: analytics.printerStats.map(
|
||||
@@ -620,9 +652,7 @@
|
||||
<p class="text-2xl font-bold text-purple-400">
|
||||
{formatBytes(analytics.totalModelSize)}
|
||||
</p>
|
||||
<p class="text-xs text-slate-400 uppercase">
|
||||
Storage Used
|
||||
</p>
|
||||
<p class="text-xs text-slate-400 uppercase">Storage Used</p>
|
||||
</div>
|
||||
</div>
|
||||
{#if analytics.topModels.length > 0}
|
||||
|
||||
Reference in New Issue
Block a user