import React from 'react'; import { Svg, Line, Polyline, Rect, Text as SvgText, G } from '@react-pdf/renderer'; export const CHART_PALETTE = [ '#2563eb', '#0891b2', '#7c3aed', '#059669', '#d97706', '#dc2626', '#db2777', '#f59e0b', '#10b981', '#6366f1', '#0284c7', '#65a30d', ]; function fmtAxis(v: number): string { if (v >= 1_000_000) return `${(v / 1_000_000).toFixed(1)}M`; if (v >= 10_000) return `${Math.round(v / 1_000)}K`; if (v >= 1_000) return `${(v / 1_000).toFixed(1)}K`; return String(Math.round(v)); } interface TrendChartProps { labels: string[]; current: number[]; previous: number[] | null; color: string; series?: Array<{ label: string; color: string; data: number[] }>; width?: number; height?: number; } export function PdfTrendChart({ labels, current, previous, color, series, width = 470, height = 155 }: TrendChartProps) { const seriesValues = (series ?? []).flatMap(s => s.data); const allValues = [...current, ...(previous ?? []), ...seriesValues].filter(v => v > 0); const max = allValues.length > 0 ? Math.max(...allValues) : 1; // padL wide enough for y-axis labels like "1.2M" const padL = 38, padR = 8, padT = 10, padB = 20; const w = width - padL - padR; const h = height - padT - padB; const sx = (i: number) => padL + (labels.length > 1 ? (i / (labels.length - 1)) * w : w / 2); const sy = (v: number) => padT + h - (v / max) * h; const toPoints = (data: number[]) => data.map((v, i) => `${sx(i).toFixed(1)},${sy(v).toFixed(1)}`).join(' '); const gridLines = [0.25, 0.5, 0.75, 1.0]; return ( {/* Baseline */} {/* Grid lines + Y-axis labels */} {gridLines.map(f => { const yPos = sy(max * f); return ( {fmtAxis(max * f)} ); })} {/* Comparison line (dashed) */} {previous && previous.some(v => v > 0) && ( )} {/* Per-museum series */} {(series ?? []).map(s => s.data.some(v => v > 0) && ( ))} {/* Current period total line */} {current.some(v => v > 0) && ( = 2 ? 2 : 2.5} fill="none" /> )} {/* X-axis week labels */} {labels .filter((_, i) => labels.length <= 8 || i % Math.ceil(labels.length / 8) === 0) .map((label) => { const origIdx = labels.indexOf(label); return ( {label} ); })} ); } interface HBarChartProps { items: Array<{ name: string; value: number }>; color: string; usepalette?: boolean; width?: number; } export function PdfHBarChart({ items, color, usepalette = false, width = 470 }: HBarChartProps) { const barH = 17; const gap = 10; const labelW = 160; const barAreaW = width - labelW - 20; const max = Math.max(...items.map(i => i.value), 1); const totalH = items.length * (barH + gap); return ( {items.map((item, i) => { const y = i * (barH + gap); const bw = Math.max((item.value / max) * barAreaW, 2); const shortName = item.name.length > 26 ? item.name.slice(0, 26) + '…' : item.name; const valueStr = item.value.toLocaleString('en-SA', { maximumFractionDigits: 0 }); const barColor = usepalette ? CHART_PALETTE[i % CHART_PALETTE.length] : color; const isShort = bw < 48; return ( {shortName} {isShort ? ( {valueStr} ) : ( {valueStr} )} ); })} ); }