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(): 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.

get cache(): PivotCache | null;

The live cache this pivot table computes from (possibly shared), or null before it is bound.

PivotCache | null


get colFieldIndices(): readonly number[];

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

readonly number[]


get colFields(): readonly PivotField[];

readonly PivotField[]


get colGrandTotals(): boolean;

boolean


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 fields(): readonly PivotField[];

readonly PivotField[]


get layoutForm(): "outline" | "compact" | "tabular";

The report layout form, read from the fields on the row and column axes: the form is recorded per field and the layout renders from those flags, while the root compact and outline are the defaults for a field placed later. Fields that disagree report the least tabular form among them, compact before outline. A definition with no axis field reports the root’s form.

"outline" | "compact" | "tabular"


get location(): PivotTableLocation;

PivotTableLocation


get measures(): readonly PivotMeasure[];

readonly PivotMeasure[]


get missingCaption(): string | undefined;

string | undefined


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 pageFields(): readonly PivotField[];

readonly PivotField[]


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 rowFields(): readonly PivotField[];

readonly PivotField[]


get rowGrandTotals(): boolean;

boolean


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 showMissing(): boolean;

boolean


get style(): PivotTableStyle | undefined;

PivotTableStyle | undefined

addMeasure(field, options?): PivotMeasure;

PivotField

PivotDataFieldAggregation

string

PivotMeasure

field belongs to another pivot table, or a cache refresh removed it


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). A null name takes the pivot table’s first data field, as GETPIVOTDATA’s Excel-97 text form does when it names no data field.

string | null

[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


matchLookupName(name): PivotLookupName | null;

What a name names in this pivot table (see matchLookupName), or null when it names nothing in it. A pivot table with no cache names nothing.

string | number

PivotLookupName | null


rename(newName): void;

string

void

the new name is taken on the same sheet (at update commit)

the new name is empty


setGrandTotals(axis, enabled): void;

"col" | "row"

boolean

void


setLayoutForm(form): void;

"outline" | "compact" | "tabular"

void


setMissingCaption(caption): void;

string | undefined

void


setShowMissing(show): void;

boolean

void