data router starter kit
Watch the whole operation on one screen.
The people running an operation need one screen that always adds up: orders arriving, shipments moving, incidents opening and closing, and a throughput line along the bottom. This template drives all of it from a single feed, so every panel is reading the same moment and nobody is reconciling four connections by eye.
Live above, running in your browser with no backend. The feed is the mock socket that ships with the grid; going live is the one line that builds it.
why it fits the desk
One feed, the whole screen.
Orders, shipments and incidents are different shapes with different columns, so they get their own grids side by side rather than one table filtered three ways. Split the single feed by what each record is and every grid fills itself, live.
Pick a run of orders and the incidents grid narrows to the same regions on its own, so you drill from what is selling into what is going wrong with one click while the feed keeps arriving underneath.
It runs with no backend, so you can shape the screen for your operation first and point it at your real stream when you are ready. Going live is a single line.
what the one feed fills
Everything on the screen, off one source.
Orders
Every order as it lands, with a live running total.
Shipments
What is moving, by carrier and region.
Incidents
What is open right now, narrowing to the orders you select.
Throughput
A live chart of events per tick, off the same feed.
the whole thing, to paste
The code that runs it.
This is the entire template: two script tags for the modules, plain grids, one router in front, and the mock socket driving them. It is what the sandbox opens and what runs above. Paste it into an empty page and it works. On localhost the grid is free to use; a deployed site is licensed per domain.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.33.0/lattice-grid.min.css">
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.33.0/lattice-grid.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.33.0/modules/charts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.33.0/modules/data-router.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.33.0/modules/mock-socket.min.js"></script>
<style>
body { font-family: system-ui, sans-serif; margin: 0; padding: 16px; background: #f6f7f9; color: #1b2430; }
.ops { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }
.panel { background: #fff; border: 1px solid #e3e6ea; border-radius: 10px; overflow: hidden; min-width: 0; }
.panel h2 { font-size: 13px; margin: 0; padding: 8px 12px; border-bottom: 1px solid #eef0f3; color: #3a4250; font-weight: 600; }
.grid { height: 300px; }
#chart { height: 200px; margin-top: 12px; background: #fff; border: 1px solid #e3e6ea; border-radius: 10px; }
@media (max-width: 820px) { .ops { grid-template-columns: 1fr; } }
</style>
<div class="ops">
<div class="panel"><h2>Orders</h2><div id="orders" class="grid"></div></div>
<div class="panel"><h2>Shipments</h2><div id="shipments" class="grid"></div></div>
<div class="panel"><h2>Incidents</h2><div id="incidents" class="grid"></div></div>
</div>
<div id="chart"></div>
<script>
var g = LatticeGrid;
var money = { style: 'currency', currency: 'USD', decimals: 0 };
// Three plain grids, one per kind of record. None of them knows about the feed.
var orders = g.createGrid(document.getElementById('orders'), {
rowKey: 'id', theme: 'light', selection: 'multiple',
columns: [
{ field: 'id', title: 'Order', layout: { width: 110 } },
{ field: 'region', title: 'Region', filter: { type: 'set' } },
{ field: 'customer', title: 'Customer' },
{ field: 'value', title: 'Value', type: 'number', format: money, total: 'sum' },
],
});
var shipments = g.createGrid(document.getElementById('shipments'), {
rowKey: 'id', theme: 'light',
columns: [
{ field: 'id', title: 'Shipment', layout: { width: 110 } },
{ field: 'region', title: 'Region', filter: { type: 'set' } },
{ field: 'carrier', title: 'Carrier' },
{ field: 'units', title: 'Units', type: 'number', total: 'sum' },
{ field: 'status', title: 'Status' },
],
});
var incidents = g.createGrid(document.getElementById('incidents'), {
rowKey: 'id', theme: 'light',
columns: [
{ field: 'id', title: 'Incident', layout: { width: 110 } },
{ field: 'region', title: 'Region', filter: { type: 'set' } },
{ field: 'service', title: 'Service' },
{ field: 'severity', title: 'Severity' },
{ field: 'status', title: 'Status' },
],
});
// A headless grid holds the throughput rollup with no table of its own; the
// chart reads it, so the chart rides the same feed as the tables.
var metrics = g.createHeadlessGrid({
rowKey: 't',
columns: [{ field: 't', type: 'number' }, { field: 'events', type: 'number' }],
});
// One router, keyed on the kind of record. Each view is attached to the slice
// it wants and only ever sees its own rows.
var router = LatticeGridDataRouter.createDataRouter({ key: 'type', rowKey: 'id' });
router.attach(orders, 'order');
router.attach(shipments, 'shipment');
router.attach(incidents, 'incident');
router.attach(metrics, 'metric', { rowKey: 't' });
// Pick one or more orders and the incidents grid narrows to the same regions.
router.link(orders, incidents, { from: 'region', to: 'region' });
// The chart follows the headless grid, so it advances as the feed does.
g.createChart({ grid: metrics, container: '#chart', type: 'line', x: 't', y: 'events', title: 'Throughput per tick' });
// The feed, with no backend. Going live is one line: swap the mock socket for
// var socket = new WebSocket('wss://ops.example.com/stream');
var socket = new LatticeGridMockSocket.MockWebSocket({ feed: LatticeGridMockSocket.opsFeed({ seed: 7 }), rate: 900, jitter: 300 });
socket.onmessage = function (event) {
var message = JSON.parse(event.data);
if (message.kind === 'snapshot') router.load(message.rows);
else router.apply(message.changes);
};
</script>
Open it in the sandbox and edit it live → How the Data Router works →
more starter kits