Zoom & Pan

ApexStock charts are zoomable and pannable out of the box. Zooming the price chart keeps every indicator pane, the volume pane, and any trading overlays aligned to the same visible window, so the whole stack scrolls together.

Zoom controls

A zoom control renders with the chart, letting the viewer zoom in, zoom out, and reset back to the full range. Panning and wheel-scrolling move the visible window along the time axis. Reset returns to the full extent of the data.

When new bars arrive through appendData, the view option decides whether the window follows the right edge or holds still, so streaming and manual zoom cooperate rather than fight.

Reading the current range

getCurrentZoomState() returns the visible x-range as { minX, maxX }, or null if the chart has not rendered yet:

const range = apexStock.getCurrentZoomState()
if (range) {
  console.log(`Visible from ${range.minX} to ${range.maxX}`)
}

This is handy for persisting a user's view, or for loading more history when they pan to the edge.

getVisibleRange() is the same information in the shape the setter takes, returning { min, max } or null.

Setting the range

setVisibleRange(min, max) zooms and pans to a window and fires rangeChange:

apexStock.setVisibleRange(Date.parse('2024-01-01'), Date.parse('2024-06-30'))

This is the primitive behind time-frame controls and cross-chart sync.

Range events

Two events, with deliberately different rhythms:

// Once per settled gesture. The right rhythm for fetching data
// or writing the range into a URL.
apexStock.on('rangeChange', ({ min, max, source }) => {
  // source: 'zoom' | 'pan' | 'reset'
})

// Every animation frame of an in-progress gesture, with the same
// payload and source: 'live'. For overlays that must stay glued
// to the axis while the gesture runs.
apexStock.on('rangeChanging', ({ min, max, source }) => {})

Subscribe to rangeChange for anything with a cost, and to rangeChanging only for per-frame drawing. Doing the reverse is the common mistake: a fetch on every frame of a wheel zoom fires dozens of times for one gesture.

Applying a range across charts

applyZoomToAllCharts() applies a saved zoom state to the main chart and all of its indicator panes at once, keeping them in lockstep:

const range = apexStock.getCurrentZoomState()
// ... later, or on another view ...
apexStock.applyZoomToAllCharts(range)

Combine the two to restore a saved window when a chart is re-created, or to keep a secondary view synchronized with the primary one.

Zoom and updates

  • A full update() preserves the current zoom state across the rebuild.
  • Adding or removing indicators preserves zoom as well, so toggling an oscillator does not reset the viewport.