# XWUIChart

The base chart engine for the chart tier: a single component whose `type` config
selects the shape - line, bar, area, pie, donut, scatter, radar, heatmap, sankey,
treemap, and dozens more (with aliases). Pass one or more named `series` of
`{ x, y }` points; it renders to SVG and draws the grid, axes, and legend for you.
Use it directly when you want to pick the chart type at runtime; reach for a
dedicated `XWUIChart*` variant when you want a fixed shape with preset blocks.

## Basic Usage

Two named series of monthly values rendered with the default line type, automatic
axes, grid, and legend.

```example
file: examples/BasicUsage.ts
html: examples/BasicUsage.html
title: Basic Usage
description: Two-series line chart from {x, y} data with auto axes, grid, and legend.
```

## Multi-Series Line Chart

Three named revenue series on one cartesian plot - shared grid and axes, palette
colours, an X-axis of month labels, and an interactive legend.

```example
file: examples/MultiSeries.ts
html: examples/MultiSeries.html
title: Multi-Series Line Chart
description: Three named series share one line chart with grid, X-axis labels, and a colour-coded legend.
```

## Stacked Bar Chart

Four traffic-source series stacked into one bar per month via `type: "stackedBar"`,
so each column's height is the monthly total and every segment its share.

```example
file: examples/Stacked.ts
html: examples/Stacked.html
title: Stacked Bar Chart
description: Four series stacked per month with type "stackedBar"; bar height is the total, segments the shares.
```

## Live Streaming Update

An area chart seeded with a 30-point sliding window that pushes a new sample every
second through the real `setData()` API, scrolling like a live metrics feed.

```example
file: examples/LiveUpdate.ts
html: examples/LiveUpdate.html
title: Live Streaming Update
description: Seed an area chart, then stream a new point per second via setData() for a live, scrolling series.
```

## Categorical Bar Chart with Custom Colours

A categorical bar series with an explicit brand colour, on-bar value labels, grid
values, and a declarative `lineY` goal annotation across the plot.

```example
file: examples/Categorical.ts
html: examples/Categorical.html
title: Categorical Bar Chart with Custom Colours
description: A categorical bar chart with a custom series colour, on-bar value labels, grid, and a goal reference line.
```

## Behaviour Notes

### RTL charts are mirrored by default

A chart that resolves to `direction: "rtl"` - pinned on the config, set as
`<xwui-chart direction="rtl">` / `dir="rtl"`, inherited from the DOM cascade, or
from `configureXWUI({ system: { direction: 'rtl' } })` - **mirrors its cartesian
plot**: X grows right-to-left, and every `<text>` is counter-flipped so labels
still read normally. This is the default because a right-to-left reader scans
the plot the same way they scan the page.

Two escape hatches:

- `mirror: false` - never mirror, even in RTL. Use it for a time series whose
  "later is further right" convention must survive translation.
- `mirror: true` - force the mirror on an LTR page.

Non-cartesian shapes (pie, donut, treemap, radial, sankey, map, …) are never
mirrored: they encode no reading order along X, so flipping them would only
reverse the slice order.

### Y-axis ticks are derived as one scale

The Y domain and the number of grid bands come from a single "nice" step, so
every printed tick is exactly `min + i × step` and always a round number. This
means the drawn band count follows from the data - `yTickCount` is a **target**,
not a mandate (a 0…80 axis draws 8 bands of 10, not 10 bands of 8).

`yDomain`, `yDomainMode: "none"` and `yDomainMode: "zero"` opt out entirely:
they are explicit statements about where the axis starts and ends, so neither
the bounds nor the band count are re-derived and `yTickCount` is honoured
literally.

### Tooltips follow the X axis

With `interactive: true`, sweeping the cursor **anywhere** across a cartesian
chart shows the values for the nearest point along X. You do not have to land on
a marker: the crosshair and the bubble snap to the nearest column, the bubble
lists every series at that X, and the row for the series nearest the cursor's Y
is highlighted. Set `trackAxis: false` to go back to requiring a hit on the shape
itself, or `tooltip: false` / `showCrosshair: false` to drop the bubble or the
line.

Non-cartesian shapes (pie, donut, treemap, sankey, radial, map, …) keep
per-shape hover, because "nearest along X" means nothing on them.

`pointClick` still fires from the shape you actually click, so click targeting is
unchanged by axis tracking.

### Sizing: filling a container

Sizing is **per axis**, and every wrapper (`XWUIChartBar`, `XWUIChartPie`, …)
forwards these through to the chart it delegates to:

- `fillContainer: true` - track the host on both axes.
- `width: '100%'` / `height: '100%'` - track the host on that axis only.
- a number - that many CSS pixels.

Filling an axis means filling **the box the container already has**, so the
container needs a resolved size on that axis. `height: '100%'` inside a parent
with no height of its own computes to `auto` in CSS, and the chart falls back to
its pixel height rather than collapsing. Give the parent a height (fixed, a grid
track, `flex: 1` in a column, or a percentage chain that resolves) and the plot
follows it - including through `%` and `vh` hosts, flex and grid items, and live
drag-resizes.

Two invariants hold at every size:

- **Geometry equals pixels.** The `viewBox` always matches the rendered SVG box,
  so the plot is never scaled non-uniformly. On an axis that is *not* filling,
  the pixel size is a preferred size: if CSS gives the SVG less room, the
  geometry follows it down rather than squashing.
- **Small hosts degrade instead of breaking.** Under roughly 150px tall or 220px
  wide, the title row, the legend row and the card padding are dropped. Under
  roughly 90x150 of actual plot surface, the grid, axis spines, tick labels and
  insets go too, leaving just the shape - which is what a chart that small can
  actually communicate. Set `compact: true` to force that mode at any size, or
  `compact: false` to keep full chrome and let the chart overflow.

`minWidth` / `minHeight` set a floor on the **rendered** plot, so a host smaller
than the floor overflows visibly rather than receiving a compressed plot. There
is no default floor.

Charts re-fit themselves on container resize via `ResizeObserver`. Call
`chart.resize()` when you change the layout in a way the observer cannot see -
a document that is not being rendered (hidden tab, `display: none` ancestor,
print) delivers no observations at all.

### `pointClick` on node-shaped charts

Treemap cells carry `data-point-index` equal to their index in `data.nodes`, so
`pointClick` reports `pointIndex` = the node's position in the array (and
`point: null`, since node-shaped charts have no `series[].data` to resolve
against). Read the node off `data.nodes[pointIndex]`. The hover tooltip on these
charts reads the shape's `data-label` / `data-value` instead, and calls
`valueFormatter` as `(value, null)` - see the `valueFormatter` contract in the
API table below.

```api
```
