# Charts and pictures on the sheet

Charts anchored over the cells the way Excel anchors one: each reads a range rather than a copy of the numbers, so typing into a cell redraws it. Insert > Chart charts the selected block and reads its first row and column as the labels, Insert > Picture puts an image on the sheet, and a double-click opens the Chart dialog for the type, the title, series in columns or rows and stacking. Drag an object to move it, its corner to resize, Delete to remove. It hangs from a cell, so inserting a row above moves it, and it rides in getState() and in the .xlsx as a real drawing part.

Requires `@svgrid/enterprise` (and `@svgrid/grid`). Category: Spreadsheet. Live demo: https://svgrid.com/demos/485-sheet-charts-objects/

Install: `npm i @svgrid/grid @svgrid/enterprise` (Svelte 5).

## About this example

Charts anchored over the cells of a Svelte 5 spreadsheet, the way Excel anchors one: each reads a range rather than a copy of the numbers, so typing into a cell redraws it. Insert > Chart charts the selected block and reads its first row and column as the labels; Insert > Picture puts an image on the sheet; a double-click opens the Chart dialog for the type, the title, series in columns or rows and stacking. Drag an object to move it, its corner to resize, Delete to remove; it hangs from a cell, so inserting a row above moves it. The charts are part of the document and ride through getState(). Enterprise, in @svgrid/enterprise.

A quarterly sales sheet with two charts anchored over it, the way Excel anchors one: each reads a RANGE rather than a copy of the numbers, so typing into a cell redraws it on the spot.

```text
Insert > Chart    charts the selected block. The first row and
                  column are read as the labels, each column is a
                  series, and the chart lands under the block.
Insert > Picture  puts an image on the sheet from a file.
Insert > Setup    (or a double-click on a chart) opens the Chart
                  dialog: type, title, series in columns or rows,
                  whether the first row and column are labels, and
                  stacking.
```

An object floats over the cells: drag it to move, its corner to resize, Delete to remove. It hangs from a cell and an offset inside it, so inserting a row above moves it and deleting that row takes it with it. Everything here is part of the document: `getState()` carries the charts with the cells, and `onChange` reports `objects`. They go into the .xlsx too, as Excel's own drawing part, a chart carrying the references its series read rather than a copy of the numbers.

Try: change a number in B2:E4 and watch both charts. Select A1:E4 and press Insert > Chart for a third. Double-click the line chart and make it an area chart. Insert a row above row 1 and watch the charts move with their cells. Save As and open the file in Excel: the charts are charts there too.

## Imports, features and API used

- Imports: `@svgrid/enterprise`

## Frequently asked questions

### Does the chart update when a cell changes?

Yes. A chart object holds the range it reads, not a copy of the values, so every edit inside that range redraws it, the same way an Excel chart bound to a table does.

### Where do the charts live?

In the document, per sheet: getState().sheets.Sales.objects. Each carries its anchor cell, an offset inside it, a size in pixels, the range it reads and how to read it. They move with an insert or delete and come back from a saved document.

### Do charts ride in the .xlsx?

Yes, both ways. A chart goes out as a chart part of its own, carrying the references its series read rather than a copy of the numbers, so Excel redraws it from the cells beside it; a picture goes out as bytes in xl/media, and a picture Excel cannot keep as it is, an SVG say, is drawn to a PNG when it is inserted so the file can carry it. Both are anchored by a drawing part, and a file opened here gives them back. The one exception is a picture whose source is a URL rather than a data URL, whose bytes are not in the document to write; Save As says so in the status bar.

## Related documentation

