---
product: "AG Grid"
title: "Application Created Charts"
description: "This section introduces Integrated Charts that are created programmatically within an application."
enterprise: true
framework: angular
version: "36.2.0"
related:
    - title: "Overview"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts/"
    - title: "Install Integrated Charts"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-installation/"
    - title: "User Created Charts"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-user-created/"
    - title: "Chart Types"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-chart-types/"
    - title: "Chart Menu"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-menu/"
    - title: "Chart Tool Panels"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-chart-tool-panels/"
    - title: "Chart Container"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-container/"
    - title: "Customisation"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-customisation/"
    - title: "Chart Events"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-events/"
    - title: "Time Series"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-time-series/"
    - title: "Save / Restore Charts"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-api-save-restore-charts/"
    - title: "Chart Image Export"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-api-downloading-image/"
llms: "https://www.ag-grid.com/archive/36.2.0/llms.txt"
---

# Application Created Charts

This section introduces Integrated Charts that are created programmatically within an application.

#### Application Created Charts

```ts
import type { OnDestroy } from "@angular/core";
import { Component } from "@angular/core";
import { AgChartsEnterpriseModule } from "ag-charts-enterprise";

import { AgGridAngular } from "ag-grid-angular";
import type {
  ChartRef,
  ChartType,
  ColDef,
  FirstDataRenderedEvent,
  GetRowIdParams,
  GridApi,
  GridReadyEvent,
  ValueFormatterParams,
} from "ag-grid-community";
import {
  CellStyleModule,
  ClientSideRowModelApiModule,
  ClientSideRowModelModule,
  ColumnApiModule,
  HighlightChangesModule,
  ModuleRegistry,
  NumberEditorModule,
  NumberFilterModule,
  TextEditorModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import { IntegratedChartsModule, RowGroupingModule } from "ag-grid-enterprise";

import "./styles.css";

if (process.env.NODE_ENV !== "production") {
  // Enable extended validations only for development
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ColumnApiModule,
  ClientSideRowModelApiModule,
  TextEditorModule,
  TextFilterModule,
  NumberEditorModule,
  CellStyleModule,
  ClientSideRowModelModule,
  IntegratedChartsModule.with(AgChartsEnterpriseModule),
  RowGroupingModule,
  HighlightChangesModule,
  NumberFilterModule,
]);

declare let __basePath: string;

function numberCellFormatter(params: ValueFormatterParams) {
  return Math.floor(params.value)
    .toString()
    .replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
}

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div id="myApp" class="wrapper">
    <div style="padding-bottom: 4px">
      <span>
        <button (click)="onStopMessages()">&#9632; Stop</button>
        <button (click)="onStartLoad()">&#9658; Start</button>
      </span>
      <span style="margin-left: 30px">
        <button (click)="updateChart('stackedColumn')">
          Stacked Column Chart
        </button>
        <button (click)="updateChart('groupedColumn')">
          Grouped Column Chart
        </button>
        <button (click)="updateChart('line')">Line Chart</button>
      </span>
    </div>
    <ag-grid-angular
      class="my-grid"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [columnTypes]="columnTypes"
      [enableCharts]="true"
      [suppressAggFuncInHeader]="true"
      [getRowId]="getRowId"
      [getChartToolbarItems]="getChartToolbarItems"
      (gridReady)="onGridReady($event)"
      (firstDataRendered)="onFirstDataRendered($event)"
    />
    <div id="myChart" class="my-chart"></div>
  </div>`,
})
export class AppComponent implements OnDestroy {
  private gridApi?: GridApi;
  private chartRef?: ChartRef;
  private worker?: Worker;

