Lattice Grid Buy a licence

demo D125

Presentation mode

Scale the whole grid up for a room, then come back

grid.presentation.start() · nudge() · stop()

Building…
Loading a live grid…

The configuration

import * as ng from '@angular/core';
import { Component, ViewChild } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import createLatticeGrid from '@toclocoinc/lattice-grid/modules/angular';

const { LatticeGridComponent } = createLatticeGrid({ ng, createGrid });

// Saved views are the slides the deck steps through.
const views = {
  saved: [
    {
      id: 'prod-spend',
      name: 'Production spend',
      state: {
        version: 1,
        filters: { op: 'and', conditions: [{ col: 'environment', op: 'in', value: ['prod', 'prod-2', 'definitely-prod'] }] },
        sort: [{ col: 'cost', dir: 'desc' }],
        group: [],
      },
    },
    {
      id: 'biggest-movers',
      name: 'Biggest movers',
      state: { version: 1, filters: null, sort: [{ col: 'change', dir: 'desc' }], group: [] },
    },
    {
      id: 'by-service',
      name: 'By service',
      state: { version: 1, filters: null, sort: [{ col: 'cost', dir: 'desc' }], group: ['service'] },
    },
  ],
};

const columns = [
  { field: 'account', title: 'Account', filter: { type: 'set' } },
  { field: 'service', title: 'Service', filter: { type: 'set' } },
  { field: 'resource', title: 'Resource', layout: { flex: 1, min: 200, max: 320 } },
  { field: 'region', title: 'Region', filter: { type: 'set' } },
  { field: 'environment', title: 'Env', filter: { type: 'set' },
    cell: { decoration: 'pill', variant: { map: {
      prod: 'danger', 'prod-2': 'danger', 'definitely-prod': 'danger',
      staging: 'warning', untagged: 'warning', test: 'info',
      dev: 'success', 'not-prod': 'neutral',
    } } } },
  { field: 'change', title: 'Change', type: 'number',
    layout: { width: 140, min: 140 }, format: { style: 'percent', decimals: 1 } },
  { field: 'cost', title: 'Monthly cost', type: 'number', layout: { width: 170 },
    format: { style: 'currency', currency: 'USD', decimals: 2 }, total: 'sum' },
];

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [LatticeGridComponent],
  template:
    '<div style="display:flex;gap:8px;margin-bottom:12px">' +
    '  <button (click)="present()">Present</button>' +
    '  <button (click)="presentDeck()">Present the views as slides</button>' +
    '  <button (click)="spotlightCost()">Spotlight the cost column</button>' +
    '  <button (click)="stop()">Stop</button>' +
    '</div>' +
    '<lattice-grid [config]="grid" style="display:block;height:540px"></lattice-grid>',
})
export class AppComponent {
  @ViewChild(LatticeGridComponent) gridRef!: LatticeGridComponent;

  grid = {
    rowKey: 'id',
    selection: 'multiple',
    views,
    toolPanel: { side: 'left', panels: ['columns', 'filters', 'views', 'quick'],
      exportName: 'lattice-demo', actions: ['restore', 'maximise'] },
    columns,
    rows: [/* cloud cost rows */],
  };

  // Presentation is an API rather than a config key, and it takes over the
  // viewport, so drive it from the live grid.
  present() { this.gridRef.grid.presentation.start({ scale: 1.5 }); }
  presentDeck() {
    this.gridRef.grid.presentation.start({ scale: 1.5, views: ['prod-spend', 'biggest-movers', 'by-service'] });
  }
  // A spotlight paints while presenting and dims every cell outside the Monthly
  // cost column.
  spotlightCost() { this.gridRef.grid.presentation.setSpotlight({ colIds: ['cost'] }); }
  stop() { this.gridRef.grid.presentation.stop(); }
}

bootstrapApplication(AppComponent);

Scaling a grid up for a room, then handing control back

Presentation mode enlarges the whole grid for viewing at a distance, then returns it to its normal layout without losing the reader’s place. A developer reaches for it when a JavaScript data grid built for a desk gets walked into a meeting: a dashboard cast to a conference screen, a review of figures on a shared monitor, a status board glanced at from across a room. Rather than a separate zoomed view, Lattice Grid scales the existing rows and columns in place, so column widths, sort order, and any applied filters stay exactly as the presenter left them. The demo is driven through grid.presentation.start(), nudge(), and stop(): start switches to the enlarged layout, nudge steps the focus forward or back a row so a presenter can advance through figures from a clicker or the keyboard, and stop restores the working layout. Because the scaling changes font size and row height rather than re-rendering the data, the switch is immediate even on a grid holding tens of thousands of rows, and virtual scrolling continues to render only the rows in view, so a large table stays as responsive at presentation scale as at desk scale. Keyboard focus carries across the switch, so a screen reader user does not lose their position when the layout changes size.

How do I make a data grid readable from across a room?

Call grid.presentation.start() to switch the grid into an enlarged layout that keeps the current data, sort, and filters in place, then nudge() to step through rows without leaving the keyboard. grid.presentation.stop() returns the grid to its normal size. The scaling only changes row height and font size, so it works the same way regardless of how many rows the grid is holding.