
## Usage

Add `<EChartsAreaChart.Brush />` as a child of the chart root. Its presence renders the brush footer — a miniature of the **full** dataset with a draggable selection window over it. Narrowing that window filters the main chart to the selected range; the miniature always keeps showing everything, so you never lose your place.

Set `xDataKey` on the root (or `dataKey` on `<XAxis />`) so the handles can label themselves with the category under each edge.

```svelte
<script lang="ts">
	import { EChartsAreaChart } from '$lib/components/evilcharts/charts/echarts-area-chart/index.js';
</script>

<EChartsAreaChart {data} config={chartConfig} xDataKey="date">
	<EChartsAreaChart.XAxis dataKey="date" />
	<EChartsAreaChart.Brush formatLabel={(value) => String(value)} />
	<EChartsAreaChart.Area dataKey="desktop" variant="gradient" />
</EChartsAreaChart>
```

## Example

### <EChartsAreaChart.Brush />

```svelte
<script lang="ts">
	import { EChartsAreaChart } from '$lib/components/evilcharts/charts/echarts-area-chart/index.js';
	import { type ChartConfig } from '$lib/components/evilcharts/ui/echarts-chart/index.js';

	const data = [
		{ date: 'June 1', desktop: 412, mobile: 268 },
		{ date: 'June 2', desktop: 468, mobile: 301 },
		{ date: 'June 3', desktop: 501, mobile: 334 },
		{ date: 'June 4', desktop: 486, mobile: 312 },
		{ date: 'June 5', desktop: 523, mobile: 349 },
		{ date: 'June 6', desktop: 297, mobile: 198 },
		{ date: 'June 7', desktop: 264, mobile: 173 },
		{ date: 'June 8', desktop: 534, mobile: 356 },
		{ date: 'June 9', desktop: 578, mobile: 384 },
		{ date: 'June 10', desktop: 612, mobile: 402 },
		{ date: 'June 11', desktop: 596, mobile: 391 },
		{ date: 'June 12', desktop: 641, mobile: 428 },
		{ date: 'June 13', desktop: 351, mobile: 236 },
		{ date: 'June 14', desktop: 318, mobile: 211 },
		{ date: 'June 15', desktop: 663, mobile: 441 },
		{ date: 'June 16', desktop: 702, mobile: 467 },
		{ date: 'June 17', desktop: 688, mobile: 452 },
		{ date: 'June 18', desktop: 731, mobile: 489 },
		{ date: 'June 19', desktop: 754, mobile: 503 },
		{ date: 'June 20', desktop: 402, mobile: 271 },
		{ date: 'June 21', desktop: 376, mobile: 249 },
		{ date: 'June 22', desktop: 769, mobile: 512 },
		{ date: 'June 23', desktop: 812, mobile: 538 },
		{ date: 'June 24', desktop: 798, mobile: 524 },
		{ date: 'June 25', desktop: 843, mobile: 561 },
		{ date: 'June 26', desktop: 867, mobile: 579 },
		{ date: 'June 27', desktop: 451, mobile: 302 },
		{ date: 'June 28', desktop: 428, mobile: 287 },
		{ date: 'June 29', desktop: 881, mobile: 594 },
		{ date: 'June 30', desktop: 926, mobile: 618 }
	];

	const chartConfig = {
		desktop: {
			label: 'Desktop',
			colors: {
				light: ['#047857'],
				dark: ['#10b981']
			}
		},
		mobile: {
			label: 'Mobile',
			colors: {
				light: ['#be123c'],
				dark: ['#f43f5e']
			}
		}
	} satisfies ChartConfig;
</script>

<EChartsAreaChart
	{data}
	config={chartConfig}
	class="h-full w-full p-4"
	curveType="monotone"
	xDataKey="date"
>
	<EChartsAreaChart.Grid />
	<EChartsAreaChart.XAxis dataKey="date" tickFormatter={(value) => String(value).split(' ')[1]} />
	<!-- [!code highlight] -->
	<EChartsAreaChart.Brush height={56} formatLabel={(value) => String(value)} />
	<EChartsAreaChart.Legend isClickable />
	<EChartsAreaChart.Tooltip />
	<EChartsAreaChart.Area dataKey="desktop" variant="gradient" isClickable />
	<EChartsAreaChart.Area dataKey="mobile" variant="gradient" isClickable />
</EChartsAreaChart>
```

> 
  

Drag either handle to resize the range, or drag the selected region itself to pan without
changing its width. Handle labels fade in while the pointer is over the brush. Because the
ECharts brush is backed by a native `dataZoom`, the main plot is draggable too — drag the chart
itself to slide the visible window, and the brush follows along.




## Supported Charts

The brush is available on the cartesian charts — `EChartsAreaChart`, `EChartsLineChart`, `EChartsBarChart`, and `EChartsComposedChart`. Attach it exactly the same way on each:

```svelte
<EChartsLineChart.Brush />
<EChartsBarChart.Brush />
<EChartsComposedChart.Brush />
```

The miniature mirrors the chart it belongs to. Area and composed charts draw filled areas, line charts draw strokes only, and bar charts draw rounded bars — and it inherits the parent chart's stacking and series colors, dimming alongside the main plot when a series is selected.

The brush is hidden while the chart is in its loading state, and it never renders for the non-cartesian charts (pie, radar, radial, sankey), which have no continuous axis to zoom.

## Reacting to the Range

Filtering the chart is automatic. Pass `onChange` when something _outside_ the chart needs to follow along, such as a heading that reports the visible window:

```svelte
<script lang="ts">
	let range = $state({ startIndex: 0, endIndex: data.length - 1 });
</script>

<EChartsAreaChart {data} config={chartConfig} xDataKey="date">
	<EChartsAreaChart.Brush onChange={(nextRange) => (range = nextRange)} />
	<EChartsAreaChart.Area dataKey="desktop" variant="gradient" />
</EChartsAreaChart>

<!-- data[range.startIndex].date → data[range.endIndex].date -->
```

`onChange` fires with data **indices**, not values, so look the labels up on your own rows.

## How It Differs from LayerChart

Same Svelte composition, props, and behavior — but the ECharts brush is built differently underneath. The miniature is a real second ECharts grid holding mirrored copies of every series. A fully transparent native `dataZoom` slider sits on top of it and supplies the drag interaction, while the active renderer — Canvas by default or SVG when `renderer="svg"` is set on the chart root — draws the rounded selection frame, dimmed sides, grip-dot handle pills, and range labels that track the selection directly.

The practical differences: the main plot gains drag-to-pan for free, and the footer is a close reconstruction of the LayerChart `EvilBrush` rather than a pixel-identical copy of it.

## API Reference

### Brush

Composed as a child of the chart root. It renders nothing itself — its presence turns the brush footer on, and its props configure it.


  ### `height`

type: `number` · default: `56`

Height of the brush preview strip in pixels.
  ### `formatLabel`

type: `(value: string, index: number) => string`

Formats the range-handle labels from the category under each edge. Defaults to the raw value.
  ### `onChange`



Fires as the selection moves, with the inclusive data indices of the visible range.


### Root


  ### `xDataKey`

type: `string`

The data key the handle labels read from. Falls back to the `<XAxis />` `dataKey`, then to the
first data column no series has claimed.

