Add column, bar, line, area, pie, doughnut and scatter charts that read cell ranges and redraw when those cells change; place, move and edit them in the grid.On this page
if (result.status!=="applied") thrownewError("The chart was not added");
A chart reads cell ranges. It does not copy their values: when a source cell
changes, by an edit, a formula, a spill or a pivot, the chart redraws. A chart
belongs to a sheet and floats over its cells.
Add the charts package
Core keeps the chart definitions, and @sheetwrite/charts draws them. Install
it and call registerChartsBackend() once, before or after you create grids.
To register by import only, import @sheetwrite/charts/register.
$ npm install @sheetwrite/charts
Without the package, the document still keeps, saves, undoes and synchronizes
charts, and each one shows as a plain frame with its title. Grids that have no
charts do not load chart code.
Define a chart
Commit the complete definition with setChart(chart, sheet?). A second call
with the same id on the same sheet replaces the chart. Each call is one undo
step and returns the transaction result, so a rejected chart reports why.
Field
Meaning
id
A stable ID, unique on its sheet.
kind
column, bar, line, area, pie, doughnut or scatter.
title
Text above the chart. Without it, the chart has no title.
axes
{ xTitle, yTitle }, the axis titles.
legend
none, top, right, bottom or left.
anchor
The top-left cell (row, col), the offset from that cell, and the size, all in CSS pixels.
series
One entry for each series: values, optional categories, and a name or a nameRange.
Ranges can be on any sheet. Pie and doughnut charts draw the first series.
Scatter charts use numeric categories as x values.
getCharts(sheet?) returns copies of the definitions.
removeChart(id, sheet?) removes a chart as one undo step.
selectChart(id, sheet?) selects a chart, and null clears the selection.
Limits: 100 charts on a sheet, 32 series in a chart, and 10,000 points in a
source range. A longer range draws its first 10,000 cells and shows a note.
What the chart shows
Text, booleans, errors and empty cells are gaps, not zeros.
Axis labels use the number format of the source cells.
A deleted source range becomes #REF!, and the chart shows a note.
Dense line, area and scatter series are thinned to the lowest and highest
value in each horizontal pixel, so a 10,000-point series stays fast.
Screen readers announce a chart by its title and kind. The chart image inside
it has a description that lists the series.
Insert and edit in the grid
Grids with the ribbon have Insert › Chart. Its face makes a column chart
from the selection, and its menu makes any of the seven kinds. A text first row
gives the series names, and a text first column gives the categories. The chart
panel opens beside the grid, where you change the kind, the ranges and the
titles. Each change is one undo step.
Right-click a chart, or press Shift+F10 on a selected chart, for Edit chart
and Delete chart.
Click a chart to select it. Drag it to move it, or drag a handle to resize it.
On a read-only grid you can select a chart, but not change it.
Key
Action on the selected chart
Arrow keys
Move by one pixel
Shift+arrow keys
Move by one cell
Enter
Open the chart panel
Delete or Backspace
Remove the chart
Escape
Return to the grid
The grid emits chart-select with { sheet, id }, or null, when the
selection changes, and chart-activate when Enter is pressed on a chart.
Colors
Series take their colors in order from --sheetwrite-chart-1 to
--sheetwrite-chart-8. The defaults have enough contrast on light and dark
themes. Set the variables on the grid's host element to use your palette.
Live data without a grid
A host that draws its own charts can read the same live data.
createChartViewCache(store) from @sheetwrite/charts returns resolved views:
the values, categories and number formats of each series. It notifies its
listeners when a chart's data changes, and gives no notice for edits to other
cells.
function registerChartsBackend(): voidfunctionregisterChartsBackend():voidfunctionregisterChartsBackend():voidRegister the chart view cache as the core chart view provider, so openChartViews(store) returns live chart views, and the SVG chart renderer, so grids created after this call draw their charts.Exampleimport { registerChartsBackend } from"@sheetwrite/charts";import { openChartViews, type Store } from"@sheetwrite/core";registerChartsBackend();functionsalesChartValues(store:Store) {constcharts=openChartViews(store);constvalues= charts.get({ sheet: "s", id: "sales" })?.series[0]?.values ?? [];charts.dispose();return values;}API reference →const grid: Gridconstgrid:Gridconstgrid:GridThe imperative core grid this controller owns.API reference →Grid.setChart(chart: ChartDefinition, sheet?: SheetId): ApplyTransactionResultGrid.setChart(chart: ChartDefinition, sheet?: SheetId): ApplyTransactionResultGrid.setChart(chart: ChartDefinition, sheet?: SheetId): ApplyTransactionResultInsert or replace the chart with chart.id as one undo entry. sheet defaults to the active sheet; chart IDs are unique only within a sheet.API reference →ChartDefinition.id: stringinterfaceChartDefinition {id:string;}interfaceChartDefinition {id:string;}Stable identity used by operations, history, and collaboration rebase.API reference →ChartDefinition.kind: ChartKindinterfaceChartDefinition {kind:ChartKind;}interfaceChartDefinition {kind:ChartKind;}ChartDefinition.title?: string | undefinedinterfaceChartDefinition {title?:string|undefined;}interfaceChartDefinition {title?:string|undefined;}Text above the chart; undefined shows no title.API reference →ChartDefinition.anchor: ChartAnchorinterfaceChartDefinition {anchor:ChartAnchor;}interfaceChartDefinition {anchor:ChartAnchor;}Top-left output cell on the owning sheet. Deleting the anchor's row or column keeps the pivot and moves the anchor to the first surviving cell at the deletion position.API reference →ChartAnchor.row: numberinterfaceChartAnchor {row:number;}interfaceChartAnchor {row:number;}0-based row of the cell that holds the top-left corner.API reference →ChartAnchor.col: numberinterfaceChartAnchor {col:number;}interfaceChartAnchor {col:number;}0-based column of the cell that holds the top-left corner.API reference →ChartAnchor.offsetX: numberinterfaceChartAnchor {offsetX:number;}interfaceChartAnchor {offsetX:number;}API reference →ChartAnchor.offsetY: numberinterfaceChartAnchor {offsetY:number;}interfaceChartAnchor {offsetY:number;}API reference →ChartAnchor.width: numberinterfaceChartAnchor {width:number;}interfaceChartAnchor {width:number;}Unzoomed column width in CSS pixels.API reference →ChartAnchor.height: numberinterfaceChartAnchor {height:number;}interfaceChartAnchor {height:number;}Host height in CSS pixels for numbers or any CSS length string.API reference →ChartDefinition.series: ChartSeries[]interfaceChartDefinition {series:ChartSeries[];}interfaceChartDefinition {series:ChartSeries[];}ChartSeries.nameRange?: ChartRange | undefinedinterfaceChartSeries {nameRange?:ChartRange|undefined;}interfaceChartSeries {nameRange?:ChartRange|undefined;}Range.sheet: stringinterfaceRange {sheet:string;}interfaceRange {sheet:string;}Sheet identity used by the simple data-first adapter. Defaults to sheet1.API reference →Range.start: {
row: number;
col: number;
}interfaceRange {start: {row:number;col:number;};}interfaceRange {start: {row:number;col:number;};}Zero-based workbook column index of the first key.API reference →row: numberlet row:numberlet row:number0-based row of the cell that holds the top-left corner.API reference →col: numberlet col:numberlet col:number0-based column of the cell that holds the top-left corner.API reference →Range.end: {
row: number;
col: number;
}interfaceRange {end: {row:number;col:number;};}interfaceRange {end: {row:number;col:number;};}Exclusive workbook column index after the last key.API reference →ChartSeries.values: ChartRangeinterfaceChartSeries {values:ChartRange;}interfaceChartSeries {values:ChartRange;}Numeric cells; text, booleans, errors and empty cells are null (a gap).API reference →ChartSeries.categories?: ChartRange | undefinedinterfaceChartSeries {categories?:ChartRange|undefined;}interfaceChartSeries {categories?:ChartRange|undefined;}function createGrid(host: HTMLElement, opts: GridOptions): GridfunctioncreateGrid(host:HTMLElement,opts:GridOptions,):GridfunctioncreateGrid(host:HTMLElement,opts:GridOptions,):GridCreates and mounts an imperative Grid in the supplied host element.Exampleimport { createGrid, initSheetwrite } from"@sheetwrite/core";awaitinitSheetwrite();consthost= document.createElement("div");host.style.height ="400px";document.body.append(host);constgrid=createGrid(host, {workbook: {activeSheet: "sales",sheets: [{ id: "sales", name: "Sales", rowCount: 2,columns: [{ key: "amount", header: "Amount", type: "number", width: 120 }] }],},data: { rowCount: 2, columns: { amount: [12, 18] } },});grid.scrollToCell({ sheet: "sales", row: 1, col: 0 });// Call when the host view is removed.grid.destroy();See alsoGrid *See alsoGridOptionsAPI reference →function initSheetwrite(source?: BufferSource | URL | string | Request | WebAssembly.Module, engine?: SheetwriteEngine): Promise<void>functioninitSheetwrite(source?:BufferSource|URL|string|Request|WebAssembly.Module,engine?:SheetwriteEngine,):Promise<void>functioninitSheetwrite(source?:|BufferSource|URL|string|Request|WebAssembly.Module,engine?:SheetwriteEngine,):Promise<void>Load one WASM engine before createGrid. The default is @sheetwrite/wasm. Pass the @sheetwrite/formulas module as the second argument to select the full engine.Exampleimport { initSheetwrite } from"@sheetwrite/core";import*as formulas from"@sheetwrite/formulas";awaitinitSheetwrite(undefined, formulas);See also/docs/start/choose-an-engine/See alsocreateGridAPI reference →interface WorkbookinterfaceWorkbookinterfaceWorkbookLive workbook schema containing ordered sheets and the active sheet ID.API reference →const host: HTMLElement | nullconsthost:HTMLElement|nullconsthost:HTMLElement|nullvar document: Documentvar document:Documentvar document:Documentwindow.document returns a reference to the document contained in the window. MDN ReferenceAPI reference →ParentNode.querySelector<HTMLElement>(selectors: string): HTMLElement | null (+4 overloads)ParentNode.querySelector<HTMLElement>(selectors: string): HTMLElement |null (+4 overloads)ParentNode.querySelector<HTMLElement>(selectors: string): HTMLElement |null (+4 overloads)Returns the first element that is a descendant of node that matches selectors. MDN Referenceinterface HTMLElementinterfaceHTMLElementinterfaceHTMLElementThe HTMLElement interface represents any HTML element. MDN Referencevar Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+2 overloads)var Error:ErrorConstructornew (message?:string, options?:ErrorOptions) =>Error (+2 overloads)var Error:ErrorConstructornew (message?:string, options?:ErrorOptions) =>Error (+2 overloads)const host: HTMLElementconsthost:HTMLElementconsthost:HTMLElementElementCSSInlineStyle.style: CSSStyleDeclarationinterfaceElementCSSInlineStyle {style:CSSStyleDeclaration;}interfaceElementCSSInlineStyle {style:CSSStyleDeclaration;}MDN ReferenceAPI reference →CSSStyleDeclaration.height: stringinterfaceCSSStyleDeclaration {height:string;}interfaceCSSStyleDeclaration {height:string;}MDN ReferenceAPI reference →const workbook: Workbookconstworkbook:Workbookconstworkbook:WorkbookLive workbook schema adopted by the store and updated by document operations.API reference →Workbook.activeSheet: stringinterfaceWorkbook {activeSheet:string;}interfaceWorkbook {activeSheet:string;}Active sheet ID and initial tab presented when the grid is created.API reference →Workbook.sheets: Sheet[]interfaceWorkbook {sheets:Sheet[];}interfaceWorkbook {sheets:Sheet[];}Sheets in display/tab order.API reference →Sheet.id: stringinterfaceSheet {id:string;}interfaceSheet {id:string;}Stable identifier, unique within the workbook and used by every cell address.API reference →Sheet.name: stringinterfaceSheet {name:string;}interfaceSheet {name:string;}User-facing sheet name shown in tabs and workbook exports.API reference →Sheet.rowCount: numberinterfaceSheet {rowCount:number;}interfaceSheet {rowCount:number;}Row count for both in-memory and datasource-backed sheets.API reference →Sheet.columns: Column[]interfaceSheet {columns:Column[];}interfaceSheet {columns:Column[];}Ordered schema; array positions are the zero-based column coordinates.API reference →Column.key: stringinterfaceColumn {key:string;}interfaceColumn {key:string;}Non-empty key, unique within the sheet, used to map input and datasource values.API reference →Column.header: stringinterfaceColumn {header:string;}interfaceColumn {header:string;}Schema label used by table exports and data-grid presentation headers.API reference →Column.width: numberinterfaceColumn {width:number;}interfaceColumn {width:number;}Unzoomed column width in CSS pixels.API reference →Column.type: CellFormatinterfaceColumn {type:CellFormat;}interfaceColumn {type:CellFormat;}Controls cell input parsing and default value formatting for this column.API reference →GridOptions.workbook: WorkbookinterfaceGridOptions {workbook:Workbook;}interfaceGridOptions {workbook:Workbook;}Live workbook schema adopted by the store and updated by document operations.API reference →GridOptions.data?: ColumnarData | undefinedinterfaceGridOptions {data?:ColumnarData|undefined;}interfaceGridOptions {data?:ColumnarData|undefined;}Eager column-major values loaded into workbook.activeSheet; use instead of datasource.API reference →ColumnarData.rowCount: numberinterfaceColumnarData {rowCount:number;}interfaceColumnarData {rowCount:number;}Row count for both in-memory and datasource-backed sheets.API reference →ColumnarData.columns: Record<string, ArrayLike<CellScalar | CellValue>>interfaceColumnarData {columns:Record<string, ArrayLike<CellScalar|CellValue>>;}interfaceColumnarData {columns:Record<string,ArrayLike<CellScalar|CellValue>>;}Exact column runs represented by every returned row.API reference →month: string[]let month:string[]let month:string[]revenue: (string | number)[]let revenue: (string|number)[]letrevenue: (string|number)[]const result: ApplyTransactionResultconstresult:ApplyTransactionResultconstresult:ApplyTransactionResultSearch state after the replacement (matches re-scanned against the new data).API reference →status: "applied" | "conflict" | "rejected" | "noop"let status:"applied"|"conflict"|"rejected"|"noop"let status:|"applied"|"conflict"|"rejected"|"noop"