/* FinPulse charts — hand-rolled responsive SVG. Exports to window. */ const { useRef, useState, useEffect, useLayoutEffect } = React; // measure container width function useWidth() { const ref = useRef(null); const [w, setW] = useState(600); useLayoutEffect(() => { if (!ref.current) return; const ro = new ResizeObserver((entries) => { const cw = entries[0].contentRect.width; if (cw > 0) setW(cw); }); ro.observe(ref.current); return () => ro.disconnect(); }, []); return [ref, w]; } function buildPath(data, w, h, padTop, padBottom) { const min = Math.min(...data), max = Math.max(...data); const range = max - min || 1; const usableH = h - padTop - padBottom; const step = data.length > 1 ? w / (data.length - 1) : 0; const pts = data.map((v, i) => [i * step, padTop + usableH - ((v - min) / range) * usableH]); const line = pts.map((p, i) => (i === 0 ? `M${p[0]},${p[1]}` : `L${p[0]},${p[1]}`)).join(' '); const area = `${line} L${pts[pts.length - 1][0]},${h - padBottom} L0,${h - padBottom} Z`; return { line, area, pts, min, max }; } // ---------- Sparkline ---------- function Sparkline({ data, up, width = 80, height = 32, strokeWidth = 1.5 }) { const { line } = buildPath(data, width, height, 3, 3); const color = up ? 'var(--up)' : 'var(--down)'; return ( ); } // ---------- Area chart ---------- function AreaChart({ data, color = 'var(--accent)', height = 260, labels }) { const [ref, w] = useWidth(); const [hover, setHover] = useState(null); const padTop = 12, padBottom = 26, padRight = 0; const cw = Math.max(w - padRight, 10); const { line, area, pts, min, max } = buildPath(data, cw, height, padTop, padBottom); const gid = 'ag-' + Math.round(min); const gridVals = [max, (max + min) / 2, min]; const usableH = height - padTop - padBottom; function onMove(e) { const rect = ref.current.getBoundingClientRect(); const x = e.clientX - rect.left; const step = cw / (data.length - 1); let idx = Math.round(x / step); idx = Math.max(0, Math.min(data.length - 1, idx)); setHover(idx); } const last = data.length; const xLabels = labels || ['9:15', '11:00', '12:45', '14:30', '15:30']; return (