Skip to content

Commit 3b8edee

Browse files
committed
docs: add recharts poc report
1 parent 83f1fb9 commit 3b8edee

1 file changed

Lines changed: 70 additions & 0 deletions

File tree

docs/recharts-poc-report.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Recharts — POC Report
2+
3+
**Date:** 2026-06-09
4+
**Author:** Serhii Shramko
5+
**Demo route:** `/labs/recharts` (animations on) / `/labs/recharts?perf=1` (animations off)
6+
**Source:** `components/recharts-poc/`
7+
**Plan:** `docs/superpowers/plans/2026-06-09-recharts-poc-plan.md` (local-only)
8+
**Design spec:** `docs/superpowers/specs/2026-06-09-recharts-poc-design.md` (local-only)
9+
10+
## Verdict
11+
12+
**Ship — conditional on perf finding on Marta's Lenovo.** Recharts cleanly satisfies every functional acceptance criterion attempted in this POC: bar/line/dual-axis/histogram/donut charts, a sortable breakdown table, period-over-period deltas, label position control, label toggling, legend-driven series visibility, and tooltips. The library is actively maintained, fully typed, well-documented, and the API surface for our use cases is small. The only open question is rendering performance on low-spec hardware, captured in the "Weak-laptop test" section below; the `?perf=1` opt-out gives Marta a clean A/B test on her Lenovo.
13+
14+
## Functional acceptance criteria
15+
16+
| # | Criterion | Status | Evidence | Notes |
17+
|---|-----------|:------:|----------|-------|
18+
| 1 | Bar chart w/ rounded corners + custom colors || `components/recharts-poc/charts/BarChartCard.tsx` | `radius={[8,8,0,0]}` on `<Bar>`; per-bar `<Cell fill>`; colors driven by `usePalette()` so the palette adapts to theme. |
19+
| 2 | Line chart w/ splines || `components/recharts-poc/charts/LineChartCard.tsx` | `<Line type="monotone">` + `<Area>` fill overlay for the long-tail series. |
20+
| 3 | Dual-axis different scales || `components/recharts-poc/charts/DualAxisChartCard.tsx` | `<ComposedChart>` + two `<YAxis yAxisId="left" \| "right">` with independent orientations, tick formatters, and colours. |
21+
| 4 | Histogram comparing 2 metrics | ⚠️ | `components/recharts-poc/charts/HistogramCard.tsx` | Recharts has no native histogram primitive — we pre-bucket data in `mocks/keywordLength.ts` and render two `<Bar>` series side-by-side. Standard, idiomatic Recharts approach. |
22+
| 5 | Pie/donut chart with %-labels || `components/recharts-poc/charts/DonutCard.tsx` | `<Pie innerRadius={60} outerRadius={110}>` + custom percent-label renderer positioned outside the slice. Hover-grow via `activeShape={{ outerRadius: 120 }}` (note: Recharts 3.x drives this through internal Redux tooltip state, not the deprecated `activeIndex` prop). |
23+
| 6 | Table with metric breakdown || `components/recharts-poc/table/BreakdownTable.tsx` | Plain HTML table; sortable column headers; heat-tinted "position now" cell scaled by `\|delta\|/maxDelta`; Δ column rendered via shared `DeltaBadge`. |
24+
| 7 | Data labels with position control + format hooks || `<LabelList>` children across charts; position picker on `BarChartCard` | The bar chart exposes a `top / inside / center / insideTop` picker so a reviewer can see position control without reading source. Formatter hook used on bar + histogram (`Intl.NumberFormat('en-US')`). |
25+
| 8 | Toggle data labels on/off || `primitives/LabelsToggle.tsx` per chart | Bar, line, histogram each have an independent toggle. Donut renders labels always (it's unreadable without them). |
26+
| 9 | Period-over-period delta || `primitives/periodOverPeriod.ts` + `kpi/DeltaBadge.tsx` | Pure helper, fully tested (positive, negative, flat, zero-prev, zero-curr, both-zero). Renders `▲ +N%` / `▼ -N%` / `— 0%` and gracefully degrades to absolute delta when there's no prior-period baseline. |
27+
| 10 | Tooltips, legend visible, series toggle, responsive layout || `<ResponsiveContainer>` + `<Legend onClick>` + `hide` prop | Legend click toggles a local `Set<string>` of hidden series; the corresponding `<Bar hide>` / `<Line hide>` reads from it. Applied to line, histogram, dual-axis (bar and donut don't need it — single effective series). |
28+
29+
## Non-functional
30+
31+
| Criterion | Status | Evidence |
32+
|-----------|:------:|----------|
33+
| Last release ≤ 6 months || `recharts@3.8.1` released **2026-03-25** (npm registry). Today is 2026-06-09 — about 2.5 months ago. Well within the window. |
34+
| TypeScript types || Recharts ships its own types — no `@types/recharts` needed. The POC's `pnpm typecheck` is clean across 21 new files. Two type widenings were needed in v3 strict types: `Tooltip.formatter` / `LabelList.formatter` accept `(v: unknown) => ...`, and `Pie.activeShape` needs a cast to attach a plain object — both documented inline in the chart files. |
35+
| Documentation quality || recharts.org + Storybook stories were sufficient for every chart attempted. The only "discoverability" pain point is the v3 API rewrite around `Pie` hover behaviour, which has migrated from props to internal state — but the new behaviour is correct and the types make the right shape obvious. |
36+
| Bundle impact | ⚠️ | Measured from `next build` output via `.next/build-manifest.json`. **First Load JS (gzipped) — `/labs/recharts`: 315.0 kB vs homepage `/`: 206.0 kB → Δ ≈ 109 kB.** Raw uncompressed delta: ~393 kB (Recharts + d3-* family + Redux Toolkit + react-redux + immer, all from Recharts' transitive graph). Pages Router code-splits per route, so this is **route-local — the homepage and other pages are unaffected**. Reasonable for an analytics page; heavy for a marketing page. |
37+
38+
## Weak-laptop test (Marta's Lenovo)
39+
40+
To be filled in after running on the target hardware. Test instructions:
41+
42+
1. Open `http://shramko.dev/labs/recharts` (or local dev URL).
43+
2. Note cold-load time, scroll smoothness, tooltip lag, series-toggle responsiveness.
44+
3. Re-open `http://shramko.dev/labs/recharts?perf=1` (animations off) and repeat.
45+
4. Fill in the scores below (1 = unusable, 5 = smooth).
46+
47+
| Scenario | Animations on | Animations off |
48+
|----------|---------------|----------------|
49+
| Cold load to interactive | _ s | _ s |
50+
| Scroll smoothness (1–5) | _ | _ |
51+
| Tooltip lag (1–5) | _ | _ |
52+
| Series toggle response (1–5) | _ | _ |
53+
| Subjective verdict | _ | _ |
54+
55+
## Known limitations / workarounds
56+
57+
- **No native histogram primitive.** Recharts has no `HistogramChart` — we pre-bucket data and render with `<BarChart>` and two `<Bar>` series. This is the library-idiomatic approach.
58+
- **Legend `onClick` not wired by default.** We attach a small handler that toggles a local `Set<string>` of hidden series; each series reads `hide={hiddenSet.has(key)}`. ~6 lines per chart.
59+
- **`ResponsiveContainer` + SSR.** Under Pages Router SSR, `ResponsiveContainer` measures DOM dimensions before they exist and would render at 0×0 on first paint. Mitigated by a `useIsMounted()` guard in `ChartCard` that renders a same-height skeleton until the component mounts. No hydration warnings observed.
60+
- **`next-themes` flash on first render.** `resolvedTheme` is `undefined` on first render. `usePalette()` defaults to the light palette until mounted, then switches once `resolvedTheme` is available. Combined with the `ChartCard` mount guard, charts only paint once the theme is resolved.
61+
- **`Pie.activeIndex` removed in v3.** Hover-grow now flows through the chart's internal Redux tooltip state; the consumer just declares `activeShape={...}` and the active sector renders with those props automatically. Documented inline in `DonutCard.tsx`.
62+
- **Bundle size.** ~109 kB gzipped per route is real. Pages Router code-splits per route, so this is contained to `/labs/recharts` and any future chart pages; the rest of the site is unaffected.
63+
64+
## Extraction notes
65+
66+
To lift this POC into a separate app:
67+
68+
1. Copy `pages/labs/recharts.tsx` and the entire `components/recharts-poc/` folder.
69+
2. Install: `recharts`, `next-themes`, `clsx`, `lucide-react`, plus the new app's normal Next.js + Tailwind setup.
70+
3. The POC has zero imports reaching outside its own folder. Only the page file imports from the barrel `@/components/recharts-poc`. Verified by `grep -rn "recharts-poc" pages/ components/`.

0 commit comments

Comments
 (0)