Skip to content

Value-axis navigation & XY brushing

Standalone Charts and Pivot share these native SVG capabilities. Supported chart types are line, smoothLine, steppedLine, area, steppedArea, stackedArea, normalizedArea, scatter, bubble and quadrant. Other families reject the new M1 policy fields. Existing heatmap navigation, range selectors and histogram navigation retain their own contracts.

await chart.update({
axes: {
...chart.model.axes,
y: { min: 0, max: 100, title: 'Units' },
yAxes: { amount: { scale: 'log', min: 1, max: 10000, title: 'Amount' } },
},
seriesOverrides: {
...chart.model.seriesOverrides,
revenue: { ...chart.model.seriesOverrides?.revenue, yAxis: 'amount' },
},
navigation: {
enabled: true,
axes: 'xy',
xAxis: 'primary',
yAxis: 'amount',
yLimits: { min: 10, max: 10000, minSpan: 0.05, maxSpan: 0.9 },
brush: true,
},
viewport: {
...chart.model.viewport,
yAxes: { ...chart.model.viewport?.yAxes, amount: { scale: 'log', min: 100, max: 1000 } },
},
});

The revenue override must name a real source series. Author named axes before assigning them, or commit definitions and assignments atomically. Primary and secondary aliases continue to work; the primary axis can remain implicit. secondary uses axes.ySecondary or its existing implicit default. Named IDs must resolve in axes.yAxes.

Navigation optionContract and default
axes'x', 'y' or 'xy'. Omission preserves existing behavior: X only for line/area, XY for relationship charts. Controls, wheel, drag, pinch and rectangle zoom change only enabled dimensions. This does not hide axes or discard dormant saved windows.
xAxisExisting selected X identity; default 'primary'. Named-X requirements remain unchanged.
yAxisSelected numeric Y identity; default 'primary'. Accepts 'secondary' or an authored named axis. A nonempty trimmed string up to 128 characters; prototype names are rejected. Selecting an axis does not reassign series.
yLimitsOptional owned ChartValueNavigationLimits object with exactly min, max, minSpan, maxSpan. Omission allows the full Y domain and the existing minimum gesture span. Applies to the selected Y owner.
yLimits.min, yLimits.maxOptional finite bounds in raw public Y units, intersected with the full axis domain. Both authored requires min < max. Logarithmic lower bounds must be positive. Nonintersecting or nonrepresentable limits reject.
yLimits.minSpanSmallest gesture window as a fraction of the full transformed domain; greater than zero and at most one. Default 0.0001. Must fit in the permitted domain intersection.
yLimits.maxSpanLargest gesture window in the same fractions; greater than zero and at most one. Default 1. Must be at least minSpan when both are authored.
brushBoolean, default false. Enables separate XY source selection by Alt-drag or keyboard. Independent of enabled; selection works with navigation gestures disabled.

Limits constrain navigation gestures, not explicit API-authored viewport ranges. Adding limits does not silently change an existing viewport. The next gesture clamps its window. Reset removes the selected enabled dimensions’ windows and returns them to their full domains; it retains limits for subsequent gestures. In Y-only mode, X windows remain untouched; in X-only mode, Y windows remain untouched. Reset and commits preserve all other named axes. Values are absolute public units; span constraints operate after linear/log/sqrt/symlog transformation. Axis reversal changes physical direction while saved min < max remains semantic.

enabled, actions and gestures keep their existing defaults. Hidden/disabled actions cannot activate. gestures.rectangle: false disables rectangle zoom; wheel, pan and pinch can be disabled independently. There are no new rendering backends or dense-data performance claims.

viewport.y remains the primary numeric Y window. viewport.yAxes.secondary addresses the secondary alias; viewport.yAxes[id] addresses a named value axis. Each entry is { scale: 'linear' | 'log' | 'sqrt' | 'symlog', min, max } with finite increasing bounds and a scale matching that axis. Log windows require positive bounds. Up to 32 own entries are accepted; IDs are trimmed nonempty strings of at most 128 characters. Primary and prototype names are reserved in yAxes; use viewport.y for primary. The enclosing viewport/configuration is a replacement, so spread windows you intend to retain.

Older saved models without these fields keep their defaults. Definitions, selected axis policy, limits, brush opt-in, committed windows and semantic selections persist. Runtime callbacks, active pointers and brush/zoom drafts do not. Invalid type/axis/scale updates reject atomically. A removed named axis must have its window and assignments removed or reassigned in the same update. Hidden series can retain dormant assignments and windows.

The same current projections feed paths, marks, axes, clipping, annotations, error bars and inspection. Full scales remain separate from windows. Overflow-safe scales preserve public units and symlog constants. Stacked and normalized area windows use the displayed cumulative/percentage coordinates; selections and data export still identify raw source observations. Preview/overview rendering retains full-domain geometry.

