Drilldown
Click a bar to drill into the next level. The chart updates in place — the WebGL context, scales, and axis chrome are reused, so the drill feels instant.
Use the breadcrumb above the chart to drill back out.
The pattern
Section titled “The pattern”The library exposes a single primitive: chart.on('click', handler) fires a ChartClickEvent with the clicked datum, its index in the data array, the click position, and (for multi-series charts) the series name.
What that click means is your application’s call. Drilldown is just one possibility — the same primitive supports detail panels, context menus, navigation, or anything else you want to wire up.
import { render, type ChartClickEvent } from 'pixi-charts';
const chart = await render(spec, container);
chart.on('click', (event: ChartClickEvent) => { const next = childrenOf(event.datum); if (next !== null) { chart.update(next); // drill in — instant, reuses the WebGL context }});chart.update(newData) is the other half of the pattern. It swaps the rows on the existing chart without recreating the PixiJS Application: scales recompute, axes re-tween, the hit-tester is rebuilt, but the GPU resources stay live. Drilling in and out of multiple levels happens in a single frame.
What the library doesn’t do
Section titled “What the library doesn’t do”The library has no concept of a navigation stack, no “drill into children” helper, no parent-pointer model. That’s deliberate — every consumer wants something slightly different from drilldown:
- An AI Explorer might “drill” by filtering the dataset by the clicked row.
- A product catalog might navigate a hierarchical tree.
- A dashboard might open a side panel with deeper metrics.
If we baked one navigation model into the library, every consumer who wanted a different one would fight it. Instead, the click event is the primitive and the navigation lives in your code.
In the demo above, the React component owns:
- The data hierarchy — regions → countries → cities, hard-coded for the demo but easily fetched on demand in a real app.
- The navigation stack — a
useStatearray of{ label, data }levels. - The breadcrumb UI — rendered above the chart, pops levels off the stack and calls
chart.update(parentData)to navigate back.
The chart knows nothing about any of this. It renders whatever rows it’s given and reports clicks.
Click semantics
Section titled “Click semantics”A click only fires when pointer-down and pointer-up land within ~5 px of each other and within 500 ms. Faster motion or a longer hold reads as a drag or long-press and the click is suppressed. This matches conventional UI expectations and future-proofs against drag interactions on the chart surface.
The event payload reports the down position (where the user pressed), not the up position. That’s what users intend when they click slightly off-target.
Wiring it to your encoding
Section titled “Wiring it to your encoding”The drilldown demo above uses a single common row shape — { label, value, kind } — at every level. That’s the easiest way to keep the chart’s encoding stable while the data changes: same field names, same data types, just different rows.
If your levels need different shapes, you can change the spec entirely between levels by destroying the chart and re-rendering — but you’ll pay a cold-start cost each transition. The fast path is to normalize your data into a single shape, then use update().
What works on every chart
Section titled “What works on every chart”The click API is available on all six chart types: Line, Area, Bar, Scatter, Heatmap, and Pie. Drilldown is most natural on Bar and Pie, but the same primitive enables detail-panel and inspection patterns on the others — clicking a heatmap cell to see its raw row, clicking a scatter point to open a popover, and so on.
See Chart.on for the full method signature and ChartClickEvent for the payload shape.