104 lines
2.5 KiB
TypeScript
104 lines
2.5 KiB
TypeScript
'use client';
|
|
|
|
import { useMemo } from 'react';
|
|
import { Pie } from 'react-chartjs-2';
|
|
import {
|
|
Chart as ChartJS,
|
|
ArcElement,
|
|
Tooltip,
|
|
Legend,
|
|
ChartOptions,
|
|
ChartDataset
|
|
} from 'chart.js';
|
|
import type { DayCount } from './ChartBar';
|
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
|
|
|
ChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);
|
|
|
|
type ChartPieProps = {
|
|
data: DayCount[];
|
|
legend?: boolean;
|
|
};
|
|
|
|
export default function ChartPie({ data, legend = true }: ChartPieProps) {
|
|
const isDark =
|
|
typeof window !== 'undefined' &&
|
|
window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
|
|
const chartData = useMemo(() => {
|
|
const labels = data.map(d => d.date);
|
|
const series = data.map(d => d.count);
|
|
|
|
return {
|
|
labels,
|
|
datasets: [
|
|
{
|
|
label: 'Erkennungen',
|
|
data: series,
|
|
backgroundColor: [
|
|
'#3b82f6', '#6366f1', '#10b981', '#f59e0b', '#ef4444',
|
|
'#8b5cf6', '#ec4899', '#f97316', '#14b8a6', '#84cc16',
|
|
'#22d3ee', '#a78bfa', '#eab308', '#fb7185'
|
|
],
|
|
borderColor: isDark ? '#1f2937' : '#ffffff',
|
|
borderWidth: 1
|
|
}
|
|
]
|
|
};
|
|
}, [data, isDark]);
|
|
|
|
const options: ChartOptions<'pie'> = useMemo(() => ({
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
display: legend,
|
|
position: 'bottom',
|
|
labels: {
|
|
color: isDark ? '#a3a3a3' : '#4b5563'
|
|
}
|
|
},
|
|
tooltip: {
|
|
callbacks: {
|
|
label: (context) => {
|
|
const value = context.raw;
|
|
const label = context.label;
|
|
return `${label}: ${value} Erkennungen`;
|
|
}
|
|
}
|
|
},
|
|
datalabels: {
|
|
color: isDark ? '#d1d5db' : '#374151',
|
|
font: {
|
|
weight: 'bold' as const,
|
|
size: 12
|
|
},
|
|
anchor: 'end',
|
|
align: 'start',
|
|
offset: 6,
|
|
clamp: true,
|
|
display: (ctx) => {
|
|
const dataset = ctx.chart.data.datasets[0] as ChartDataset<'pie', number[]>;;
|
|
const total = dataset.data.reduce((sum: number, val: number) => sum + val, 0);
|
|
const value = dataset.data[ctx.dataIndex] as number;
|
|
return value / total >= 0.03;
|
|
}
|
|
},
|
|
layout: {
|
|
padding: 20
|
|
},
|
|
clip: false,
|
|
},
|
|
animation: {
|
|
animateRotate: true,
|
|
animateScale: true,
|
|
duration: 800,
|
|
easing: 'easeOutCubic'
|
|
}
|
|
}), [isDark, legend]);
|
|
|
|
return (
|
|
<Pie data={chartData} options={options} />
|
|
);
|
|
}
|