No data
; const w = 600; const pad = { l: 0, r: 0, t: 14, b: showLabels ? 18 : 2 }; const m = max(data, (d) => d.value) ?? 0; const y = scaleLinear().domain([0, m || 1]).range([height - pad.b, pad.t]); const bw = (w - pad.l - pad.r) / data.length; const every = Math.ceil(data.length / 12); return ( ); } /** Horizontal bars with labels — for rankings (top orgs, categories). Uses HTML for crisp text. */ export function HBars({ data, className, color = 'var(--series-1)', format = fmtCompact, max: maxOverride, href }: { data: { label: string; value: number; sub?: string; href?: string }[]; className?: string; color?: string; format?: (v: number) => string; max?: number; href?: (d: { label: string }) => string | undefined }) { if (!data.length) returnNo data
; const m = (maxOverride ?? max(data, (d) => d.value) ?? 0) || 1; return (Not enough history
; const l = line<{ x: number; y: number }>() .x((p) => L.x(p.x)) .y((p) => L.y(p.y)) .curve(step ? curveStepAfter : curveMonotoneX); return ( ); } /** Step chart = LineChart in step mode (prices, statuses). */ export function StepChart(props: OmitNo data
; const lo = minOverride ?? (min(values) as number); const hi = maxOverride ?? (max(values) as number); const t = (v: number) => { const r = hi === lo ? 1 : (v - lo) / (hi - lo); const k = direction === 'lower' ? 1 - r : r; return Math.max(0, Math.min(1, k)); }; return (| {rowHeader} | {cols.map((c) => ({c.href ? ( {c.label} ) : ( c.label )} {c.sub && {c.sub}} | ))}|
|---|---|---|
| {r.href ? ( {r.label} ) : ( r.label )} {r.sub && {r.sub}} | {cols.map((c) => { const h = cell(r.key, c.key); const v = h?.value; if (v === null || v === undefined || !Number.isFinite(v)) return (— | ); const k = t(v); const pct = Math.round(8 + k * 72); const style = { background: `color-mix(in srgb, ${color} ${pct}%, var(--surface))`, color: k > 0.62 ? 'var(--accent-ink)' : 'var(--ink)' }; const text = h?.label ?? format(v); return ({h?.href ? {text} : text} | ); })}