Exporting Charts
export() is one entry point over five formats, returning a consistent result:
const { format, blob, url, text } = await chart.export({ format: 'png' })
| Format | Returns | Honors |
|---|---|---|
png | blob, url | scale. Falls back to svg where raster capture is blocked |
svg | blob, url | scale |
pdf | blob, url | scale, range, include, summary |
csv | blob, url, text | range, include, includeVolume, raw |
json | blob, url, text | range, include, includeVolume, raw, pretty |
download: true and filename save the result instead of only handing it back.
The export button in the toolbar is the same path with no configuration, and it can be hidden with toolbar: { items: { download: false } }.
The PNG fallback
Some browsers block reading pixels back out of a canvas. Rather than fail, png returns an SVG and says so:
const res = await chart.export({ format: 'png' })
if (res.fallback) {
// res.format === 'svg'
}
PNG composites the price chart and the oscillator panes into one real raster, so a chart with RSI and MACD exports as the whole stack rather than just the top pane.
A single-page document with the chart embedded as a raster, built with no external PDF library:
await chart.export({ format: 'pdf', download: true, filename: 'aapl.pdf' })
Carrying the analysis into the export
include means something appropriate to each medium.
For csv and json it adds per-bar columns:
await chart.export({ format: 'csv', include: ['indicators', 'analysis'] })
| Value | Adds |
|---|---|
'indicators' | One column per active indicator series, main-chart overlays and oscillator panes alike, null through each warm-up |
'analysis' | return (percent change from the previous bar) and drawdown (percent below the running peak, per analysis.drawdownBasis) |
For pdf it sets a text summary below the chart image:
await chart.export({ format: 'pdf', include: ['analysis'] })
await chart.export({ format: 'pdf', summary: ['Q1 review', 'Prepared for the desk'] })
The generated summary carries the window's dates and bar count, the change, high, low, average, volume, annualized return, volatility and maximum drawdown, plus the comparison leaderboard when one is active. summary overrides it with your own lines. It follows range, defaulting to the visible window there, so the exported numbers describe what you were looking at.
The PDF summary needs no font embedding: it is set in Helvetica, one of the PDF base-14 fonts.
The data spine always survives
The OHLC columns are always present whatever include adds, so a CSV keeps round-tripping:
const { text } = await chart.export({ format: 'csv' })
const series = ApexStock.fromCSV(text)
An added column whose name collides with a spine column is suffixed rather than overwriting it.
Range statistics are a summary, not a per-bar value, so they are not columns. Read them from getRangeStats().
The lower-level paths
Both still exist, and export() folds them together:
// Images only, async
await chart.exportImage({ format: 'png', scale: 2, download: true })
// Data only, synchronous, returns a string
const csv = chart.exportData({ format: 'csv', range: 'visible', includeVolume: true })
exportData is synchronous and returns the serialized text directly. Columns are time,open,high,low,close[,volume] plus whatever include adds, with ISO-8601 time by default; raw: true keeps the original x values instead.
What is captured
An image or PDF export reflects the chart's current state: the active chart type, the visible zoom window, the active indicators, the drawings and overlays, and the current theme. Set the view up before exporting.
Data exports take range: 'all' or range: 'visible', so a data export does not have to follow the zoom unless you ask it to.
See also
- Range Statistics and Drawdown for the numbers the PDF summary reports
- Data Format for the adapters a CSV round-trips through
- Toolbar Customization for hiding or replacing the download button