Data Legend and Readout

Two ways to answer "what are the numbers at the bar under my cursor": the built-in corner panel, or getDataAt() for building your own.

The built-in legend

const chart = new ApexStock(el, {
  legend: { show: true, position: 'top-left' },
  // ...
})

Or imperatively:

chart.showLegend({ position: 'top-right' })
chart.hideLegend()
chart.toggleLegend()
chart.isLegendVisible()
OptionDefaultWhat it controls
showfalseWhether the panel is drawn
position'top-left''top-left', 'top-right', 'bottom-left', 'bottom-right'
showChangetrueThe change against the previous close
showVolumetrueThe bar's volume
showIndicatorstrueEach main-chart overlay indicator's value

The panel reads out the instrument's OHLC, the change against the previous close, and the volume at the crosshair, falling back to the latest bar when the pointer is off the chart. It tracks the pointer through the crosshairMove event and stays in sync as indicators are toggled. It is pointer-events: none, so it never intercepts a click or a drag meant for the chart.

Reading the same values in code

getDataAt(index?) is a read-only, structured snapshot at a bar index:

const at = chart.getDataAt(120)

at.index
at.x
at.ohlc              // { open, high, low, close }
at.volume            // null when the bar carries none
at.change            // { absolute, percent }, null on the first bar
at.indicators        // [{ name, value, color, pane, key? }]

indicators covers both main-chart overlays, where pane is 'main', and oscillator panes, where pane is the indicator's key. That includes the drawdown pane.

Values are plain unformatted numbers. Anything unavailable is null (volume, change) or omitted (an indicator still inside its warm-up period). With the index omitted or out of range, it returns the latest bar.

Building a custom legend

Pair it with the crosshairMove event's dataPointIndex:

chart.on('crosshairMove', ({ dataPointIndex }) => {
  const at = chart.getDataAt(dataPointIndex)
  if (!at) return

  panel.textContent = [
    `O ${at.ohlc.open.toFixed(2)}`,
    `H ${at.ohlc.high.toFixed(2)}`,
    `L ${at.ohlc.low.toFixed(2)}`,
    `C ${at.ohlc.close.toFixed(2)}`,
    at.change ? `${at.change.percent.toFixed(2)}%` : '',
    ...at.indicators.map((i) => `${i.name} ${i.value.toFixed(2)}`),
  ].join('  ')
})

This is the route to a side panel, a header strip, or a readout rendered by your own framework instead of by the chart.

See also