Lattice Grid Buy a licence

developer guide

Leaflet as a Viewer of a JavaScript Data Grid

Your grid's rows, drawn by your own Leaflet layers, over your own map. The grid never imports Leaflet and Leaflet never imports the grid; bindLeaflet is the one connection between them, the same contract bindDeck already keeps with deck.gl.

bindLeaflet: one function, two-way

Import the Leaflet module and hand bindLeaflet a live grid and the L.Map a page has already built. Your own layers function is called with the rows the grid currently shows, so a filter, a sort or a live update reaches the map the same frame it reaches the table.

import { bindLeaflet } from '@toclocoinc/lattice-grid/modules/leaflet';

const binding = bindLeaflet(grid, {
  map,                                   // your own L.Map
  position: { lon: 'lon', lat: 'lat' },  // or geometry: '<col>'
  viewportFilter: true,
  layers: (rows, ctx) => [
    L.geoJSON(ctx.features),   // exactly the rows the grid currently shows
  ],
});
// layers is your own function, written against your own Leaflet classes; the
// module never imports Leaflet itself. It runs whenever the rows or the
// selection change, and its result replaces the previous layers on the map.

The map's own pan and zoom, as a filter

With viewportFilter on, every moveend/zoomend, including your own setView, fitBounds or flyTo, writes one withinBbox condition back onto the grid, replacing only its own previous one; a box set from elsewhere moves the map to match it in turn.

Rows inside the view, from a paged source

Bound to a paged pushdown source, bindLeaflet asks the engine for the rows inside the map's current view rather than only the loaded page, and falls back to density cells past a row cap.

// A paged pushdown grid hands over the rows inside the map's current view
// from the engine, not only the loaded page:
bindLeaflet(grid, { map, position: { lon: 'lon', lat: 'lat' }, viewportCap: 20000, layers });
// Past viewportCap, ctx.binned is true and the engine hands over density
// cells instead of individual rows. ctx.features carries the rows as GeoJSON
// features, id set to the row key.

Selection, both ways

A click on a feature drawn from ctx.features selects its row on the grid. For a layer of your own that carries no feature, binding.select(key) does the same from code; ctx.selected lets your layers function mark whichever row the grid has selected.

// A click on a feature of L.geoJSON(ctx.features) selects its row on its
// own. For a layer that carries no feature of its own:
binding.select(rowKey);   // null clears the selection
// The grid needs selection: 'single' or 'multiple'.
binding.destroy();  // removes the layers, the viewport condition, and the map and grid listeners

See it running in the Leaflet demo repository. The deck.gl guide covers the same binding contract over deck.gl, and the geospatial guide covers the geometry column type that feeds both.