Treemap
Part-to-whole as nested rectangles sized by area, laid out with the squarify algorithm so tiles stay close to square instead of degenerating into slivers.
src/components/ui/treemap.tsxAbout
From the component's own source, where it was written.
Part-to-whole as nested rectangles, sized by area.
**Squarified, not sliced.** The naive layout cuts the space into strips, which produces slivers — rectangles hundreds of times longer than they are wide. Slivers cannot be labelled, are almost impossible to compare, and are hard to hit with a pointer. This uses the squarify algorithm (Bruls, Huizing, van Wijk): it grows a row while the worst aspect ratio in that row improves, and closes it as soon as adding the next item would make it worse. The result is tiles close to square at every size.
**Area encodes the value, and area is read poorly.** People judge area far less accurately than length, so a treemap is the right choice for "what is big, roughly, and what is inside what" and the wrong one for "is A bigger than B" when A and B are close — for that, use a bar chart. The honest use is disk usage, bundle composition, spend by category: hierarchies where the nesting matters and precision does not.
**Labels are drawn only where they fit.** A label wider or taller than its tile is not truncated to an ellipsis that tells you nothing; it is dropped, and the tile keeps its tooltip. Everything about the value stays reachable through the title and the legend.
Install
npx astralyx-ui add treemap
Usage
import { Treemap } from '@/components/ui/treemap'
<Treemap nodes={nodes} depth={2} />Composer
Change the props and the source below follows.
<Treemap
nodes={nodes}
depth={2}
/>Examples
A bundle, by module
<Treemap nodes={bundle} valueFormat={(b) => `${(b / 1000).toFixed(0)} kB`} />API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
Treemap
Extends Omit<ComponentProps<'figure'>, 'height' | 'onSelect'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| nodes | TreemapNode[] | required | { id, label, value?, children?, color? }. Parents sum their children. |
| height | number | 320 | — |
| depth | number | 2 | 1 flattens the hierarchy to its top level. |
| valueFormat | (value: number) => string | DEFAULT_FORMAT | — |
| onSelect | (node: TreemapNode) => void | — | — |
| gap | number | 2 | Gap between tiles, in pixels. |
| emptyLabel | string | 'Nothing to show.' | — |
| label | string | 'Treemap' | — |
Types
TreemapNode
Part-to-whole as nested rectangles, sized by area.
| Field | Type | Description |
|---|---|---|
| id | string | — |
| label | string | — |
| value? | number | Leaf magnitude. Ignored when children is present — parents sum. |
| children? | TreemapNode[] | — |
| color? | string | — |
Behaviour
| Topic | Detail | Description |
|---|---|---|
| squarified | not sliced | The strip layout produces rectangles hundreds of times longer than they are wide — unlabellable, incomparable, hard to hit. Squarify keeps the worst aspect ratio in each row as low as it can. |
| area | read poorly | People judge area far less accurately than length. Right for "what is big, roughly, and what is inside what"; wrong for "is A bigger than B" when they are close. |
| labels | dropped, not truncated | A label that does not fit is removed rather than ellipsised into nothing. The value stays reachable through the tooltip. |