118 lines
2.8 KiB
Vue
118 lines
2.8 KiB
Vue
<script setup lang="ts">
|
|
import {
|
|
CategoryScale,
|
|
Chart,
|
|
Filler,
|
|
LinearScale,
|
|
LineController,
|
|
LineElement,
|
|
PointElement,
|
|
Tooltip,
|
|
type ChartConfiguration,
|
|
} from 'chart.js';
|
|
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
labels: string[];
|
|
values: number[];
|
|
/** Series label, shown in the tooltip title area. */
|
|
label?: string;
|
|
/** Builds the tooltip text for a value, e.g. "3 actions". */
|
|
formatValue?: (value: number) => string;
|
|
height?: number;
|
|
}>(),
|
|
{ height: 365 },
|
|
);
|
|
|
|
Chart.register(
|
|
LineController,
|
|
LineElement,
|
|
PointElement,
|
|
LinearScale,
|
|
CategoryScale,
|
|
Filler,
|
|
Tooltip,
|
|
);
|
|
|
|
const canvas = ref<HTMLCanvasElement | null>(null);
|
|
let chart: Chart | null = null;
|
|
|
|
const BRAND = '#179970';
|
|
|
|
function config(): ChartConfiguration {
|
|
return {
|
|
type: 'line',
|
|
data: {
|
|
labels: props.labels,
|
|
datasets: [
|
|
{
|
|
label: props.label ?? '',
|
|
backgroundColor: 'transparent',
|
|
borderColor: BRAND,
|
|
pointBackgroundColor: BRAND,
|
|
data: props.values,
|
|
},
|
|
],
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
x: { grid: { display: false } },
|
|
y: {
|
|
beginAtZero: true,
|
|
grid: { color: '#f6f6f6' },
|
|
border: { display: false },
|
|
// Registrations and activity counts are whole numbers.
|
|
ticks: { precision: 0 },
|
|
},
|
|
},
|
|
plugins: {
|
|
legend: { display: false },
|
|
tooltip: {
|
|
titleMarginBottom: 15,
|
|
callbacks: {
|
|
label: (item) =>
|
|
props.formatValue
|
|
? ` ${props.formatValue(Number(item.parsed.y))}`
|
|
: ` ${item.parsed.y}`,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
onMounted(() => {
|
|
if (canvas.value) {
|
|
chart = new Chart(canvas.value, config());
|
|
}
|
|
});
|
|
|
|
watch(
|
|
() => [props.labels, props.values],
|
|
() => {
|
|
if (!chart) {
|
|
return;
|
|
}
|
|
|
|
chart.data.labels = props.labels;
|
|
chart.data.datasets[0].data = props.values;
|
|
chart.update();
|
|
},
|
|
{ deep: true },
|
|
);
|
|
|
|
onBeforeUnmount(() => {
|
|
chart?.destroy();
|
|
chart = null;
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div :style="{ height: `${height}px` }">
|
|
<canvas ref="canvas" />
|
|
</div>
|
|
</template>
|