Skip to content

DataView

DataView provides a mapping layer between logical (visible) row indices and physical (CellStore) row indices. When sorting or filtering is active, logical row 0 may map to physical row 500. When no sort/filter is active, DataView operates as a zero-overhead passthrough.

Logical rows (what user sees)
↕ DataView mapping
Physical rows (CellStore storage)

All engine subsystems (selection, editing, rendering) work with logical indices. CellStore operations use physical indices. DataView translates between the two.

import { DataView } from '@witqq/spreadsheet';
const view = new DataView({ totalRowCount: 10000 });
interface DataViewConfig {
totalRowCount: number;
}

Convert a logical (visible) row index to its physical (CellStore) row index:

const physRow = view.getPhysicalRow(0); // First visible row → actual storage row

Returns -1 if the logical row has no mapping (out of range).

Convert a physical row index back to logical. Returns undefined if the row is hidden (filtered out):

const logRow = view.getLogicalRow(500);
if (logRow === undefined) {
console.log('Row 500 is filtered out');
}

Number of visible rows after filtering:

console.log(view.visibleRowCount); // e.g., 7500 (after filter)

Total physical rows (before filtering):

console.log(view.totalRowCount); // e.g., 10000

True when logical === physical (no sort/filter active). In passthrough mode, getPhysicalRow returns the input directly with zero overhead:

if (view.isPassthrough()) {
console.log('No sort/filter — direct mapping');
}

Set a new mapping. physicalIndices[logicalRow] = physicalRow. Called by SortEngine and FilterEngine after sorting/filtering:

// After sorting: logical row 0 = physical row 42, etc.
view.recompute([42, 15, 88, 3, 201, ...]);
console.log(view.visibleRowCount); // length of indices array

Also builds a reverse mapping (Map<physical, logical>) for getLogicalRow().

Reset to passthrough (identity mapping):

view.reset();
console.log(view.isPassthrough()); // true
console.log(view.visibleRowCount === view.totalRowCount); // true

Update total row count when rows are added or removed. In passthrough mode, this also updates visibleRowCount:

view.setTotalRowCount(15000); // e.g., after pushRows

The sort/filter pipeline uses DataView as the output layer:

FilterEngine.apply()
→ produces filtered physical indices
→ SortEngine.sort()
→ reorders filtered indices
→ DataView.recompute(finalIndices)

When both are cleared:

DataView.reset() → passthrough mode

StreamingAdapter.updateRow() and StreamingAdapter.deleteRow() use DataView.getPhysicalRow() internally. This ensures that operations on logical indices (what the user sees) correctly target the right physical rows, even when sort/filter is active.

  • Sorting — multi-column sort via DataView
  • Filtering — 14 filter operators via DataView
  • Streaming Data — live row updates with DataView integration