mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-08-05 20:18:19 -04:00
97 lines
2.4 KiB
Vue
97 lines
2.4 KiB
Vue
<script setup lang="ts">
|
|
import type { ChartDataset, ChartOptions, ChartType } from 'chart.js';
|
|
|
|
const COLOURS = [
|
|
'#C71585',
|
|
'#dc3545',
|
|
'#fd7e14',
|
|
'#ffc107',
|
|
'#198754',
|
|
'#20c997',
|
|
'#0dcaf0',
|
|
'#0d6efd',
|
|
'#6610f2',
|
|
'#6f42c1',
|
|
'#d63384',
|
|
];
|
|
|
|
export type Dataset = Record<number | string, number>;
|
|
|
|
const props = withDefaults(defineProps<{
|
|
label: string;
|
|
data: Dataset[] | Dataset;
|
|
cumulative?: boolean;
|
|
type?: ChartType;
|
|
options?: ChartOptions;
|
|
}>(), {
|
|
type: 'line',
|
|
options: () => ({
|
|
responsive: true,
|
|
interaction: {
|
|
intersect: false,
|
|
mode: 'index',
|
|
},
|
|
}),
|
|
});
|
|
|
|
onMounted(async () => {
|
|
await drawChart();
|
|
});
|
|
|
|
const buildDataset = (data: Dataset, label: string, colour: string): ChartDataset => {
|
|
return {
|
|
label,
|
|
data: props.cumulative
|
|
? accumulate(Object.values(data))
|
|
: Object.values(data),
|
|
fill: false,
|
|
backgroundColor: colour,
|
|
borderColor: colour,
|
|
};
|
|
};
|
|
const isMultiDataset = (data: Dataset[] | Dataset): data is Dataset[] => {
|
|
return Object.values(data).length > 0 && typeof Object.values(data)[0] === 'object';
|
|
};
|
|
|
|
const canvas = useTemplateRef<HTMLCanvasElement>('canvas');
|
|
const drawChart = async () => {
|
|
if (!canvas.value) {
|
|
throw new Error('cannot find canvas');
|
|
}
|
|
|
|
let colourIndex = 0;
|
|
const { default: Chart } = await import('chart.js/auto');
|
|
new Chart(canvas.value, {
|
|
type: props.type,
|
|
data: {
|
|
labels: isMultiDataset(props.data)
|
|
? Array.from(Object.values(props.data).reduce((carry, item) => {
|
|
for (const key in item) {
|
|
carry.add(key);
|
|
}
|
|
return carry;
|
|
}, new Set()))
|
|
: Object.keys(props.data),
|
|
datasets: isMultiDataset(props.data)
|
|
? Object.entries(props.data).map(([key, data]) => buildDataset(data, key, COLOURS[colourIndex++ % COLOURS.length]))
|
|
: [buildDataset(props.data, props.label, COLOURS[0])],
|
|
},
|
|
options: props.options,
|
|
});
|
|
};
|
|
|
|
const accumulate = (values: number[]): number[] => {
|
|
const newValues = [];
|
|
let acc = 0;
|
|
for (const v of values) {
|
|
acc += v;
|
|
newValues.push(acc);
|
|
}
|
|
return newValues;
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<canvas ref="canvas"></canvas>
|
|
</template>
|