demo D37
Pie and donut in a cell in htmx
Composition per row, at 24 pixels, still legible
render: 'pie' | 'donut'
This grid draws a pie or donut inside a cell, small enough to sit in a normal row yet still legible. It shows a row's value as a share of a whole, a queue split by priority or a budget by category, without moving it to a dashboard tile.
This is the htmx version. A server-rendered table is upgraded in place, so the page is readable before any script runs and gains the full grid when the module loads, which suits a progressively enhanced app.
The configuration
<link rel="stylesheet" href="https://cdn.latticegrid.dev/lattice-grid@1.107.0/lattice-grid.min.css">
<!-- A real, server-rendered table: readable with JavaScript off. data-field on
each header names the column that cell becomes, and data-id on each row is
the key the grid carries it under. -->
<table id="pie-and-donut-table" data-lattice-grid>
<thead>
<tr>
<th data-field="service">Service</th>
<th data-field="team">Team</th>
<th data-field="mix">Pie</th>
<th data-field="region">Region</th>
</tr>
</thead>
<tbody>
<tr data-id="0"><td>fraud-edge</td><td>Commerce</td><td>[45,23,14,4.5]</td><td>us-east-1</td></tr>
<tr data-id="1"><td>payments-stream</td><td>Growth</td><td>[52,34,16,2.9]</td><td>us-east-1</td></tr>
<tr data-id="2"><td>checkout-edge</td><td>Payments</td><td>[49,22,13,0.1]</td><td>us-west-2</td></tr>
<!-- the rest of the rows, rendered by your server -->
</tbody>
</table>
<script type="module">
import { readTable, hydrateTable } from 'https://cdn.latticegrid.dev/lattice-grid@1.107.0/modules/htmx.esm.min.js';
// A table cell carries text, so the column whose value is a whole object
// travels as JSON and is read back here. Everything else
// arrives as the number, boolean or string it already looks like.
const rows = readTable(document.getElementById('pie-and-donut-table')).rows.map((row) => ({
...row,
mix: JSON.parse(row.mix),
}));
// The markup carries the rows; a server-rendered table's column types are
// declared in the config hydrateTable takes. The grid replaces the table
// where it stood.
const grid = hydrateTable(document.getElementById('pie-and-donut-table'), {
selection: 'multiple',
toolPanel: {
side: 'left',
panels: ['columns', 'filters', 'views', 'quick'],
actions: ['undo', 'redo', 'export', 'restore', 'maximise'],
exportName: 'lattice-demo',
},
columns: [
{ field: 'service', title: 'Service', layout: { pin: 'start', width: 170 } },
{ field: 'team', title: 'Team', filter: { type: 'set' } },
// Each cell draws the row's mix as a whole, with no chart to wire up.
{ id: 'mix-pie', field: 'mix', title: 'Pie', layout: { width: 110 },
sort: { enabled: false }, filter: { enabled: false }, cell: { render: 'pie' } },
// The hole is a fraction of the radius. Larger reads as a ring and loses
// the small slices, so a thin ring is about as far as this size goes.
{ id: 'mix-donut', field: 'mix', title: 'Donut', layout: { width: 110 },
sort: { enabled: false }, filter: { enabled: false }, cell: { render: 'donut', props: { hole: 0.55 } } },
{ id: 'mix-thin-donut', field: 'mix', title: 'Thin donut', layout: { width: 130 },
sort: { enabled: false }, filter: { enabled: false }, cell: { render: 'donut', props: { hole: 0.72 } } },
{ id: 'mix-the-same-stacked', field: 'mix', title: 'The same, stacked', layout: { width: 200 },
sort: { enabled: false }, filter: { enabled: false }, cell: { render: 'stacked' } },
{ field: 'region', title: 'Region', filter: { type: 'set' } },
],
rows,
});
</script>
Drawing a pie or donut chart inside a single cell
A pie or donut in a cell is a composition chart, share of total, drawn small enough to sit inside a normal row rather than a dashboard tile. A developer reaches for one wherever a row’s value is really a split, a support queue broken down by priority, a budget by department, a portfolio by asset class, and the split itself is the fact worth seeing at a glance next to the row’s other columns. Lattice Grid controls the shape with the render option on a column definition, set to 'pie' or 'donut', so a column of category breakdowns switches between a filled disc and a ringed one by changing a single string. The cell value is an array of segment values, drawn to a small canvas sized to the row height, commonly 24 pixels, so segment boundaries stay distinguishable rather than blurring into a smudge of colour. Because charts are canvas-based and scoped to the cell, only rows currently on screen are drawn, so a column of compositions scrolling through several thousand rows costs no more than any other rendered column, the same row virtualisation that keeps a JavaScript data grid responsive elsewhere in the sheet. Segment colours are set once per column, so a sheet of pie or donut cells stays visually consistent without per-row styling work.
Can you put a pie chart inside a table cell?
Yes. Set render: 'pie' or render: 'donut' on a column definition in Lattice Grid and pass an array of segment values as the cell’s data. The grid draws a small canvas chart sized to the row for each visible cell, so a table of accounts, categories or queues can show each row’s composition alongside its other fields, without a separate chart panel.
An in-cell renderer, not the charting module. This draws one SVG inside a cell, sized to the cell and costing what a cell costs as rows recycle. It is a different, older feature from the charts module, which draws full charts from the grid’s own filtered rows across thirty types and redraws them as the grid moves. Reach for a renderer when the shape belongs in the row; reach for charts when it belongs above the grid.