Wheel zooms around the pointer; drag pans and pinch zooms around the touch center. Shift-drag creates a zoom rectangle on supported XY geometry. It is a viewport operation and does not select or activate source points. The existing gestures.rectangle policy also applies to the supported ordered line/area families when Y navigation is enabled.

Focus the plot/navigation controls: arrows pan, +/− zoom and Home resets enabled dimensions. Up/down controls are available when value navigation is active. Shift increases the keyboard pan step. Escape cancels an active zoom gesture and restores the committed viewport. Programmatic windows remain usable when interactive navigation is disabled. An authored X navigator remains visible but read-only in Y-only mode; its handles are disabled. Use the plot/toolbar for Y navigation. This milestone does not add a separate Y slider.

Alt-drag inside the plot selects eligible point centers in a rectangle and replaces the semantic selection. A drag must cover at least six SVG units in both dimensions; a click is not a brush. Only the configured navigation.xAxis and navigation.yAxis participate, even when overlapping layers or other axes occupy the same plot.

Eligibility comes from canonical geometry, not SVG glyphs: sampled/omitted markers remain selectable, duplicate X positions keep distinct category/series identities, and hidden series, null/nonfinite values, clipped points, synthetic categories and derived series are excluded. Selection uses point centers, not bubble radius intersection or line-segment intersection. Closed rectangle edges are inclusive. For stacked/normalized areas the rendered source endpoint determines membership.

Tab to the localized XY selection surface. Arrow keys move its box by 5% of plot size; Shift+arrows resize its right/bottom edge by 5%. The initial box spans the visible plot. Enter commits, Delete/Backspace clears selection, and Escape cancels a draft. Committing or clearing preserves keyboard focus through repaint. Pointer cancellation, lost capture, host updates and destroy cancel transient drafts. Keyboard blur cancels an uncommitted keyboard draft. The next independent pointer action is not consumed by stale click suppression.

Brushing does not fire onNodeClick or drill-through. Native charts commit through their existing setSelection policy. In interaction.mode: 'event', the existing onSelectionRequest callback receives the proposed semantic targets and the host controls the commit. Pivot uses its existing selection transaction/events and filter/highlight policy; it retains query/source-record authority. Selecting an aggregated Pivot point identifies its semantic cell/measure, not a fabricated list of original records. Runtime adapters expose ChartRenderInput.onSelectionChange(selection, origin) with 'pointer' | 'keyboard'; hosts supplying custom render inputs own this callback. Renderers must advertise navigation and semantic selection support.

The existing one-dimensional rangeSelection API remains separate. Its range events and persisted interval are unchanged. Alt-drag uses shared gesture ownership so it cannot simultaneously pan, draw annotations, or modify that range. Clear source selection through the brush keyboard surface or existing selection API.

Windowed sources receive the complete viewport.y/yAxes alongside X windows. Supply full-source numeric bounds in fullDomain.y and fullDomain.yAxes to keep gesture domains independent of the loaded page. Requested named Y windows require matching named full-domain metadata; omitted or mismatched scales reject the response. Pivot viewport providers must echo every named Y window exactly, preserving the existing correlation/revision/cancellation rules. Full-domain metadata is runtime state and must be supplied again after restore.

Current-view CSV keeps canonical rows with visible source points and leaves clipped path cells empty; Y membership uses displayed stack coordinates but emitted numbers remain raw. { dataScope: 'all' } retains the accepted complete local dataset, without fetching missing remote rows. Normal SVG/image exports omit brush surfaces/drafts and retain committed chart content. SSR and hydration retain declarative options/windows; hosts reattach runtime callbacks. No server rows are reconstructed by brushing or export.

The Pivot navigation inspector edits dimensions, selected Y axis, all four limit fields and brush opt-in through the same options. Switching the selected Y axis clears the previous axis’s gesture limits to avoid applying unrelated units. Compatible gallery changes retain Y policy/windows; unsupported families prune them. Public types are ChartNavigation, ChartValueNavigationLimits, ChartViewport and their Pivot aliases, including PivotChartValueNavigationLimits through both root and charts entry points.

New localized captions under localeText.navigation are navigationAxes, navigationDefault, navigationYAxis, xyBrush, navigationYMin, navigationYMax, navigationYMinSpan, navigationYMaxSpan and xyBrushInstructions. These new captions are optional on older manually constructed full locale records and fall back to shared defaults. Existing numeric navigation instructions continue to describe zoom/pan keys. Labels are text; they do not change gesture bindings.

M1 ends here. Polar navigation, cross-chart unit conversion, batched SVG and WebGL remain separate milestones.