- [The spreadsheet shell](https://svgrid.com/docs/help/cells/spreadsheet-shell.md)
- [Charts, sparklines and pictures](https://svgrid.com/docs/help/sheet/charts-and-objects.md)

## Related articles

- [A Fill Handle (Drag to Fill) in SvGrid](https://svgrid.com/blog/fill-handle-drag-to-fill/) - Build a working spreadsheet-style fill handle on top of SvGrid's cell selection and editing - pointer tracking, range highlighting, series fill, and undo/redo integration all covered.
- [Pivot Tables in Svelte - Summarize Data Without a Spreadsheet](https://svgrid.com/blog/pivot-tables/) - Run a cross-tab pivot directly inside your Svelte app using @svgrid/enterprise createPivotModel - no Excel, no server-side aggregation, no stale exports.
- [Spreadsheet-Style Cell Range Selection in SvGrid](https://svgrid.com/blog/cell-range-selection/) - How to enable drag-to-select cell ranges, read live selection state, and build a status-bar footer that sums and averages the selected values.

## Source code (485-sheet-charts-objects.svelte)

```svelte
<script lang="ts">
  /**
   * 485. Charts and pictures on the sheet
   * -------------------------------------
   * A quarterly sales sheet with two charts anchored over it, the way
   * Excel anchors one: each reads a RANGE rather than a copy of the
   * numbers, so typing into a cell redraws it on the spot.
   *
   *   Insert > Chart    charts the selected block. The first row and
   *                     column are read as the labels, each column is a
   *                     series, and the chart lands under the block.
   *   Insert > Picture  puts an image on the sheet from a file.
   *   Insert > Setup    (or a double-click on a chart) opens the Chart
   *                     dialog: type, title, series in columns or rows,
   *                     whether the first row and column are labels, and
   *                     stacking.
   *
   * An object floats over the cells: drag it to move, its corner to
   * resize, Delete to remove. It hangs from a cell and an offset inside
   * it, so inserting a row above moves it and deleting that row takes it
   * with it. Everything here is part of the document: `getState()`
   * carries the charts with the cells, and `onChange` reports `objects`.
   * They go into the .xlsx too, as Excel's own drawing part, a chart
   * carrying the references its series read rather than a copy of the
   * numbers.
   *
   * Try: change a number in B2:E4 and watch both charts. Select A1:E4 and
   * press Insert > Chart for a third. Double-click the line chart and
   * make it an area chart. Insert a row above row 1 and watch the charts
   * move with their cells. Save As and open the file in Excel: the charts
   * are charts there too.
   */
  import { SvSheet, createWorkbook, createSheetDocument, objectId, type SheetObject } from '@svgrid/enterprise'

  const rows: string[][] = [
    ['Region', 'Q1', 'Q2', 'Q3', 'Q4', 'Year'],
    ['North', '48000', '52500', '61000', '68500', '=SUM(B2:E2)'],
    ['South', '39000', '41500', '44000', '52000', '=SUM(B3:E3)'],
    ['EMEA', '71000', '69500', '78000', '91000', '=SUM(B4:E4)'],
    ['Total', '=SUM(B2:B4)', '=SUM(C2:C4)', '=SUM(D2:D4)', '=SUM(E2:E4)', '=SUM(F2:F4)'],
  ]

  const wb = createWorkbook([{ name: 'Sales', cells: rows }])
  const doc = createSheetDocument({ workbook: wb })
  const sheet = doc.get('Sales')
  const at = { rowIdAt: (i: number) => `r${i}`, columnIdAt: (i: number) => String.fromCharCode(65 + i) }
  sheet.formats.set([[0, 0, 0, 5]], { bold: true, fill: '#e2e8f0', color: '#0f172a' }, at)
  sheet.formats.set([[4, 0, 4, 5]], { bold: true, border: { top: { width: 1 } } }, at)
  sheet.formats.set([[1, 1, 4, 5]], { numFmt: '$#,##0' }, at)
  sheet.widths.A = 110
  sheet.freeze = { rows: 1, cols: 1 }

  // Two charts over the same numbers, read two ways: the quarters by
  // region, and the regions by quarter. Both are part of the document.
  // Anchored from column B on: column A is frozen, and a frozen column
  // paints over whatever scrolls under it, as a frozen pane does in Excel.
  const charts: SheetObject[] = [
    {
      id: objectId(),
      kind: 'chart',
      anchor: { row: 6, col: 1, dx: 8, dy: 8, width: 400, height: 250 },
      range: [0, 0, 3, 4],
      type: 'bar',
      headers: true,
      series: 'columns',
      title: 'Quarters by region',
    },
    {
      id: objectId(),
      kind: 'chart',
      anchor: { row: 6, col: 5, dx: 32, dy: 8, width: 400, height: 250 },
      range: [0, 0, 3, 4],
      type: 'line',
      headers: true,
      series: 'rows',
      title: 'Regions by quarter',
    },
  ]
  sheet.objects = charts
</script>

<SvSheet document={doc} height="100%" rows={22} columns={8} />
```

[View this example on GitHub](https://github.com/sv-grid/sv-grid/blob/main/examples/src/demos/485-sheet-charts-objects.svelte)
