Skip to content

Headless API and Persistence

PivotChartsPlugin is the source of truth for chart data and lifecycle. PivotChartsUiPlugin is a client of that API; applications can build their own gallery, settings, containers, or workspace without replacing the data model.

For normal application-owned charts, use mountPivotChart():

import { mountPivotChart } from '@revolist/pivot';
const chart = await mountPivotChart(grid, {
container: document.querySelector<HTMLElement>('#dashboard-chart')!,
});
Interactive example

Application-owned charts

Compare a linked chart with a frozen snapshot as the Pivot changes, then relink it.

The example loads when visible.

The container does not need to be inside the grid. The default controls: 'none' path renders only the chart and requires no UI plugin. Request controls: 'standard' when the same container should include the built-in configuration experience:

const chart = await mountPivotChart(grid, {
container: document.querySelector<HTMLElement>('#chart-workspace')!,
controls: 'standard',
});

controls: 'standard' requires PivotChartsUiPlugin; chart-only mounting does not. Both return the same PivotChartRef. Give the mount container an explicit height. The built-in renderer fills the available size and observes later layout changes, including a mounted container that becomes visible later. Treat the container as an empty chart mount point: mounting replaces its children, and chart.destroy() leaves it empty.

Configuration controls are optional application UI. Each control can call the same chart ref without recreating the renderer:

chartTypeSelect.addEventListener('change', async () => {
await chart.update({
chartType: chartTypeSelect.value as PivotChartType,
});
});
dataLabelsCheckbox.addEventListener('change', async () => {
await chart.update({
presentation: { dataLabels: dataLabelsCheckbox.checked },
});
});

See the Pivot Charts overview for complete minimal markup and setup for chart-only, standard-control, and component-lifecycle integrations.

Use the plugin instance when an advanced workflow needs collection-wide methods such as restore, getChartModels(), or destroyAllCharts():

const charts = (await grid.getPlugins()).find(
(plugin) => plugin instanceof PivotChartsPlugin,
) as PivotChartsPlugin;
MethodPurpose
getChartData(options?)Project and validate a cached immutable dataset for the current Pivot revision and optional semantic scope.
createChart(params)Create a model, resolve data, mount a renderer instance, and return PivotChartRef.
updateChart(chartId, patch)Validate and queue a model/data/presentation update.
setChartSelection(chartId, selection)Commit owned semantic selection and apply Filter-mode predicates.
clearChartSelection(chartId)Clear selection and release only this chart’s filter contribution.
requestChartSelectionClear(chartId, origin?)Handle a custom UI clear action: request an empty selection in Event mode, or commit clearing in other modes.
getChartRendererCapabilities(chartId)Inspect the creation-time backend’s supported types, interaction modes, options, and graphics features.
getChartRenderer(chartId)Obtain the creation-time renderer factory for matching previews or other advanced integrations.
getChartDownloadCapabilities(chartId)Discover CSV and the existing renderer instance’s graphics formats and PDF encoding.
getChartCSV(chartId, options?)Encode committed chart data without downloading or loading a provider.
refreshChart(chartId)Reproject a linked chart from the current committed Pivot.
canDrillDown(chartId, target)Test a semantic row, column, or two-axis drill target.
drillDownChart(chartId, target)Load and commit a child frame.
drillUpChart(chartId)Navigate to the parent frame.
drillToChart(chartId, frameIndex)Jump to a stored breadcrumb frame.
resetChartDrill(chartId)Return to the chart’s root frame.
retryChartDrill(chartId)Retry the last failed drill transition.
getChartModels()Return cloned serializable models for every active chart.
restoreChart(model, options)Validate a saved model and recreate it in a supplied container.
downloadChart(chartId, options?)Download advertised PNG/SVG/PDF graphics or plugin-owned chart-data CSV.
getChartImageDataURL(chartId, options?)Request an image data URL from a capable renderer.
destroyChart(chartId)Destroy one renderer and release its state.
destroyAllCharts()Destroy every chart owned by the plugin.

