State Persistence

getState() returns a versioned, plain-JSON snapshot of everything the user has set up. setState() puts it back.

localStorage.setItem('chart', JSON.stringify(chart.getState()))

// later, on a fresh chart
chart.setState(JSON.parse(localStorage.getItem('chart')))

The result is JSON-serializable with no functions in it, so it goes into localStorage, a URL, or a database row without special handling.

What is captured

ThemeThe mode, and the preset name
Chart typeCandlestick, line, renko, and the rest
IndicatorsEvery active one with its params
ZoomThe visible range
DrawingsEvery anchored shape, mouse-drawn ones included
MeasurementsInside drawings, because a measurement is a measure drawing
Event markersmeta included
AnnotationsLines, bands, points, text
Trading price linesThe declarative config
Price scaleThe mode and its baseline
Pane heightsOnly the ratios you set
ComparisonMode, benchmark, alignment policy, and each instrument's name and color

Two things are deliberately not captured

Both are owned by the consumer, so serializing them would either fail or go stale.

Price-line callbacks. onCross, onMove and onRemove are functions and are not serializable. The lines come back; re-bind their callbacks after setState:

chart.setState(saved)
for (const line of chart.getPriceLines()) {
  chart.updatePriceLine(line.id, { onCross: handleCross })
}

Comparison instrument data. Your app fetches it, it runs to thousands of bars per instrument, and it would be stale the moment it was written to storage. State carries each instrument's name and color only. setState keeps any instrument still loaded, and emits comparisonRestoreNeeded for the rest:

chart.on('comparisonRestoreNeeded', async ({ names }) => {
  for (const name of names) {
    chart.addComparison({ name, data: await fetchCloses(name) })  // remembered color is reapplied
  }
})

The event does not fire for an instrument whose data is still in memory. Mode, benchmark and alignment policy restore on their own, and a benchmark whose instrument has not come back yet is remembered by name with the primary filling the role until it does.

Versioning and migration

ApexStock.STATE_VERSION                 // the current schema version
ApexStock.migrateState(oldState)        // bring an older snapshot forward

setState() migrates automatically, so an older saved state loads without special handling. Keys are additive and back-filled by migrateState, which means adding a new captured key does not bump the version: a state written before that key existed restores with the default for it.

Custom drawings and unknown presets

Two things depend on what the restoring app has registered:

  • A custom drawing type must be registered again with ApexStock.registerDrawingTool() before setState can re-render drawings of that type. The registry is global and does not survive a reload on its own.
  • A theme preset the restoring app does not know falls back to its base mode rather than failing.

See also