Interaction and states
Tooltips, legend, selection under your control, the context menu and export - and what a chart shows when it cannot draw the data.
@workspace/active-charts 6.0.0Status unknowncontent differs from the recorded release 6.0.0baseline ce081dc3
Selected: nothing
// apps/docs/examples/charts/interaction.tsx'use client';
import {useRef, useState} from 'react';import {MONTHLY_SALES, SALES_SERIES} from '@/lib/examples/chart-data';
import { BarChart, englishChartTranslator, type ChartHandle, type ChartItemRef,} from '@workspace/active-charts';import {Button} from '@workspace/active-ui/components/primitives/button';
/** A readable name for a selected bar: its series and its month. */function describe(ref: ChartItemRef): string { if ('seriesId' in ref) return `${ref.seriesId} @ ${String(ref.key)}`; return JSON.stringify(ref);}
/** * Selection under the host's control, the shared tooltip and legend, and * the export of the imperative handle. Click a bar, or move to it with the * arrow keys and press Space, to select it; Shift+F10 opens the chart's menu * with copy, the data table and export. */export default function ChartInteraction() { const chart = useRef<ChartHandle>(null); const [selected, setSelected] = useState<ChartItemRef[]>([]); const [exported, setExported] = useState<string | null>(null); return ( <div className="flex w-full flex-col gap-4"> <BarChart ref={chart} data={MONTHLY_SALES} xKey="month" xAxis="category" series={SALES_SERIES} legend tooltip={{enabled: true, mode: 'shared'}} selection selectedItems={selected} onSelectionChange={(next) => setSelected(next)} height={300} locale="en-GB" t={englishChartTranslator} /> <div className="flex flex-wrap items-center gap-2"> <Button variant="outline" size="sm" onClick={async () => { const result = await chart.current?.exportAsCsv('sales.csv'); setExported( result ? `${result.filename}: ${result.blob.size} bytes` : null, ); }} > Export CSV </Button> <Button variant="outline" size="sm" onClick={async () => { const result = await chart.current?.exportAsPng('sales.png', 2); setExported( result ? `${result.filename}: ${result.blob.size} bytes` : null, ); }} > Export PNG </Button> <Button variant="ghost" size="sm" disabled={selected.length === 0} onClick={() => setSelected([])} > Clear selection </Button> </div> <p className="text-sm" aria-live="polite" data-chart-selection> Selected:{' '} {selected.length > 0 ? selected.map(describe).join(', ') : 'nothing'} </p> {exported ? ( <p className="text-muted-foreground text-sm">{exported}</p> ) : null} </div> );}Selection#
Turn selection on with selection. Controlled, you own selected and update it from
on; uncontrolled, seed it with default. An item is a logical
identity ({series for an item of a series, a cell, a node or a link), never a position, so
one selection can be given to several charts. on fires on a click or on Enter.
Tooltip, legend and menu#
tooltip={{mode: 'shared'}}shows every series at the hovered x;'single'one item;'split'one box per series.legendtoggles series; a hidden series leaves the scales.The context menu (right click, long press, Shift+F10) carries copy, the data table and export; add your own items with
context.Menu={{items}}
Export#
The imperative Chart (ref) offers export, export, export and
export. Each waits until the chart is still and resolves with the file (blob, filename)
when it was handed to the browser. See Export.
States#
No rows
Empty gauge range
A flow with a loop
// apps/docs/examples/charts/states.tsx'use client';
import { BarChart, ChartDefaults, englishChartTranslator, GaugeChart, SankeyChart,} from '@workspace/active-charts';
/** * What a chart shows when it cannot draw the data truthfully: no rows, a * gauge whose range is empty, a flow that loops. Each is a translated * unavailable state, not an empty frame or a broken drawing. */export default function ChartStates() { return ( <ChartDefaults locale="en-GB" t={englishChartTranslator}> <div className="grid w-full gap-6 sm:grid-cols-3"> <section aria-label="No rows" data-chart-state="empty"> <p className="mb-2 text-sm font-medium">No rows</p> <BarChart data={[]} xKey="month" xAxis="category" yKey="sales" name="Sales" height={180} /> </section> <section aria-label="Empty range" data-chart-state="range"> <p className="mb-2 text-sm font-medium">Empty gauge range</p> <GaugeChart value={5} min={10} max={10} label="Score" height={180} /> </section> <section aria-label="A loop" data-chart-state="cycle"> <p className="mb-2 text-sm font-medium">A flow with a loop</p> <SankeyChart nodes={[ {id: 'a', label: 'A'}, {id: 'b', label: 'B'}, ]} links={[ {source: 'a', target: 'b', value: 3}, {source: 'b', target: 'a', value: 1}, ]} height={180} /> </section> </div> </ChartDefaults> );}Input a chart cannot draw truthfully (no rows, an empty gauge range, a sankey cycle, an inverted
axis domain) shows a translated unavailable state, with a development diagnostic to your sink. For
unexpected errors, wrap charts in your own <Chart.