diff --git a/src/components/Report/reportCharts.tsx b/src/components/Report/reportCharts.tsx new file mode 100644 index 0000000..c71dbd2 --- /dev/null +++ b/src/components/Report/reportCharts.tsx @@ -0,0 +1,94 @@ +import React from 'react'; +import { Svg, Line, Polyline, Rect, Text as SvgText, G } from '@react-pdf/renderer'; + +interface TrendChartProps { + labels: string[]; + current: number[]; + previous: number[] | null; + color: string; + width?: number; + height?: number; +} + +export function PdfTrendChart({ labels, current, previous, color, width = 460, height = 140 }: TrendChartProps) { + const allValues = [...current, ...(previous ?? [])].filter(v => v > 0); + const max = allValues.length > 0 ? Math.max(...allValues) : 1; + const padL = 8, padR = 8, padT = 8, padB = 8; + 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 ( + + {gridLines.map(f => ( + + ))} + {previous && previous.some(v => v > 0) && ( + + )} + {current.some(v => v > 0) && ( + + )} + {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; + width?: number; +} + +export function PdfHBarChart({ items, color, width = 460 }: HBarChartProps) { + const barH = 16; + const gap = 10; + const labelW = 150; + const valueW = 70; + const barAreaW = width - labelW - valueW - 8; + 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 > 22 ? item.name.slice(0, 22) + '…' : item.name; + const valueStr = item.value.toLocaleString('en-SA', { maximumFractionDigits: 0 }); + return ( + + {shortName} + + {valueStr} + + ); + })} + + ); +}