Skip to content

Axis range selection

Enable rangeSelection to select an interval directly on a chart. Drag the plot to create a range, drag its body to move it, and drag either handle to resize it. The chart dims the area outside the selection. Mouse, pen, touch and keyboard use the same control.

Range selection belongs to shared Charts and works in standalone charts and Pivot. It keeps the source data and viewport unchanged. Use Data selection for individual observations, or a Navigator to change the visible window.

This example starts with April–September selected. Move or resize the range, then inspect rangeSelection in the model below. Choose Clear range and drag anywhere on the plot to create another range. Select Apr–Sep sets a range through the public API. Both series remain visible; range selection does not choose which series to show.

Loading chart…

Inspect live chart state

The chart uses the native Charts renderer. Buttons outside the plot are example application controls calling the public API.

Complete chart setup with sample data

Install Charts using the installation guide, then run this setup after the host mounts. The data is illustrative. Additional actions for this tool are explained below.

<div id="chart" style="width:100%;height:500px"></div>
import { createChartFactory } from '@revolist/charts/core';
import { lineChart } from '@revolist/charts/line';
import { groupedColumnChart } from '@revolist/charts/grouped-column';
import { columnLineChart } from '@revolist/charts/column-line';
const rows = [
{
"date": 1767225600000,
"month": "Jan",
"revenue": 65,
"costs": 45
},
{
"date": 1769904000000,
"month": "Feb",
"revenue": 82,
"costs": 50
},
{
"date": 1772323200000,
"month": "Mar",
"revenue": 76,
"costs": 48
},
{
"date": 1775001600000,
"month": "Apr",
"revenue": 95,
"costs": 65
},
{
"date": 1777593600000,
"month": "May",
"revenue": 110,
"costs": 72
},
{
"date": 1780272000000,
"month": "Jun",
"revenue": 102,
"costs": 68
},
{
"date": 1782864000000,
"month": "Jul",
"revenue": 121,
"costs": 80
},
{
"date": 1785542400000,
"month": "Aug",
"revenue": 115,
"costs": 76
},
{
"date": 1788220800000,
"month": "Sep",
"revenue": 135,
"costs": 89
},
{
"date": 1790812800000,
"month": "Oct",
"revenue": 128,
"costs": 85
},
{
"date": 1793491200000,
"month": "Nov",
"revenue": 145,
"costs": 92
},
{
"date": 1796083200000,
"month": "Dec",
"revenue": 155,
"costs": 100
}
];
const mapping = {
"category": {
"field": "date",
"label": "month"
},
"series": [
{
"field": "revenue",
"label": "Revenue"
},
{
"field": "costs",
"label": "Costs"
}
]
};
const createChart = createChartFactory([lineChart, groupedColumnChart, columnLineChart]);
const container = document.getElementById('chart')!;
const chart = await createChart({
container,
data: rows,
mapping,
"chartType": "line",
"axes": {
"x": {
"scale": "time"
}
},
"presentation": {
"title": "Monthly performance",
"subtitle": "Illustrative data · 2026",
"legendPosition": "bottom"
},
"interaction": {
"mode": "event"
},
"rangeSelection": {
"enabled": true,
"range": {
"scale": "time",
"min": 1775001600000,
"max": 1788220800000
}
}
});
// When the host unmounts:
// chart.destroy();

Create an ordinary chart and enable range selection:

import { createChart } from '@revolist/charts';
const chart = await createChart({
container: document.getElementById('chart')!,
chartType: 'line',
data: [
{ date: Date.UTC(2026, 0, 1), revenue: 65 },
{ date: Date.UTC(2026, 1, 1), revenue: 82 },
{ date: Date.UTC(2026, 2, 1), revenue: 76 },
{ date: Date.UTC(2026, 3, 1), revenue: 95 },
],
mapping: {
category: { field: 'date' },
series: [{ field: 'revenue' }],
},
axes: { x: { scale: 'time' } },
rangeSelection: { enabled: true },
onRangeSelectionEnd({ range, origin }) {
// The committed range is already available in chart.model.
console.log('Selected range', range, origin);
},
});

Give the chart host a height, for example <div id="chart" style="height:400px"></div>. Framework component options accept the same settings and callbacks.

APIPurpose
rangeSelection: { enabled: true, range?, style? }Configure the control at creation or through update().
chart.setRangeSelection(range)Enable the control and set an owned category/time/numeric interval. Retains styling.
chart.setRangeSelection(null)Enable the control with no selected interval.
chart.clearRangeSelection()Clear the interval while retaining the enabled state and styling.
chart.model.rangeSelectionRead a snapshot of the committed range and authored settings.
chart.subscribe(listener)Observe committed standalone chart changes; returns an unsubscribe function.
onRangeSelectionStart/Change/EndObserve pointer and keyboard gestures.
chart.update({ rangeSelection: {} })Disable the control.
await chart.setRangeSelection({
scale: 'time',
min: Date.UTC(2026, 0, 1),
max: Date.UTC(2026, 2, 1),
});
const selected = chart.model.rangeSelection?.range;
await chart.clearRangeSelection();

Both methods return promises. They validate against the chart’s configured axis, own the supplied bounds before queuing, and preserve current styling. Await them before reading the result. Invalid input rejects without changing the committed model, and calls after destruction reject. The methods leave the viewport, source data and semantic point selection unchanged.