All updates for a chart are serialized. A later linked refresh cannot partially overwrite an earlier options update.

const chart = await charts.createChart({
container: document.querySelector('#sales-chart')!,
chartType: 'groupedColumn',
linked: true,
totals: 'none',
bindings: {},
initialScope: {
rowPath: ['Europe'],
rowLabels: ['Europe'],
columnPath: [2026],
columnLabels: ['2026'],
},
presentation: {
title: 'European sales',
legendPosition: 'bottom',
},
theme: 'auto',
chartOptions: {
showGridLines: true,
markOpacity: 0.9,
},
drillSyncMode: 'chart',
});
await chart.update({
chartType: 'stackedColumn',
totals: 'grand',
presentation: { subtitle: 'Including grand total' },
});

Data-affecting patches reproject or validate a snapshot. Presentation, theme, and chart-option changes reuse the current dataset. Failed renderer updates roll back to the previous model and rendered input.

Patch values are owned before entering the chart’s queue. Omitted properties preserve their current value. presentation merges its supplied fields; axes, bindings, chart options, query, navigation, viewport, colors, annotations, and series overrides replace their authored objects. Pass {} to reset those objects. selection replaces the selection array, and seriesIds: [] selects all configured series where the chart supports them. Changing chart type clears chart options unless the same patch supplies options for the new type.

Render-only changes, including axes, viewport, presentation, and theme, preserve pending fresh data and drill caches. When that refresh completes, the chart uses the fresh data with its latest render settings. A source-changing query deliberately supersedes earlier source work; if the new operation fails, the previous committed chart remains available.

The ref scopes common operations to one chart:

chart.id;
chart.container;
chart.model;
await chart.update({ linked: false });
chart.canDrillDown({ axis: 'row', category });
await chart.drillDown({ axis: 'row', category });
await chart.drillUp();
await chart.drillTo(0);
await chart.resetDrill();
await chart.retryDrill();
chart.getDrillState();
await chart.setSelection(selection);
await chart.clearSelection();
chart.focus();
chart.destroy();

model and getDrillState() return clones. Mutating them does not update the active chart; call update or a drill method.

PivotChartModel version 2 contains:

  • stable chartId and chartType;
  • link state and an optional unlinked dataset snapshot;
  • totals, series selection, values-on-rows measure, and semantic bindings;
  • presentation, renderer theme, and validated chart options;
  • authored axes, per-series overrides, interaction mode, and semantic selection;
  • navigation controls and the authored category/time viewport;
  • the authored chart-local query, including its slice, filters, sort, and ranking;
  • breadcrumb/drill scope and drill synchronization mode.
const saved = charts.getChartModels();
localStorage.setItem('pivot-charts', JSON.stringify(saved));
const restoredModels = JSON.parse(
localStorage.getItem('pivot-charts') ?? '[]',
);
for (const model of restoredModels) {
await charts.restoreChart(model, {
container: createWorkspacePanel(model.chartId),
});
}

Restore parses the current model version, checks chart identity, renderer support, options, bindings, selected series, hierarchy paths, dataset shape, limits, and linked/unlinked rules. Optional model.limits contains the authored partial budget overrides and survives JSON save/restore. Missing limits in an existing version 2 model inherit plugin configuration. Restoring captured data validates it against the effective budget before renderer creation. Older model versions are rejected rather than implicitly migrated. Supply chartId in PivotChartRestoreOptions only when the application intentionally replaces the persisted identity.

Interactive example

Renderers and lifecycle

Inspect the renderer's declared capabilities and the chart it creates.

The example loads when visible.

const renderer: PivotChartRenderer = {
capabilities: {
supportedTypes: ['groupedColumn', 'line'],
download: true,
downloadFormats: ['png'],
imageDataUrl: true,
},
create(input) {
const instance = mountApplicationChart(input);
return {
update(nextInput) {
instance.update(nextInput);
},
focus() {
instance.focus();
},
async download(options) {
await instance.downloadPng(options);
},
async getImageDataURL(options) {
return instance.getPngDataUrl(options);
},
destroy() {
instance.destroy();
},
};
},
};

