Files
fnx_web/svelte/src/util/Chart.svelte
2026-01-26 22:23:36 +01:00

157 lines
3.0 KiB
Svelte

<script lang="ts">
import { onMount } from "svelte";
import { formatDataVolume, formatDuration, formatNumber } from "./Formatting";
import { color_by_name } from "./Util";
import {
Chart,
PointElement,
LineElement,
LinearScale,
CategoryScale,
LineController,
Filler,
Tooltip,
Legend,
type Tick,
} from "chart.js"
Chart.register(
PointElement,
LineElement,
LinearScale,
CategoryScale,
LineController,
Filler,
Tooltip,
Legend,
)
let chart_element: HTMLCanvasElement = $state()
let chart_object: Chart
let {
data_type = "",
legend = true,
tooltips = true,
ticks = true,
animations = true,
height = "300px"
}: {
data_type?: string;
legend?: boolean;
tooltips?: boolean;
ticks?: boolean;
animations?: boolean;
height?: string;
} = $props();
export const chart = () => {
return chart_object
}
export const data = () => {
return chart_object.data
}
export const update = () => {
return chart_object.update()
}
Chart.defaults.color = color_by_name("body_text_color");
Chart.defaults.font.size = 15;
Chart.defaults.font.family = "system-ui, sans-serif";
Chart.defaults.maintainAspectRatio = false;
Chart.defaults.plugins.tooltip.mode = "index";
Chart.defaults.plugins.tooltip.axis = "x";
Chart.defaults.plugins.tooltip.intersect = false;
onMount(() => {
chart_object = new Chart(
chart_element.getContext("2d"),
{
type: 'line',
data: {
labels: [],
datasets: [],
},
options: {
responsive: true,
// Only update the chart 100ms after the last time the container
// is resized. This fixes the stuttering that happens when the
// chart updates each frame
resizeDelay: 100,
plugins: {
legend: {
display: legend,
labels: {
boxWidth: 12,
boxHeight: 12,
}
},
tooltip: {
enabled: tooltips,
itemSort: (a, b): number => {
return <number>b.raw - <number>a.raw
},
},
},
layout: {
padding: {
left: 4,
right: 4,
}
},
scales: {
y: {
type: "linear",
display: true,
position: "left",
ticks: {
callback: function (value: number, index: number, values: Tick[]) {
if (data_type == "bytes") {
return formatDataVolume(value, 3);
} else if (data_type === "duration") {
return formatDuration(value, 2);
}
return formatNumber(value, 3);
},
},
beginAtZero: true,
grid: {
display: true,
color: color_by_name("separator"),
},
},
x: {
display: true,
ticks: {
display: ticks,
sampleSize: 1,
padding: 4,
minRotation: 0,
maxRotation: 0
},
grid: {
display: false,
}
}
},
}
}
);
if (!animations) {
chart_object.options.animation = false
chart_object.options.transitions.active.animation.duration = 0
}
})
</script>
<div class="chart-container" style="height: {height};">
<canvas bind:this={chart_element}></canvas>
</div>
<style>
.chart-container {
position: relative;
width: 100%;
}
</style>