/**
* TreemapChart — a total, cut into the things it is made of, by area.
*
* ```tsx
*
*
*
*
*
*
* ```
*
* ## What it is for, against the dial next door
*
* A pie and a treemap answer the same question — what is this total made of —
* and they fail at different sizes. A dial can carry five or six slices before
* the small ones become slivers with nowhere to put a name. A treemap keeps
* going, because a share is a rectangle rather than an angle: it can be read
* at a tenth the size, it tiles the box with nothing left over, and it has a
* flat side to write on.
*
* So the rule of thumb is the count. Up to about six parts, a `PieChart` is
* easier to read and more familiar. Past that, a treemap is the one that still
* works.
*
* The trade-off is precision. People compare angles badly and areas worse, so
* nobody should be reading values off the tiles — the layout is for *ranking
* and grouping* at a glance, and the numbers are in the labels.
*
* ## The layout
*
* Squarified. Tiles are laid in rows across whichever side of the remaining
* space is shorter, and a row takes another tile only while doing so makes its
* worst rectangle *less* elongated than it already is. The result is tiles
* close to square, which matters for two reasons: a square is the shape whose
* area the eye judges least badly, and it is the only shape with room for a
* name across it.
*
* It follows that the tiles are sorted, largest first, and the order is the
* chart's rather than the caller's. An unsorted treemap squarifies badly —
* rows end up mixing one large tile with several small ones, which is exactly
* the case the row test cannot rescue. Pass `sort={false}` where the given
* order carries meaning and the shapes may suffer for it.
*
* ## Too many parts
*
* A treemap of two hundred rows on a phone is a texture, not a chart. `maxTiles`
* keeps the largest few and gathers the rest into one tile, which is the honest
* summary of a long tail — the reader can see how much of the total it is worth
* instead of squinting at forty slivers that were never legible.
*
* ## Colour
*
* One hue, stepping down the ranking, rather than a colour per tile. The tiles
* are parts of one total and the area already says which is bigger, so a set of
* unrelated hues would be claiming a distinction that is not in the data — and
* a treemap has more parts than there are chart tokens, so they would repeat
* and two unrelated tiles would come out matching. A tile can still be given
* its own `color` where it means something, and that one is drawn at full
* strength against the ramp.
*/
import { type ReactNode } from 'react';
import { type ViewProps } from 'react-native';
/** Whether the chart is showing data or waiting for it. */
export type TreemapChartStatus = 'loading' | 'ready';
/** One part of the total. */
export interface TreemapDatum {
/** Name of the part, for the label, the readout and the legend. */
label: string;
/** Its size. Negatives are treated as zero — an area cannot be less than none. */
value: number;
/** Explicit colour, drawn at full strength instead of the ramp. */
color?: string;
}
/** A tile's box inside the chart, in points. */
export interface TreemapRect {
x: number;
y: number;
width: number;
height: number;
}
/** One laid-out tile: its datum, its share of the total, and where it sits. */
export interface TreemapTile extends TreemapRect {
label: string;
value: number;
/** Its share of the whole chart, `0` to `1`. */
share: number;
color: string;
/** How far along the ramp it is drawn, `0` to `1`. `1` where a colour was given. */
strength: number;
/**
* Its row in `data`, or `-1` for the gathered tile `maxTiles` makes, which
* stands for several rows and so belongs to none of them.
*/
sourceIndex: number;
}
/**
* Squarified treemap layout: values in, rectangles out, in the same order.
*
* Written out rather than taken from a layout dependency, because it is sixty
* lines and the alternative is shipping a tree library to call one function of.
*
* The shape of it: take the remaining box, and start a row along whichever of
* its sides is shorter. Add tiles to that row one at a time, and after each,
* ask what the worst aspect ratio in the row now is. While that number keeps
* falling the row is getting better and the tile is kept; the first tile that
* makes it rise is put back, the row is closed and laid out, and the box
* shrinks by the strip the row took.
*
* Rows go along the *shorter* side because a row is divided along its length
* and is a fixed depth: dividing the long side gives thin tiles, and the whole
* point of the exercise is not to have any.
*
* @param values Tile sizes. Must be non-negative, and should be descending.
* @param ratio The aspect ratio the row test aims at.
*/
export declare function squarifyLayout(values: number[], width: number, height: number, ratio?: number): TreemapRect[];
/**
* The selected tile, for something rendered *inside* the chart. A readout in
* the card's header is outside this provider — use `onActiveIndexChange` there.
*/
export declare function useTreemapChart(): {
/** Index into the tiles **as laid out**, which is the sorted order. */
activeIndex: number;
activeTile: TreemapTile | null;
tiles: TreemapTile[];
total: number;
};
export interface TreemapChartProps extends ViewProps {
className?: string;
/** The parts of the total, in any order. Sorted by the chart unless told not to. */
data: TreemapDatum[];
/** Width ÷ height of the box the tiles fill. */
aspectRatio?: number;
/** Space between one tile and the next, in points. */
gap?: number;
/** Corner radius of a tile, in points. */
cornerRadius?: number;
/**
* Sort the tiles largest first.
*
* On by default, and worth leaving on. The row test assumes a descending run
* — given a large tile next to a small one it has no good row to make, and
* the chart comes out as slivers. Turn it off only where the given order is
* itself the message.
*/
sort?: boolean;
/**
* Keep the largest `maxTiles` and gather the rest into one.
*
* A phone-width treemap runs out of legible tiles somewhere around twenty.
* Past that the tail is texture, and one tile that says how much the tail is
* worth is more use than forty that cannot be read or hit.
*/
maxTiles?: number;
/** What the gathered tile is called. */
otherLabel?: string;
/** The ramp's hue. Defaults to the first chart token. */
color?: string;
/**
* Smallest side, in points, a tile needs before `Labels` writes on it.
*
* A name clipped to two letters is not a shorter name, it is a different
* word. Tiles under this are left blank and read through the readout.
*/
minLabelSize?: number;
/** Milliseconds for one tile to grow. */
animationDuration?: number;
/** Milliseconds between one tile starting and the next. `0` for all at once. */
staggerDelay?: number;
/** `loading` draws the box undivided until the data arrives. */
status?: TreemapChartStatus;
/** Selected tile, indexed as laid out. Leave unset to let the chart track it. */
activeIndex?: number;
/** Fires with the selected tile, or `-1` when the selection is cleared. */
onActiveIndexChange?: (index: number) => void;
children?: ReactNode;
}
/** Imperative handle: re-run the entrance, for a "replay" control. */
export interface TreemapChartHandle {
replay: () => void;
}
export interface TreemapChartTilesProps {
/** Opacity of the tiles that are not selected, once one is. */
dimOpacity?: number;
}
/**
* Every tile, drawn in the order they were laid out.
*
* One part rather than one per datum: a tile's box is decided by every tile
* before it in the row, so they cannot be configured apart without the layout
* coming apart with them.
*/
declare function TreemapChartTiles({ dimOpacity }: TreemapChartTilesProps): import("react").JSX.Element | null;
declare namespace TreemapChartTiles {
var displayName: string;
var slot: "svg";
}
export interface TreemapChartSkeletonProps {
/** Milliseconds for one pass of the sweep. */
duration?: number;
color?: string;
}
/**
* The loading state: the box as one plain rectangle, with a highlight
* travelling across it.
*
* Undivided on purpose. Placeholder tiles would be a made-up split, and a
* reader has no way to tell an invented one from a real one until it changes
* under them — which is worse than showing nothing, because it is showing
* something wrong.
*/
declare function TreemapChartSkeleton({ duration, color }: TreemapChartSkeletonProps): import("react").JSX.Element | null;
declare namespace TreemapChartSkeleton {
var displayName: string;
var slot: "svg";
}
export interface TreemapChartLabelsProps {
/** Show each tile's value under its name. */
showValue?: boolean;
/** Show each tile's share of the total under its name. */
showShare?: boolean;
/** Format the value. Defaults to a compact number. */
formatValue?: (value: number, tile: TreemapTile) => string;
className?: string;
}
/**
* The name and reading on each tile that has room for them.
*
* Real text over the SVG rather than SVG text, so the labels follow the theme's
* font and the platform's text scaling — SVG text does neither.
*
* A tile smaller than `minLabelSize` on either side is left blank. The
* alternative is a name clipped to its first two letters, which is not a
* shorter name but a different word, and a chart of those is a chart nobody can
* read. Those tiles are read through `Tooltip` instead.
*
* Each label takes its colour from the tile under it rather than from the
* theme. A tile is the chart's own hue, and a theme is free to set that hue
* anywhere on the scale — a fixed white label vanishes on a pale one, and the
* foreground token would be the wrong colour on half the tiles in either mode.
*/
declare function TreemapChartLabels({ showValue, showShare, formatValue, className, }: TreemapChartLabelsProps): import("react").JSX.Element | null;
declare namespace TreemapChartLabels {
var displayName: string;
var slot: "overlay";
}
export interface TreemapChartTooltipProps {
/** Format the value. Defaults to a compact number. */
formatValue?: (value: number, tile: TreemapTile) => string;
className?: string;
}
/**
* The readout for the selected tile, floating over the box.
*
* This is how the small tiles are read. They are the ones with no room for a
* label, so without it a treemap answers questions about its largest parts only
* — which is the half the reader could already see.
*/
declare function TreemapChartTooltip({ formatValue, className }: TreemapChartTooltipProps): import("react").JSX.Element | null;
declare namespace TreemapChartTooltip {
var displayName: string;
var slot: "overlay";
}
export interface TreemapChartLegendProps extends ViewProps {
className?: string;
/** How many tiles to name before stopping. The rest are left to the chart. */
limit?: number;
/** Show each tile's share beside its name. */
showShare?: boolean;
}
/**
* A swatch and a name per tile, under the box. Pressable in the same way the
* tiles are.
*
* Inline and wrapping, because the tiles are already in size order and the
* legend is a lookup rather than a ranking — it is read by searching for a
* name, not from the top down.
*/
declare function TreemapChartLegend({ className, limit, showShare, ...props }: TreemapChartLegendProps): import("react").JSX.Element | null;
declare namespace TreemapChartLegend {
var displayName: string;
var slot: "footer";
}
export interface TreemapChartHeaderProps extends ViewProps {
className?: string;
/** Small line above the value — what the total is of. */
title?: string;
/** The readout. The largest thing on the card, and the first thing read. */
value?: string;
/** One muted line under the value — a period, a comparison, a caveat. */
caption?: string;
/** Trailing slot — a control, a badge, a range picker. */
children?: ReactNode;
}
/**
* The strip above the box: what the total is of and what it reads.
*
* The value is not derived even though the chart knows the total, because the
* formatting is not the chart's to guess: 48200 is a count, a currency or a
* rate depending on what was counted.
*/
declare function TreemapChartHeader({ className, title, value, caption, children, ...props }: TreemapChartHeaderProps): import("react").JSX.Element;
declare namespace TreemapChartHeader {
var displayName: string;
var slot: "header";
}
export declare const TreemapChart: import("react").ForwardRefExoticComponent> & {
Header: typeof TreemapChartHeader;
Tiles: typeof TreemapChartTiles;
Labels: typeof TreemapChartLabels;
Tooltip: typeof TreemapChartTooltip;
Legend: typeof TreemapChartLegend;
Skeleton: typeof TreemapChartSkeleton;
};
export {};
//# sourceMappingURL=index.d.ts.map