Programmatic changes notify standalone model subscribers; they do not synthesize pointer/keyboard gesture callbacks. In Pivot, use the existing pivot-chart-updated event to observe API updates.

Time ranges use UTC epoch milliseconds, with min < max:

await chart.update({
rangeSelection: {
enabled: true,
range: {
scale: 'time',
min: Date.UTC(2026, 0, 1),
max: Date.UTC(2026, 2, 1),
},
},
});

Category ranges use stable category IDs, with both endpoints included. Use IDs from the dataset rather than display labels. For a category-axis chart:

const categories = chart.getDataset().categories;
await chart.update({
axes: { x: { scale: 'category' } },
rangeSelection: {
enabled: true,
range: {
scale: 'category',
startId: categories[0].id,
endId: categories[2].id,
},
},
});

Numeric X ranges use { scale: 'linear', min, max } or { scale: 'log', min, max } to match the chart’s configured axis. Logarithmic bounds must be positive.

CallbackWhen it runs
onRangeSelectionStartA pointer or keyboard interaction starts.
onRangeSelectionChangeThe transient range changes during the interaction.
onRangeSelectionEndThe range commits successfully, after the model updates.

Each receives { range, origin }, where origin is 'pointer' or 'keyboard'. Clearing supplies range: null. Cancelling a drag restores the previous range without committing it. Use the change callback for temporary previews and the end callback for committed application work.

You can also observe the committed range through chart.subscribe(model => console.log(model.rangeSelection?.range)).

// Clear the range while retaining styling and interaction.
await chart.clearRangeSelection();
// Disable the control and remove its overlay.
await chart.update({ rangeSelection: {} });

Updates replace the whole rangeSelection record. Spread the previous record when retaining its other fields.

await chart.update({ rangeSelection: {
...chart.model.rangeSelection,
enabled: true,
style: {
selectedOpacity: 1,
unselectedOpacity: 0.25,
borderColor: '#64748b',
borderWidth: 1,
handleBorderColor: '#cbd5e1',
handleBorderWidth: 1,
activeColor: '#2563eb',
},
} });

selectedOpacity and unselectedOpacity independently control the plot opacity inside and outside the range, from 0 to 1. They multiply any per-series area fillOpacity. Main charts default to full selected opacity and 25% outside opacity. Navigator areas default to 35% selected and 10% outside opacity.

The shared style also accepts fillColor, fillOpacity, outsideColor, outsideOpacity, handleColor, handleGripColor, handleGripWidth, handleWidth, handleHeight, and handleRadius. outsideOpacity controls the outside veil; an explicit unselectedOpacity takes precedence. A zero borderWidth hides the selection boundary. Use navigator.selectionStyle for the same styling in a built-in navigator.

Use a native axis-navigation-capable chart with a supported category, time, linear, logarithmic, symlog or signed square-root axis. A range control does not apply to axis-free charts such as pies. Check chart.capabilities.rangeSelection for backend support and getChartDefinition(type) from @revolist/charts/catalog for type/axis support.

Enabling range selection reserves the plot’s drag gesture for creating and editing a range. It does not filter rows, change a Pivot query, populate semantic model.selection, or move the viewport automatically. Navigator controls remain separate and available when configured.

ControlAction
Tab, then Enter or Space on the plot selection controlCreate a range without a pointer.
Arrow keys on the range bodyMove the range.
Arrow keys on a handleResize that endpoint.
Shift + ArrowUse a larger step; on the range body, resize the end.
Home / EndMove the range or focused endpoint to a domain boundary.
Escape during a dragCancel and restore the previous range.
Escape on a committed plot rangeClear the range.

Touch supports creating, moving and resizing with the same gestures as a mouse. Touch input inside an enabled main-plot selection is reserved for chart interaction. The built-in navigator reserves horizontal range gestures; the surrounding page remains scrollable.

Pass rangeSelection: { enabled: true } when creating or updating a chart through PivotChartsPlugin. The grid emits pivot-chart-range-selection-start, pivot-chart-range-selection-change and pivot-chart-range-selection-end. Their details include chartId, range and origin.

Pivot chart references expose the same setRangeSelection() and clearRangeSelection() methods. The plugin also exposes setChartRangeSelection(chartId, range) and clearChartRangeSelection(chartId) for applications working by chart ID. ChartAxisRange, ChartRangeSelection, ChartRangeSelectionStyle, and ChartRangeSelectionEvent are exported public types.

Pivot persists the same range with the chart model. Range events alone do not apply a grid filter; the application decides how to use them.

Committed ranges and authored styles are saved in chart.model. Transient drags are not saved. Normal chart creation validates restored models, including range scale and bounds. Interactive main-plot selection overlays are omitted from chart image exports.

Destroy the chart when its host unmounts, and unsubscribe any application listeners:

const stop = chart.subscribe(model => {
console.log(model.rangeSelection?.range);
});
// On unmount:
stop();
chart.destroy();

Navigator · Data selection · All chart tools

rangeSelection.xAxis chooses a declared X identity independently of navigation.xAxis. It defaults to primary. Ranges use that axis’s category IDs, UTC instants or raw numeric values; numeric scale accepts linear, log, symlog and sqrt and must match the selected axis. The symlog constant is inherited from the axis. Unsupported types, including heatmaps, reject this independent brush. See axis configuration.

XY source-point selection is a separate opt-in from this one-dimensional range API. See value-axis navigation and XY brushing.