Skip to content

Server Data and Performance

A remote Pivot viewport is only a window into the analytical result. Pivot Charts never treat the visible rows or columns as the complete dataset. Configure PivotChartDataProvider to return the complete immediate-child frame for every requested semantic scope.

grid.pivotCharts = {
renderer: createPivotChartsRenderer(),
dataProvider: {
async load(request, { signal }) {
const response = await fetch('/api/pivot/chart-data', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(request),
signal,
});
if (!response.ok) {
throw new Error(`Chart data failed: ${response.status}`);
}
return response.json();
},
},
};

The provider is used for root projection, explicit scoped data, linked refreshes, and drill frames. Local and server Pivots produce the same PivotChartDataset contract after projection and validation.

PivotChartDataRequest includes:

FieldPurpose
requestIdUnique request identity that the response must echo.
viewId and fieldsVersionIdentify the remote analytical view and field registry.
loadOptionsCommitted Pivot filters, sorting, grouping, and engine options.
uiStateOptional Pivot UI hints.
axisStateExpanded row and column paths.
chart.seriesIdsRequested series selection.
chart.categoryMeasureValues-on-rows measure selection.
chart.totalsRequested totals mode.
chart.limitsEffective category, series, and point limits.
chart.bindingsStable semantic field-to-channel bindings.
chart.scopeExact committed revision, row/column paths, and immediate-child depths.

The semantic scope is absolute:

interface PivotChartSemanticScope {
revision: number;
rowPath: PivotPath;
columnPath: PivotPath;
rowDepth: number;
columnDepth: number;
}

The response must contain every immediate child for that scope, not a viewport-sized subset.

interface PivotChartDataResponse {
requestId: string;
scope: PivotChartSemanticScope;
categories: PivotChartCategory[];
series: PivotChartSeries[];
values: Array<Array<number | null>>;
displayValues?: Array<Array<string | null>>;
hierarchies: {
row?: PivotChartHierarchyDefinition;
column?: PivotChartHierarchyDefinition;
};
totalCategoryCount: number;
totalSeriesCount: number;
}

categories.length and series.length describe the returned complete frame. The total counts let the client prove that the response is complete and within limits. Hierarchy definitions and member hierarchy metadata are required when the response contains drillable members.

The client rejects:

  • a response whose requestId differs from the request;
  • any change to revision, row/column paths, or requested depths;
  • partial frames whose returned and total counts disagree;
  • value/display matrices with wrong dimensions;
  • duplicate or unstable category/series IDs;
  • malformed hierarchy levels or member paths;
  • incompatible bindings, selected series, or values-on-rows measures;
  • categories, series, or point counts above the effective limits;
  • data that violates the selected chart’s semantic constraints.

There is no visible-window fallback. A partial response would create a misleading chart and is treated as an error.

Every provider call receives an AbortSignal. Abort underlying HTTP, query, and decoding work when possible. Root loads, linked refreshes, and drill transitions carry monotonically increasing revisions. The plugin ignores a completion that is no longer current even if the provider did not stop after abort.

During drill, the last successful frame remains rendered. During a linked refresh, the UI exposes a loading state and commits the replacement only after data validation and renderer update succeed.

The plugin caches immutable datasets by committed Pivot revision, effective data options, bindings, and semantic scope. Concurrent equivalent requests share the same promise. Successful drill scopes are cached per chart so breadcrumb navigation does not repeatedly load unchanged data.

Replacing grid.pivotCharts, changing the Pivot model/source/filter/sort/group state, or advancing the committed revision invalidates the relevant cache. Application/server caches should use the same request identity inputs and must still return the exact requested scope.

Defaults are:

const DEFAULT_PIVOT_CHART_LIMITS = {
maxCategories: 1_000,
maxSeries: 250,
maxDataPoints: 50_000,
};

Within those limits, the renderer degrades deliberately:

  • every legend position reserves a valid plot rectangle;
  • long legends show a deterministic subset and localized hidden count;
  • category ticks and data labels are thinned without removing data;
  • Cartesian marks retain exact values;
  • density scatter, connected trends, small multiples, and timeline geometry aggregate or sample above their accessibility thresholds;
  • the renderer avoids creating one focus target for every dense source point when that would make keyboard navigation unusable.

Sampling affects rendered geometry, not the persisted normalized dataset. Exceeding configured projection limits fails rather than silently truncating the model.

The gallery uses the same chart definitions and renderer functions as full charts, but with renderMode: 'preview'. Preview mode is decorative and omits tooltips and interactive focus targets. Intersection-based mounting and cache keys for type, renderer, theme, and locale prevent a 63-card gallery from creating 63 active charts at once.

Geographic views are opt-in because map geometry, projections, tiles, and licenses belong to the provider:

const pack = createPivotChartGeographicCapabilityPack(provider);
const host = await pack.render({
container,
chartType: 'choropleth',
dataset,
bindings: { geographic: ['dimension:country'], value: ['measure:sales'] },
});

The pack exposes choropleth, proportionalSymbolMap, and geographicHeatmap. These views are not built-in gallery types and do not change PivotChartModel. Importing Pivot Charts alone loads no geographic assets or map dependency.

  • Return complete immediate-child frames from the analytical engine.
  • Preserve stable field, category, series, hierarchy, and path identities.
  • Echo the request ID and semantic scope exactly.
  • Forward abort signals to network and query work.
  • Set limits that match renderer and server budgets.
  • Include formatted display values when chart and Pivot formatting must match.
  • Log provider errors with request/view IDs without exposing raw sensitive source rows.
  • Exercise root, linked refresh, drill, retry, breadcrumb, and stale-response paths before release.

Previous: Headless API and persistence · Pivot Charts overview · Remote Pivot guide · API reference