PivotChartRenderInput contains the chart ID, container, chart type, validated dataset, bindings, presentation, chart options, axes, series overrides, theme, locale text, and chart/preview render mode. It also supplies interaction mode, persistent selection, derived peer highlightSelections, and activation and clear callbacks. Call onNodeClick for semantic mark activation and onSelectionClear for a user clear action; the plugin dispatches these according to the interaction mode. A custom renderer must not mutate the supplied dataset or model state, or persist peer highlights as local selection.

A renderer can implement optional synchronous validate(input) preflight. Throw when the complete candidate input requests a feature the backend cannot preserve. The plugin runs this hook before renderer creation/update and native selection-filter effects; the hook must be side-effect-free. Existing renderers can omit it. Direct renderer consumers must also receive the same validation from the renderer’s own create and update methods.

Configure the renderer before creating a chart. Renderer injection is a runtime configuration, and is not serialized in the chart model. Replacing that configuration does not migrate an existing chart instance to another backend. Each chart retains its captured factory, validator, and capability contract. Changing pivotCharts.renderer applies to newly created charts. Existing chart controls, previews, updates, and exports continue using their original backend. The optional ECharts Canvas adapter uses this boundary with an explicit supported feature set.

Navigation-capable renderers receive the canonical dataset, authored navigation and viewport, and onViewportChange. Request a semantic window through that callback instead of modifying Pivot filters or the supplied dataset. Window-only updates use the chart’s update queue and do not load another provider dataset. Custom renderers must advertise capabilities.navigation: true to accept authored navigation or viewport settings. Omitting that capability preserves existing renderer integrations and rejects unsupported navigation requests.

The UI intersects the chart catalog with the existing backend’s capabilities. interactionModes and chartOptionKeys can restrict modes and option controls; omitting them preserves legacy catalog behavior. An empty interactionModes list disables authored interaction. A backend’s validate hook remains responsible for additional option combinations and data-specific restrictions. Download and image actions are available only when the renderer advertises and implements them.

PivotChartsUiPlugin.openChart(params) accepts every PivotChartCreateParams field except container; the UI owns its chart container. pivotChartsUi.dialogParent can move the modeless host into an application overlay root. Closing the dialog destroys its chart.

PivotChartsUiPlugin.mountChart(params) is the lower-level equivalent of mountPivotChart(..., { controls: 'standard' }). It embeds the existing gallery, Data, Customize, current-frame table, export, and drill controls in the supplied application container. Prefer mountPivotChart() unless the UI plugin instance is already part of a larger plugin-management workflow.

EventDetail
pivot-chart-createdChart ID and PivotChartRef.
pivot-chart-updatedChart ID, update reason, and cloned model.
pivot-chart-destroyedChart ID.
pivot-chart-node-clickSemantic category/series, paths, measure, and aggregator.
pivot-chart-errorOptional chart ID and normalized Error.
pivot-chart-before-downloadCancelable download proposal with owned model/options, format, and operation ID.
pivot-chart-downloadedThe download action completed; this does not confirm that the browser saved a file.
pivot-chart-download-errorA download failed or was aborted, with its operation ID and error.
pivot-chart-before-selectionCancelable semantic selection proposal.
pivot-chart-selection-changedCommitted selection with origin, operation ID, and revision.
pivot-chart-selection-requestEvent-mode proposal for explicit application acceptance.
pivot-chart-selection-errorFailed selection/filter transition or cleanup.
pivot-chart-before-drillCancelable transition with from/to drill state.
pivot-chart-drill-startPending drill transition.
pivot-chart-drilledSuccessful transition with model and dataset.
pivot-chart-drill-errorFailed transition and error.
pivot-chart-drill-resetSuccessful reset transition.
pivot-chart-drill-syncSynchronization request and selected mode.

Update reasons are data, options, theme, relink, and drill.

Previous: Customization and export · Next: Server data and performance · API reference