  columnDefs: ColDef[] = [
    { field: "product", chartDataType: "category", minWidth: 110 },
    { field: "book", chartDataType: "category", minWidth: 100 },
    { field: "current", type: "measure" },
    { field: "previous", type: "measure" },
    { headerName: "PL 1", field: "pl1", type: "measure" },
    { headerName: "PL 2", field: "pl2", type: "measure" },
    { headerName: "Gain-DX", field: "gainDx", type: "measure" },
    { headerName: "SX / PX", field: "sxPx", type: "measure" },
    { field: "trade", type: "measure" },
    { field: "submitterID", type: "measure" },
    { field: "submitterDealID", type: "measure" },
    { field: "portfolio" },
    { field: "dealType" },
    { headerName: "Bid", field: "bidFlag" },
  ];
  defaultColDef: ColDef = {
    editable: true,
    flex: 1,
    minWidth: 140,
    filter: true,
  };
  columnTypes: Record<string, ColDef> = {
    measure: {
      chartDataType: "series",
      cellClass: "number",
      valueFormatter: numberCellFormatter,
      cellRenderer: "agAnimateShowChangeCellRenderer",
    },
  };

  getRowId = (params: GetRowIdParams) => String(params.data.trade);
  getChartToolbarItems = () => [];

  onGridReady(params: GridReadyEvent) {
    this.gridApi = params.api;
    // Create the worker once the grid API exists so the first 'setRowData' message is never dropped.
    if (!this.worker) {
      this.worker = new Worker(`${__basePath || "."}/dataUpdateWorker.js`);
      this.worker.addEventListener("message", this.handleWorkerMessage);
      this.worker.postMessage("start");
    }
  }

  onFirstDataRendered(params: FirstDataRenderedEvent) {
    this.chartRef = params.api.createRangeChart({
      chartContainer: document.querySelector("#myChart") as HTMLElement,
      cellRange: {
        columns: [
          "product",
          "current",
          "previous",
          "pl1",
          "pl2",
          "gainDx",
          "sxPx",
        ],
      },
      suppressChartRanges: true,
      chartType: "groupedColumn",
      aggFunc: "sum",
      chartThemeOverrides: {
        common: {
          animation: {
            enabled: false,
          },
        },
      },
    });
  }

  updateChart(chartType: ChartType) {
    if (this.gridApi && this.chartRef) {
      this.gridApi.updateChart({
        type: "rangeChartUpdate",
        chartId: this.chartRef.chartId,
        chartType,
      });
    }
  }

  onStartLoad() {
    this.worker?.postMessage("start");
  }

  onStopMessages() {
    this.worker?.postMessage("stop");
  }

  // Arrow function so `this` stays bound when used as an event listener.
  private handleWorkerMessage = (e: MessageEvent) => {
    if (!this.gridApi) {
      return;
    }
    if (e.data.type === "setRowData") {
      this.gridApi.setGridOption("rowData", e.data.records);
    } else if (e.data.type === "updateData") {
      this.gridApi.applyTransactionAsync({ update: e.data.records });
    }
  };

  // Tear down the worker on destroy so no update interval survives navigation.
  ngOnDestroy() {
    if (this.worker) {
      this.worker.removeEventListener("message", this.handleWorkerMessage);
      this.worker.terminate();
      this.worker = undefined;
    }
    this.gridApi = undefined;
  }
}
```

[Live example: Application Created Charts](https://www.ag-grid.com/archive/36.2.0/examples/integrated-charts-application-created/application-created-charts/angular/)

The dummy financial application above shows some of the grid's integrated charting capabilities. Note the following:

- **Pre-Defined Chart**: A pre-defined chart is shown in a separate chart container below the grid.
- **Dynamic Charts**: Buttons positioned above the grid dynamically create different chart types.
- **High Performance**: 100 rows are randomly updated 10 times a second (1,000 updates per second). Try updating the example via Plunker with higher update frequencies and more data.

> **Note**
>
> Charts created through the Grid API do not require the `enableCharts` grid option. That option governs the user-initiated path only — whether the grid offers users the `chartRange` and `pivotChart` [Context Menu](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/context-menu/) items by default.

To learn how to create charts in your applications see the following sections for details:

- [Range Chart API](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-api-range-chart/) - create Range Charts using the Grid API
- [Pivot Chart API](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-api-pivot-chart/) - create Pivot Charts using the Grid API
- [Cross Filter Chart API](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/integrated-charts-api-cross-filter-chart/) - create cross-filter charts where element clicks auto-filter grid and charts
