Skip to content

Add TreeMap component for hierarchical data visualization - #123

Merged
jalexw merged 3 commits into
mainfrom
claude/upbeat-knuth-rsuma6
Sep 26, 2026
Merged

jalexw merged 3 commits into
mainfrom
claude/upbeat-knuth-rsuma6

Conversation

@jalexw

@jalexw jalexw commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds a new TreeMap component to Charts & Graphs for part-of-whole data: cases with more parts than a pie chart can label clearly, or data that is hierarchical. Each tile's area is proportional to its value. It uses the squarified layout (Bruls, Huizing & van Wijk, 2000), draws in pure SVG and adds no new dependencies.

The branch is up to date with main through 0.109.2 (#122, #124, #125).

Key Changes

  • New TreeMap component (src/components/ui/treemap/treemap.tsx):

    • Squarified layout: a row keeps growing only while that improves its worst aspect ratio, so tiles stay close to square and are easy to compare by eye
    • Supports any nesting depth through each node's children. A branch's value is always the sum of its children
    • maxDepth collapses deeper levels into the nearest ancestor that is drawn, and that ancestor keeps the subtree's total value
    • Three paint variants: soft (translucent fill, the default), solid (full fill, with a label halo in the background colour via paint-order: stroke so labels stay readable in light and dark mode) and outline (border only)
    • Six preset colours from @schemavaults/theme. Descendants inherit their ancestor's colour at a lower fill opacity (depthFillFalloff), and a raw fill overrides the preset
    • Custom label and value formatters. Labels are hidden on tiles too small to fit them
    • Tiles become keyboard-reachable buttons (Enter/Space) once a click handler is passed in
    • Four fixed canvas sizes (sm–xl), with width/height overrides
  • Storybook stories (src/components/ui/treemap/TreeMap.stories.tsx) under Charts & Graphs/TreeMap, with 12 entries. Three of them have play() tests:

    • Interactive: activates tiles with a mouse click and with the keyboard
    • LayoutInvariants: one tile per node, every tile inside the canvas, areas in value order, at least 80% of the canvas covered
    • Nested: every group name is drawn, and every leaf sits inside its parent group
  • Public exports: src/components/ui/treemap/index.ts, also added to src/components/ui/index.ts

  • Version: 0.109.2 (main) → 0.110.1

Notable Implementation Details

  • The layout is exact. I rendered it on the server and measured the rects. With tileGap: 0 the tiles cover 100% of the canvas, none overlap, and each tile's area matches its share of the total up to floating-point error.
  • Bug fixed during review: the default groupHeaderHeight (16) was smaller than minLabelHeight (18). The leaf-size check also ran on branch headers, so with the default settings every group name was hidden. minLabelHeight now applies only to leaves, and the Nested story has a regression test for it.
  • Merges from main: the only conflicts were the barrel exports in src/components/ui/index.ts (kept both sides) and the package.json version, twice, because main released 0.109.x on its own.

For reviewers

  • Colour convention: 0.109.0 - Refactor charts to use shared primitives and add Histogram #122 added the chart-primitives palette (chart-1…chart-8). TreeMap still uses the older default/primary/positive/warning/destructive/muted preset maps, the same ones FunnelChart and RadarChart still use. Theme 0.29.0 still has every token those maps need, so nothing breaks. Moving TreeMap to chart-primitives would change the exported TreeMapColorId type and would add the shared tooltip and legend. I can do that here or in a follow-up.
  • TreeMap uses fixed canvas sizes. It does not use the new ResponsiveChart sizing yet.
  • The default tileGap of 2 costs about 2% of the canvas area at lg.

Verification (on head 538c650)

  • typecheck, typecheck:storybook, lint, build: all pass
  • test:unit: 14/14
  • Storybook test runner: 136 suites, 1165 tests, all passing

🤖 Generated with Claude Code

https://claude.ai/code/session_01Px7WyxT4i2wTrj5ZvabCr6

TreeMap renders a squarified treemap (Bruls, Huizing & van Wijk, 2000) for
part-of-whole data that has more parts than a pie chart can label legibly,
or that is hierarchical: storage per collection, rows per table grouped by
schema, spend per project.

- Pure-SVG layout, no new dependencies. Rows are grown only while they
  improve the worst aspect ratio, so tiles stay close to square and are
  comparable by eye. Verified exact: tiles cover 100% of the canvas with
  `tileGap: 0`, never overlap, and each area is proportional to its value
  to within floating-point error.
- Arbitrary nesting via each node's `children`, with `maxDepth` to collapse
  deeper levels into their nearest rendered ancestor (which keeps the
  subtree's aggregate value). Labelled branches get a header band.
- Three paint variants: `soft` (default), `solid` and `outline`. Colors come
  from the @schemavaults/theme palette, so the chart tracks light and dark
  mode; descendants inherit their ancestor's color at a reduced fill opacity
  so each branch reads as one family. `solid` gives labels a
  background-colored halo (`paint-order: stroke`) to keep them legible on
  saturated fills in both brightness themes.
- Tiles become keyboard-reachable buttons as soon as a click handler is
  supplied, matching the other charts in the library.

The story covers the flat and nested cases, all sizes and variants, raw
fills, percentage labels, three-level nesting and the empty state, plus
interaction tests for mouse and keyboard activation and layout-invariant
tests (bounds, ordering, coverage, and child-inside-parent containment).

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Px7WyxT4i2wTrj5ZvabCr6
@vercel

vercel Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
ui Ready Ready Preview Sep 26, 2026 3:18pm UTC

Request Review

Brings in the chart upgrades from #122: the `chart-primitives` module (the
`--chart-1`..`--chart-8` categorical palette, scales, tooltips, legends,
responsive sizing), the new Histogram and BarList components, the upgrades to
BarChart / LineChart / PieChart / ScatterPlot / Sparkline, the `test:unit`
script and its CI job, and @schemavaults/theme 0.29.0.

Conflicts resolved:

- src/components/ui/index.ts - both sides appended exports after
  ./scatter-plot. Kept both; ./treemap now follows ./histogram and ./bar-list.
- package.json - main shipped 0.109.0 independently, so this branch moves to
  0.110.0 rather than reusing a published version.

TreeMap is unaffected by the theme bump: 0.29.0 adds the `--chart-*` tokens
without removing `--schemavaults-brand-blue`, `--warning` or `--destructive`,
which is what its palette maps resolve against.

Verified on the merge result: typecheck, typecheck:storybook, lint and build
clean; `bun run test:unit` 14/14; Storybook suite 136 suites / 1165 tests
passing.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Px7WyxT4i2wTrj5ZvabCr6
Brings in 0.109.1 (LineChart area fill follows the smoothed curve) and
0.109.2 (Storybook test runner waits for the reduced-motion change event).

The only conflict was the package.json version: main moved to 0.109.2, and
this branch goes to 0.110.1.

Verified on the merge result: typecheck, typecheck:storybook, lint and build
clean; test:unit 14/14; Storybook suite 136 suites / 1165 tests passing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Px7WyxT4i2wTrj5ZvabCr6
@jalexw jalexw self-assigned this Sep 26, 2026
@jalexw
jalexw merged commit 02661e5 into main Sep 26, 2026
12 checks passed
@jalexw
jalexw deleted the claude/upbeat-knuth-rsuma6 branch September 26, 2026 15:23

This branch was successfully deployed

1 active deployment
Preview — 538c6506 Deployed Sep 26, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants