Lattice Grid Buy a licence

demo D69

Totals that keep up

A live feed against a million rows with a totals row, timed

incremental grand totals

Building…
Loading a live grid…

The configuration

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.css">
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.js"></script>

<div id="grid" style="height: 540px"></div>

<script>
  const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
    rowKey: 'id',
    /*
     * Nothing here asks for the 1.4 behaviour. `sum`, `avg`, `min`, `max`
     * and `countValues` on a numeric column over a memory source are
     * maintained across cell updates by difference rather than re-reduced,
     * so a feed writing single cells does not walk a million rows to move
     * a total by one number.
     *
     * The reported figure is never a guess: where a running value cannot be
     * trusted the column falls back to a full pass. That is when a value
     * moves off the current min or max, when rows arrive or leave, when the
     * filter, sort or grouping changes, and when a sum grows large enough
     * that a 64-bit float stops registering small changes.
     */
    grandTotalRow: 'bottom',
    selection: 'multiple',
    toolPanel: {
      side: 'left',
      panels: ['columns', 'filters', 'views', 'quick'],
      actions: ['undo', 'redo', 'export', 'restore', 'maximise'],
      exportName: 'lattice-demo',
    },
    columns: [
      { field: 'desk', title: 'Desk', filter: { type: 'set' } },
      { field: 'book', title: 'Book', filter: { type: 'set' } },
      { field: 'region', title: 'Region', filter: { type: 'set' } },
      { field: 'currency', title: 'Ccy', layout: { width: 90 } },
      { field: 'notional', title: 'Notional', type: 'number', total: 'sum', format: { style: 'currency', currency: 'GBP', decimals: 0 } },
      { field: 'pnl', title: 'P&L', type: 'number', total: 'sum', format: { style: 'currency', currency: 'GBP', decimals: 2 } },
      { field: 'fee', title: 'Fee', type: 'number', total: 'sum', format: { style: 'currency', currency: 'GBP', decimals: 2 } },
      { field: 'rate', title: 'Rate', type: 'number', total: 'avg', format: { decimals: 3 } },
    ],
    rows,  // a million settlement rows
  });

  // Feed single-cell updates and the running totals catch up by difference.
  grid.rows.apply({ update: [{ id: 0, pnl: 1234.56 }] });
</script>

Keeping grand totals current under a fast-moving feed

Incremental grand totals are what keep a totals row honest while the underlying data is still arriving: a trading feed pushing thousands of updates a second, a live dashboard, or any source where rows change after the grid has already rendered them. The alternative, re-reducing every row on every update, is the usual cost of a naive totals row, and it scales with the size of the dataset rather than the size of the change. Lattice Grid avoids that: when an update lands, the grid adjusts the affected sums, counts and averages by the delta rather than recomputing them from the full row set, so a single-row change costs a single-row’s worth of arithmetic regardless of whether the grid holds a thousand rows or a million. This is the same discipline that makes a JavaScript data grid usable under a live feed at all: virtual scrolling keeps the DOM bounded to the visible rows, and incremental totals keep the aggregation layer bounded to the rows that actually moved. The demo runs a live feed against a million rows with a totals row attached, and times the update itself, so the cost of keeping the total current is visible rather than assumed. The same mechanism underpins group footers and pivot summaries, reading from the same per-column total definitions.

How do grid totals stay accurate when data updates in real time?

The grid recalculates each affected total from the change rather than the whole dataset: an update to one row adjusts the sum, count or average by that row’s delta, not by re-scanning every row. This keeps the cost of an update proportional to the number of rows it touches, which is what makes a totals row viable against a feed updating continuously rather than a static snapshot loaded once.