---
product: "AG Grid"
title: "Application Created Charts"
description: "This section introduces Integrated Charts that are created programmatically within an application."
enterprise: true
framework: vue
version: "36.2.0"
related:
    - title: "Overview"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts/"
    - title: "Install Integrated Charts"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts-installation/"
    - title: "User Created Charts"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts-user-created/"
    - title: "Chart Types"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts-chart-types/"
    - title: "Chart Menu"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts-menu/"
    - title: "Chart Tool Panels"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts-chart-tool-panels/"
    - title: "Chart Container"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts-container/"
    - title: "Customisation"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts-customisation/"
    - title: "Chart Events"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts-events/"
    - title: "Time Series"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts-time-series/"
    - title: "Save / Restore Charts"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/integrated-charts-api-save-restore-charts/"
    - title: "Chart Image Export"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-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 { AgChartsEnterpriseModule } from "ag-charts-enterprise";
import { createApp, defineComponent, onUnmounted, ref } from "vue";

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 { AgGridVue } from "ag-grid-vue3";

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,");
}

const VueExample = defineComponent({
  template: `
    <div id="myApp" class="wrapper">
        <div style="padding-bottom: 4px">
            <span>
                <button v-on:click="onStopMessages()">&#9632; Stop</button>
                <button v-on:click="onStartLoad()">&#9658; Start</button>
            </span>
            <span style="margin-left: 30px">
                <button v-on:click="updateChart('stackedColumn')">Stacked Column Chart</button>
                <button v-on:click="updateChart('groupedColumn')">Grouped Column Chart</button>
                <button v-on:click="updateChart('line')">Line Chart</button>
            </span>
        </div>
        <ag-grid-vue
            class="my-grid"
            :columnDefs="columnDefs"
            :defaultColDef="defaultColDef"
            :columnTypes="columnTypes"
            :enableCharts="true"
            :suppressAggFuncInHeader="true"
            :getRowId="getRowId"
            :getChartToolbarItems="getChartToolbarItems"
            @grid-ready="onGridReady"
            @first-data-rendered="onFirstDataRendered"
        ></ag-grid-vue>
        <div id="myChart" class="my-chart"></div>
    </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup() {
    const columnDefs = ref<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" },
    ]);
    const defaultColDef = ref<ColDef>({
      editable: true,
      flex: 1,
      minWidth: 140,
      filter: true,
    });
    const columnTypes = ref<Record<string, ColDef>>({
      measure: {
        chartDataType: "series",
        cellClass: "number",
        valueFormatter: numberCellFormatter,
        cellRenderer: "agAnimateShowChangeCellRenderer",
      },
    });

    // Stored as non-reactive closure variables — a Worker inside a Vue reactive proxy makes postMessage throw.
    let gridApi: GridApi | undefined;
    let chartRef: ChartRef | undefined;
    let worker: Worker | undefined;

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

    const handleWorkerMessage = (e: MessageEvent) => {
      if (!gridApi) {
        return;
      }
      if (e.data.type === "setRowData") {
        gridApi.setGridOption("rowData", e.data.records);
      } else if (e.data.type === "updateData") {
        gridApi.applyTransactionAsync({ update: e.data.records });
      }
    };

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

    const onFirstDataRendered = (params: FirstDataRenderedEvent) => {
      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,
            },
          },
        },
      });
    };

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

    const onStartLoad = () => worker?.postMessage("start");
    const onStopMessages = () => worker?.postMessage("stop");

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

    return {
      columnDefs,
      defaultColDef,
      columnTypes,
      getRowId,
      getChartToolbarItems,
      onGridReady,
      onFirstDataRendered,
      updateChart,
      onStartLoad,
      onStopMessages,
    };
  },
});

createApp(VueExample).mount("#app");
```

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

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/vue-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/vue-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/vue-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/vue-data-grid/integrated-charts-api-cross-filter-chart/) - create cross-filter charts where element clicks auto-filter grid and charts
