Skip to content
Spreadsheet Engine

PivotTable

Runtime representation of a pivot table. Wraps the JSF PivotTable definition and provides methods for computing layout, writing to sheet cells, and looking up values for GETPIVOTDATA.

new PivotTable(jsf): PivotTable;

PivotTable

PivotTable

readonly cacheIndex: number;

Position in the owning manager’s _caches array, or -1 when unbound. Used only for serialization correlation; runtime lookups go through the attached cache directly. Readonly because the invariant “matches manager._caches.indexOf(_cache)” must be updated atomically with the cache attachment.


readonly jsf: PivotTable;
get colFieldIndices(): readonly number[];

Column field indices with negative placeholders (e.g. -2 for “Values”) filtered out.

readonly number[]


get colGrandTotals(): boolean | undefined;

boolean | undefined


get colRoles(): PivotColRole[];

Column-axis style roles --- the rowRoles mirror for the column axis, as 0-based column offsets from the left of the output area. The renderer positions a declared table style’s firstSubtotalColumn region on these.

The column axis has no outline/separator placement modes (column subtotals always sit right-of-group), so every entry is a subtotal; there is no column subheading. A column subtotal materializes once per displayed data field --- the data fields multiply the columns, except in the hideValuesRow collapse where they show as a single block, and in the row-axis Values (onRows) layout where they multiply rows instead --- so this emits one role per (subtotal, displayed data-field column), at the same columns the cell emitter writes them to: the positions come from the emitter’s own subtotalCol closure (see _refRelativeEmitter). Verified against excel-test/pivot-valuesouter-colsubtotal-verify and excel-test/pivot-values-inner-position.

PivotColRole[]


get colStride(): number;

Columns each column-header group occupies in the computed output: normally one per data field, but collapses to 1 when the location lacks slack for the synthetic Values row (Excel’s hideValuesRow="1" signature: multi-data

  • col-axis + no slack between firstHeaderRow and firstDataRow). Used by the cell emitter for column position arithmetic --- except the row-axis Values layout, which overrides the column stride to 1 and expands rows by the data-field count instead (see resolveRowAxisStrides). Degenerate case (no data fields) yields 1.

number


get dataFields(): readonly PivotDataField[];

The data fields (a fresh deep copy on every read --- elements too, since the readonly array typing would not stop element mutation), defaulting to empty when absent. Mutations belong on jsf.dataFields (followed by clearLayout), never here.

readonly PivotDataField[]


get location(): PivotTableLocation;

PivotTableLocation


get name(): string;

string


get pageArea():
| PivotPageArea
| null;

Geometry of the page-field (report filter) area, or null when the pivot has no page fields. The renderer (mondrian) reads this to find the filter cells --- they sit above and outside ref, so its per-cell pivot index built from ref never reaches them --- e.g. to position a declared table style’s pageFieldLabels / pageFieldValues regions.

The geometry is purely positional: when the anchor sits too high for all the rows to fit (a hand-built JSF; Excel reserves the rows on creation), the reported region can extend above the top of the sheet, and getCellWrites omits the cells that fall there. Callers clip to the sheet.

| PivotPageArea | null


get ref(): string;

The A1-style range covering the pivot’s output area.

string


get rowFieldIndices(): readonly number[];

Row field indices with negative placeholders (e.g. -2 for “Values”) filtered out.

readonly number[]


get rowGrandTotals(): boolean | undefined;

boolean | undefined


get rowRoles(): PivotRowRole[];

Style roles of the output rows that are not plain data rows: the row axis’s subheading (group label) and subtotal rows, as 0-based row offsets from the top of the output area. The renderer (mondrian) reads this to position a declared table style’s firstRowSubheading / firstSubtotalRow regions. Blank separator rows (insertBlankRow="1") carry no role; the renderer styles them as plain body rows. In the row-axis Values (dataOnRows) layout each aggregate subtotal spans one sheet row per data field, so it contributes that many entries --- regardless of its role, since an outline-above aggregate (Values nested at a non-innermost row position) classifies as a subheading yet still expands (see below). Only the separator and blank rows stay single-row (the positioner collapses their data-field offset).

A row is a subheading when it is the group’s label row, and a subtotal only when it is a dedicated subtotal row below its group. Excel styles the above-group row (outline/compact “subtotal at top”, where the group label and its subtotal share one row) as a subheading, not a subtotal --- verified in Excel on PivotStyleLight16 (an above-group row shows no top border and no fill, the firstRowSubheading look, where firstSubtotalRow would add a top border). So outlineAbove rows classify as subheading alongside the bare separator rows; only below-group rows (outlineAbove === false) are subtotal.

PivotRowRole[]


get sheet(): string;

string


get style(): PivotTableStyle | undefined;

PivotTableStyle | undefined

containsOutput(row, col): boolean;

Check whether (row, col) falls within this pivot table’s output area.

number

number

boolean


getDataValue(
dataFieldName,
criteria,
options?):
| CellValue
| PivotLookupError;

Look up an aggregated value by data field name and field/item criteria (GETPIVOTDATA).

string

[string, CellValue][]

boolean

| CellValue | PivotLookupError


getOutputBounds():
| Readonly<OutputBounds>
| null;

Compute and cache the output bounds from the materialized cell writes. Unlike ref, which is only rewritten when a refresh/repaint runs and so can lag a source-data change, these bounds always reflect the current data. Returns null for malformed refs. Every call returns a fresh copy: the bounds behind containsOutput, PivotManager.findAt, and the pivot write guards must not be reachable through the return value.

| Readonly<OutputBounds> | null


getProtectedBounds():
| Readonly<OutputBounds>
| null;

The pivot’s full protected footprint: its output area (getOutputBounds) extended to cover the page-field (report-filter) area, which materializes ABOVE the anchor (and, when the page fields wrap into multiple column-groups, to the RIGHT of the body) and outside ref (see PivotPageArea). Identical to getOutputBounds when the pivot has no page fields.

The range/structural write guards (clearCells, moveCells, insert/delete cells, insert/delete rows or columns) use this rather than getOutputBounds so they agree with the single-cell write guard, which blocks writes anywhere in the per-sheet R-tree footprint (fed from boundsOfWrites, which already covers the page-field caption cells). Without it, a range or structural edit overlapping only the page area would slip past while a direct write to the same cell is blocked.

Body-bounds consumers keep using getOutputBounds: syncLayoutToJSF’s ref excludes the page area by Excel convention, and the adopted-output export scrub deliberately reads only the body.

| Readonly<OutputBounds> | null