Cells
Canvas Cell Renderer
The GraphiteGridCanvas
renderer draws to an HTML canvas element. You can
define a custom cell renderer for the canvas using the cellCanvasRenderer
property on the column definition.
The cellCanvasRenderer
property is an object that provides two properties:
drawFunc
: a function called to draw to a cell.drawPortal
: a function that returns a React component relative to the cell's top-left corner.
Both properties can be provided, allowing you to mix DOM functionality with the Canvas Cell.
Using the drawFunc
Property
The example below demonstrates a custom canvas cell renderer that draws a basic sparkline based on the row data provided to the grid.
Info
The drawFunc
receives a CellCanvasRendererParams
object, which contains
viewX
and viewY
properties. These properties represent the x
and y
coordinates of the grid cell relative to the viewport. Any drawing must be
bounded by viewX
, viewY
, and the cell's width
and height
. Graphite Grid
clips content outside the rectangle described by the points:
- Top-left:
viewX, viewY
- Bottom-right:
viewX + width, viewY + height
const rowData = [
["Rob Co", 1884, [4000, 3000, 2000, 2780, 1890, 2390, 3490]],
["Cats R Us", 1993, [4000, 2100, 3000, 2280, 1890, 4390, 1490]],
["Carl Inc", 2024, [1000, 3020, 1500, 2780, 1800, 2900, 1890]],
];
function CanvasCellRenderer<T>({
ctx,
viewX,
viewY,
width,
height,
theme,
field,
}: CellCanvasRendererParams<T>) {
if (!Array.isArray(field)) return;
const widthSpacing = width / field.length;
const maxHeight = Math.max(...field);
ctx.beginPath();
ctx.moveTo(viewX, viewY + height - 2);
ctx.strokeStyle = theme.color;
ctx.lineWidth = 1.5;
ctx.lineCap = "round";
for (let i = 1; i <= field.length; i++) {
const dataPoint = field[i - 1];
const x = viewX + widthSpacing * i;
const y = viewY + height * (dataPoint / maxHeight);
ctx.lineTo(x, y);
}
ctx.stroke();
}
export function CanvasCellRendererExample() {
const grid = useGraphiteGrid({
initial: {
columnDefinitions: [
{ id: "company-name", headerLabel: "Company Name", field: 0 },
{ id: "founded", headerLabel: "Founded", field: 1 },
{
id: "performance",
headerLabel: "Performance",
field: 2,
cellCanvasRenderer: { drawFunc: CanvasCellRenderer },
},
],
// other props
},
});
return (
<div style={{ height: 200 }}>
<GraphiteGridCanvas state={grid} />
</div>
);
}
Using the drawPortal
Property
Adding interactivity to cells in the Canvas
Grid can be complex. Cell events
should suffice for cell-level interactions. However, for
interactions concerning specific elements within a cell,
the drawPortal
property is a better option.
The drawPortal
property is a function that returns a React component.
This component is positioned relative to the grid cell on the canvas,
allowing you to mix canvas drawings with DOM elements.
In the example below, a portal renderer displays two buttons that increment and decrease the item count.
const countData: [string, number][] = [
["apple", 0],
["banana", 0],
["orange", 0],
];
function IncrDecrPortal({ api, row }: CellRendererParams<[string, number]>) {
return (
<div>
<button
onClick={() => {
const source = api.getRowDataSource();
if (source?.kind !== "client") return;
const data = source.data;
data[row.rowIndex!][1]++;
api.refreshRowDataSource();
}}
>
Incr
</button>
<button
onClick={() => {
// similar to increment
}}
>
Decr
</button>
</div>
);
}
export function CanvasCellDrawPortal() {
const grid = useGraphiteGrid<[string, number]>({
initial: {
columnDefinitions: [
{ id: "item", headerLabel: "Item", field: 0 },
{ id: "count", headerLabel: "Count", field: 1 },
{
id: "buttons",
headerLabel: "Incr/Decr",
field: 2,
cellCanvasRenderer: {
drawPortal: IncrDecrPortal,
},
},
],
// other props
},
});
return (
<div style={{ height: 200 }}>
<GraphiteGridCanvas state={grid} />
</div>
);
}
By leveraging the cellCanvasRenderer
property and its drawFunc
and
drawPortal
functions, you can create custom cell renderers for the Canvas Grid
that suit your application's specific needs.