import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip, Legend, Filler } from 'chart.js'; import ChartDataLabels from 'chartjs-plugin-datalabels'; import Annotation from 'chartjs-plugin-annotation'; // Register ChartJS components once ChartJS.register( CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip, Legend, Filler, ChartDataLabels, Annotation ); export const chartColors = { primary: '#2563eb', secondary: '#7c3aed', tertiary: '#0891b2', success: '#059669', danger: '#dc2626', muted: '#94a3b8', grid: '#e2e8f0' // fallback only; use getChartTheme().border at runtime }; export function getChartTheme() { const style = getComputedStyle(document.documentElement); const get = (v: string) => style.getPropertyValue(v).trim(); return { surface: get('--surface') || '#ffffff', textPrimary: get('--text-primary') || '#0f172a', textMuted: get('--text-muted') || '#64748b', border: get('--border') || '#e2e8f0', textInverse: get('--text-inverse') || '#ffffff', }; } // Extended palette for charts with many categories (events, channels) export const chartPalette = [ '#2563eb', // blue '#7c3aed', // purple '#0891b2', // cyan '#059669', // emerald '#d97706', // amber '#e11d48', // rose '#4f46e5', // indigo '#0d9488', // teal '#c026d3', // fuchsia '#ea580c', // orange ]; export const createDataLabelConfig = (showDataLabels: boolean, overrides?: { color?: string; backgroundColor?: string }): any => ({ display: showDataLabels, color: overrides?.color ?? '#1e293b', font: { size: 10, weight: 600 }, anchor: 'end', align: 'end', offset: 4, padding: 4, backgroundColor: overrides?.backgroundColor ?? 'rgba(255, 255, 255, 0.85)', borderRadius: 3, textDirection: 'ltr', // Force LTR for numbers - fixes RTL misalignment formatter: (value: number | null) => { if (value == null) return ''; if (value >= 1000000) return (value / 1000000).toFixed(2) + 'M'; if (value >= 1000) return (value / 1000).toFixed(2) + 'K'; if (value < 100 && value > 0) return value.toFixed(2); return Math.round(value).toLocaleString(); } }); export const createBaseOptions = (showDataLabels: boolean): any => { const theme = getChartTheme(); return { responsive: true, maintainAspectRatio: false, locale: 'en-US', // Force LTR number formatting layout: { padding: { top: showDataLabels ? 25 : 5, right: 5, bottom: 5, left: 5 } }, plugins: { legend: { display: false }, tooltip: { backgroundColor: theme.surface, titleColor: theme.textPrimary, bodyColor: theme.textMuted, borderColor: theme.border, borderWidth: 1, padding: 12, cornerRadius: 8, titleFont: { size: 12 }, bodyFont: { size: 11 }, rtl: false, textDirection: 'ltr' }, datalabels: createDataLabelConfig(showDataLabels, { color: theme.textPrimary, backgroundColor: theme.surface + 'dd', }) }, scales: { x: { grid: { display: false }, ticks: { font: { size: 10 }, color: theme.textMuted } }, y: { grid: { color: theme.border }, ticks: { font: { size: 10 }, color: theme.textMuted }, border: { display: false } } } }; }; export const lineDatasetDefaults = { borderWidth: 2, tension: 0.4, fill: true, pointRadius: 0, pointHoverRadius: 4 }; export const barDatasetDefaults = { borderRadius: 4 };