Syncfusion AI Assistant

How can I help you?

Integrate Chart in Syncfusion React Grid

17 Feb 202624 minutes to read

Grid and Chart integration in Syncfusion® enables visualizing tabular data by linking the grid with a chart. Selected data can be rendered interactively as bar, line, or pie charts via the ContextMenu feature. This integration is suitable for dashboards, reporting tools, and other data-driven applications where tabular and visual representations improve analysis and decision making.

Steps for chart integration

Follow these steps to integrate charts into the grid:

Dependencies

Below is the list of minimum dependencies required to integrate chart functionality into the grid:

|-- dependencies
  |-- @syncfusion/ej2-grid-chart
    |-- @syncfusion/ej2-buttons
    |-- @syncfusion/ej2-dropdowns
    |-- @syncfusion/ej2-grids
    |-- @syncfusion/ej2-inputs
    |-- @syncfusion/ej2-navigations
    |-- @syncfusion/ej2-popups
    |-- @syncfusion/ej2-splitbuttons
    |-- @syncfusion/ej2-notifications
    |-- @syncfusion/ej2-calendars
    |-- @syncfusion/ej2-charts

Setup for local development

Choose one of the following options to set up a React application. The recommended approach is using create-react-app, which prepares a development environment and optimizes the application for production. Refer to the installation instructions.

npx create-react-app my-app
cd my-app
npm start

or

yarn create react-app my-app
cd my-app
yarn start

Run the following command to create a React application in a TypeScript environment:

npx create-react-app my-app --template typescript
cd my-app
npm start

Alternatively, create an application with npm init. For npm init, ensure npm is version 6 or higher.

npm init react-app my-app
cd my-app
npm start

Add Syncfusion React packages

Syncfusion® React component packages are available at npmjs.com. Install the corresponding npm packages to use Syncfusion® React components in a project.

Run the following commands to install the grid and grid-chart packages.

npm install @syncfusion/ej2-react-grids
npm install @syncfusion/ej2-grid-chart

Import the Syncfusion CSS styles

Syncfusion® React controls include built-in themes provided in the installed packages. Apply one of the built-in themes to match the application’s visual style.

Import the required CSS files from the node_modules directory. For example, to use the “Material 3” theme, add the following imports to the src/App.css file.

@import '../node_modules/@syncfusion/ej2-base/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-buttons/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-calendars/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-dropdowns/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-inputs/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-navigations/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-popups/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-notifications/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-splitbuttons/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-react-grids/styles/material3.css';
@import '../node_modules/@syncfusion/ej2-grid-chart/styles/material3.css';

Chart integration via context menu in grid

This section explains how the grid can render charts dynamically based on interactions within the Syncfusion® React grid using the context menu. Right-clicking on selected rows presents chart types such as bar, pie, or line for immediate visualization. This enhances interactivity and provides a quick analytical view.

For example, in a sales dashboard, selecting records for specific products can display a comparative bar or pie chart that shows online sales versus retail sales or revenue trends across months.

Steps to integrate a chart into the grid via the context menu:

Step 1. Inject required modules:

Import the required modules from the Grid, GridChart, and Chart packages, then inject the ContextMenu module into the grid:

import { ColumnDirective, ColumnsDirective, ContextMenuClickEventArgs, ContextMenu, GridComponent, Inject } from '@syncfusion/ej2-react-grids';
import { GridChart } from '@syncfusion/ej2-grid-chart';

function App() {
  return (
    <div>
      <GridComponent>
        <ColumnsDirective>
        </ColumnsDirective>
        <Inject services={[ContextMenu]} />
      </GridComponent>
    </div>
  );
}

export default App;
import { ColumnDirective, ColumnsDirective, ContextMenuClickEventArgs, ContextMenu, GridComponent, Inject, SelectionSettingsModel} from '@syncfusion/ej2-react-grids';
import { GridChart, CategorySeries, ChartChanges} from '@syncfusion/ej2-grid-chart';
import { ChartModel } from '@syncfusion/ej2-charts';

function App() {
  return (
    <div>
      <GridComponent>
        <ColumnsDirective>
        </ColumnsDirective>
        <Inject services={[ContextMenu]} />
      </GridComponent>
    </div>
  );
}

export default App;

Step 2: Define chart options to grid context menu:

Add chart visualization options as context menu items within the grid configuration using the contextMenuItems property. These items allow right-clicking on selected rows to choose a chart type for visualization.

contextMenuItems={[
  'Bar', 'StackingBar', 'StackingBar100',
  'Pie', 'Column', 'StackingColumn', 'StackingColumn100',
  'Line', 'StackingLine', 'StackingLine100',
  'Area', 'StackingArea', 'StackingArea100', 'Scatter'
]}

Step 3: Initialize GridChart instance on grid creation:

Inside the grid’s created event, instantiate a GridChart object. This instance is used to render charts dynamically based on the selected grid data.

function created() {
  gridChart = new GridChart({
    enableRtl: grid.enableRtl,
    locale: grid.locale,
  });
}
function created() {
  gridChart = new GridChart({
    enableRtl: (grid as GridComponent).enableRtl,
    locale: (grid as GridComponent).locale,
  });
}

This ensures the chart instance is ready when the grid initializes, allowing seamless interaction through the context menu.

Step 4: Handle context menu click to render chart:

Use the contextMenuClick event to determine the selected chart type and render it with the gridChart.render method.

The contextMenuClick event provides the following arguments:

  • args.chartType: Selected chart type.
  • args.gridInstance: Current grid instance.
  • args.records: Selected data records to visualize.

The gridChart.render method accepts three arguments:

  • chartArgs: Contains the grid instance, chart type, and the selected records.

  • chartModel: Specifies chart configuration, including axes, labels, legends, tooltips, and other appearance or behavior settings. See Syncfusion’s Chart Model for details.

  • categorySeries: Specifies data fields for categories and series.

    • Category fields define the grouping axis.
    • Series fields define the values plotted on the chart.
function contextMenuClick(args) 
{
  if (args.chartType) 
  {
    // Prepare the chart arguments including the grid instance, chart type, and records to plot.
    const chartArgs = {
      gridInstance: args.gridInstance,
      chartType: args.chartType,
      records: args.records
    };

    // Set up the Chart model configurations.
    const chartModel = {
      primaryXAxis: {
        valueType: 'Category',
        labelRotation: 315
      }
    };

    // Combine both Chart models into a single model for rendering.
    const model = {
      chart: chartModel,
      accumulationChart: {}
    };

    // Determine fields for category and series data in the Chart.
    const categorySeries = {
      category: ['Product', 'Month'],
      series: ['Online', 'Retail']
    };

    // Render the chart using the configured arguments and models.
    // The render function uses the defined chartArgs, model, and categorySeries to display the chart.
    gridChart.render(chartArgs, model, categorySeries);
  }
}
function contextMenuClick(args: ContextMenuClickEventArgs) 
{
  if (args.chartType) 
  {
    const chartArgs = {
      gridInstance: (args.gridInstance as GridComponent),
      chartType: args.chartType,
      records: (args.records as SalesRecord[])
    };

    // Set up the chart model configurations.
    const chartModel: ChartModel = {
      primaryXAxis: {
        valueType: 'Category',
        labelRotation: 315
      }
    };

    // Combine both chart models into a single model for rendering.
    const model: ChartChanges = {
      chart: chartModel,
      accumulationChart: {}
    };

    // Determine fields for category and series data in the chart.
    const categorySeries: CategorySeries = {
      category: ['Product', 'Month'],
      series: ['Online', 'Retail']
    };

    // Render the chart using the configured arguments and models.
    // The render function uses the defined chartArgs, model, and categorySeries to display the chart.
    (gridChart as GridChart).render(chartArgs, model, categorySeries);
  }
}

The following example demonstrates integrating charts into the grid context menu by using the contextMenuClick event and the gridChart.render method:

import { ColumnDirective, ColumnsDirective, ContextMenu, GridComponent, Inject } from '@syncfusion/ej2-react-grids';
import { GridChart } from '@syncfusion/ej2-grid-chart';
import * as React from 'react';
import { salesDatas } from './datasource';

function App() {
  let grid;
  let gridChart;
  const selectionSettings = { type: 'Multiple' };

  function created() {
    gridChart = new GridChart({
      enableRtl: grid.enableRtl,
      locale: grid.locale,
    });
  }

  function contextMenuClick(args) {
    if (args.chartType) {
      const chartArgs = {
        gridInstance: args.gridInstance,
        chartType: args.chartType,
        records: args.records
      };
      const chartModel = {
        primaryXAxis: {
          valueType: 'Category',
          labelRotation: 315
        }
      };
      const model = {
        chart: chartModel,
        accumulationChart: {}
      };
      const categorySeries = {
        category: ['Product', 'Month'],
        series: ['Online', 'Retail']
      };
      gridChart.render(chartArgs, model, categorySeries);
    }
  }

  return (
    <div>
      <GridComponent
        dataSource={salesDatas}
        height={340}
        ref={g => (grid = g)}
        created={created}
        contextMenuClick={contextMenuClick}
        allowSelection={true}
        contextMenuItems={[
          'Bar', 'StackingBar', 'StackingBar100',
          'Pie', 'Column', 'StackingColumn', 'StackingColumn100',
          'Line', 'StackingLine', 'StackingLine100',
          'Area', 'StackingArea', 'StackingArea100', 'Scatter'
        ]}
        selectionSettings={selectionSettings}
      >
        <ColumnsDirective>
          <ColumnDirective type="checkbox" width="50" />
          <ColumnDirective field="Product" headerText="Product" width="90" />
          <ColumnDirective field="Month" headerText="Month" width="180" />
          <ColumnDirective field="Online" headerText="Online" width="120" textAlign="Right" />
          <ColumnDirective field="Retail" headerText="Retail" width="110" textAlign="Right" />
          <ColumnDirective field="Total" headerText="Total" width="110" textAlign="Right" />
        </ColumnsDirective>
        <Inject services={[ContextMenu]} />
      </GridComponent>
    </div>
  );
}

export default App;
import { ColumnDirective, ColumnsDirective, ContextMenuClickEventArgs, ContextMenu, GridComponent, Inject , SelectionSettingsModel } from '@syncfusion/ej2-react-grids';
import { GridChart, CategorySeries, ChartChanges} from '@syncfusion/ej2-grid-chart';
import { ChartModel } from '@syncfusion/ej2-charts';
import * as React from 'react';
import { salesDatas } from './datasource';

interface SalesRecord {
  Product: string;
  Month: string;
  Online: number;
  Retail: number;
  Total: number;
}

function App() {
  let grid: GridComponent | null;
  let gridChart: GridChart;
  const selectionSettings: SelectionSettingsModel = { type: 'Multiple' };

  function created() {
    gridChart = new GridChart({
      enableRtl: (grid as GridComponent).enableRtl,
      locale: (grid as GridComponent).locale,
    });
  }

  function contextMenuClick(args: ContextMenuClickEventArgs) {
    if (args.chartType) {
      const chartArgs = {
        gridInstance: (args.gridInstance as GridComponent),
        chartType: args.chartType,
        records: (args.records as SalesRecord[])
      };
      const chartModel: ChartModel = {
        primaryXAxis: {
          valueType: 'Category',
          labelRotation: 315
        }
      };
      const model: ChartChanges = {
        chart: chartModel,
        accumulationChart: {}
      };
      const categorySeries: CategorySeries = {
        category: ['Product', 'Month'],
        series: ['Online', 'Retail']
      };
      (gridChart as GridChart).render(chartArgs, model, categorySeries);
    }
  }

 return (
  <div>
    <GridComponent
      dataSource={salesDatas}
      height={340}
      ref={g => (grid = g)}
      created={created}
      contextMenuClick={contextMenuClick}
      allowSelection={true}
      contextMenuItems={[
        'Bar', 'StackingBar', 'StackingBar100',
        'Pie', 'Column', 'StackingColumn', 'StackingColumn100',
        'Line', 'StackingLine', 'StackingLine100',
        'Area', 'StackingArea', 'StackingArea100', 'Scatter'
      ]}
      selectionSettings={selectionSettings}
    >
      <ColumnsDirective>
        <ColumnDirective type="checkbox" width="50" />
        <ColumnDirective field="Product" headerText="Product" width="90" />
        <ColumnDirective field="Month" headerText="Month" width="180" />
        <ColumnDirective field="Online" headerText="Online" width="120" textAlign="Right" />
        <ColumnDirective field="Retail" headerText="Retail" width="110" textAlign="Right" />
        <ColumnDirective field="Total" headerText="Total" width="110" textAlign="Right" />
      </ColumnsDirective>
      <Inject services={[ContextMenu]} />
    </GridComponent>
  </div>
);

}

export default App;
export const salesDatas = [
  { Product: "Laptop", Month: "January", Online: 1500, Retail: 2000, Total: 3500 },
  { Product: "Mobile", Month: "February", Online: 1600, Retail: 2500, Total: 4100 },
  { Product: "Tablet", Month: "March", Online: 1800, Retail: 2200, Total: 4000 },
  { Product: "Smartwatch", Month: "April", Online: 2000, Retail: 2100, Total: 4100 },
  { Product: "Camera", Month: "May", Online: 2200, Retail: 2300, Total: 4500 },
  { Product: "Headphones", Month: "June", Online: 1700, Retail: 1800, Total: 3500 },
  { Product: "Smart Speaker", Month: "July", Online: 1900, Retail: 2000, Total: 3900 },
  { Product: "Printer", Month: "August", Online: 2100, Retail: 1900, Total: 4000 },
  { Product: "Monitor", Month: "September", Online: 2000, Retail: 1900, Total: 3900 },
  { Product: "Keyboard", Month: "October", Online: 1600, Retail: 1700, Total: 3300 },
  { Product: "Mouse", Month: "November", Online: 1700, Retail: 1600, Total: 3300 },
  { Product: "Router", Month: "December", Online: 1800, Retail: 2000, Total: 3800 }
];
export const salesDatas: Object[] = [
  { Product: "Laptop", Month: "January", Online: 1500, Retail: 2000, Total: 3500 },
  { Product: "Mobile", Month: "February", Online: 1600, Retail: 2500, Total: 4100 },
  { Product: "Tablet", Month: "March", Online: 1800, Retail: 2200, Total: 4000 },
  { Product: "Smartwatch", Month: "April", Online: 2000, Retail: 2100, Total: 4100 },
  { Product: "Camera", Month: "May", Online: 2200, Retail: 2300, Total: 4500 },
  { Product: "Headphones", Month: "June", Online: 1700, Retail: 1800, Total: 3500 },
  { Product: "Smart Speaker", Month: "July", Online: 1900, Retail: 2000, Total: 3900 },
  { Product: "Printer", Month: "August", Online: 2100, Retail: 1900, Total: 4000 },
  { Product: "Monitor", Month: "September", Online: 2000, Retail: 1900, Total: 3900 },
  { Product: "Keyboard", Month: "October", Online: 1600, Retail: 1700, Total: 3300 },
  { Product: "Mouse", Month: "November", Online: 1700, Retail: 1600, Total: 3300 },
  { Product: "Router", Month: "December", Online: 1800, Retail: 2000, Total: 3800 }
];

Enable export functionality in GridChart

GridChart export functionality enables saving or sharing charts in multiple formats. This is useful for preserving visualizations or including charts in reports and presentations.

Enable export by setting the allowExport property to true when creating the GridChart instance. Once enabled, an export option appears in the chart popup toolbar, allowing export to formats such as PDF, CSV, Print, JPEG, XLSX, SVG, and PNG.

gridChart = new GridChart({
  allowExport: true
});

When enabled, the property panel appears alongside the chart popup and offers three main configuration sections:

  • Chart Types: Choose from a variety of chart types, including Column, Line, Pie, and others.

  • Chart Data: Configure the category axis and series fields for data visualization.

  • Formatting Options: Adjust styling properties such as chart style, title style, legend appearance, series settings, and axes formatting.

    • Chart Style:

      • Margin: Adjust the margins around the chart (top, bottom, left, right) for better layout spacing.
      • Color: Set distinct colors for different chart elements to improve visual clarity.
    • Title Style

      • Legend: Toggle the visibility of the legend and customize its font, size, color, and position.
      • Series: Enable/disable tooltips and customize Series color and data labels based on categories such as online, retail, or revenue.
    • Axes: Select axes as either category or value type, and customize:

      • Reverse Order to change the data sequence.
      • Title: Adjust text, font, size, color, and rotation.
      • Label: Modify text, font, size, color, and rotation for better label presentation.

Customize the chart model:

Accumulation Charts (for example, pie charts) can be customized using the accumulationChart property of the model object. This property configures titles, legends, data labels, and visual styles for accumulation-type visualizations.

Additionally, Accumulation chart events can be used to apply extra customizations during rendering.

function contextMenuClick(args) 
{
  if (args.chartType) {
    const chartArgs = {
       gridInstance: args.gridInstance,
      chartType: args.chartType,
      records: args.records
    };
    const chartModel = {
      primaryXAxis: {
        valueType: 'Category',
        labelRotation: 315
      },
      margin: {
        top: 20,
        bottom: 20,
        right: 20,
        left: 20
      },
      tooltip: {
        enable: true,
        textStyle: {
          size: '16px',
          fontFamily: 'Arial, Helvetica, sans-serif'
        }
      },
      title: 'Sales Data',
      titleStyle: {
        size: '24px',
        fontFamily: 'Arial, Helvetica, sans-serif',
        fontWeight: 'Bold'
      },
      subTitle: 'Sales data for various products over the months',
      load: (args) => {
        if (args.chart.titleStyle) {
          args.chart.titleStyle.color = '#1976d2';
        }
      }
    };
    const accumulationChartModel = {
      title :'Sales Distribution'
    };
    const model = {
      chart: chartModel,
      accumulationChart: accumulationChartModel
    };
  }
}
function contextMenuClick(args: ContextMenuClickEventArgs) {
  if (args.chartType) {
    const chartModel: ChartModel = {
      primaryXAxis: {
        valueType: 'Category',
        labelRotation: 315
      },
      margin: {
        top: 20,
        bottom: 20,
        right: 20,
        left: 20
      },
      tooltip: {
        enable: true,
        textStyle: {
          size: '16px',
          fontFamily: 'Arial, Helvetica, sans-serif'
        }
      },
      title: 'Sales Data',
      titleStyle: {
        size: '24px',
        fontFamily: 'Arial, Helvetica, sans-serif',
        fontWeight: 'Bold'
      },
      subTitle: 'Sales data for various products over the months',
      load: (args: ILoadedEventArgs) => {
        if (args.chart.titleStyle) {
          args.chart.titleStyle.color = '#1976d2';
        }
      }
    };
    const accumulationChartModel: AccumulationChartModel = {
      title :'Sales Distribution'
    }

    // Combine both chart models into a single object.
    const model: ChartChanges = {
      chart: chartModel,
      accumulationChart: accumulationChartModel
    };
  }
}

Chart appearance can also be updated programmatically using the updateChartSettings event provided by the GridChart integration. This event triggers when chart properties are modified through the chart popup’s property panel. The event enables applying custom themes, adjusting axis settings, or modifying series styles.

The following code snippet demonstrates dynamically customizing chart margins and restricting their values to a minimum of “20” using the updateChartSettings event:

function created() {
  gridChart = new GridChart({
    enablePropertyPanel: true,
    allowExport: true,
    enableRtl: grid.enableRtl,
    locale: grid.locale,
    updateChartSettings: updateChartSettings
  });
}

function updateChartSettings(args) 
{
  const chart = args.changes.chart;
  if (!chart) return;
  const chartMargin = chart.margin;

  // Restrict margin values to minimum 20.
  if (chartMargin && !isNullOrUndefined(chartMargin)) {
    if (chartMargin.top < 20) chartMargin.top = 20;
    if (chartMargin.bottom < 20) chartMargin.bottom = 20;
    if (chartMargin.left < 20) chartMargin.left = 20;
    if (chartMargin.right < 20) chartMargin.right = 20;
  }
}
function created() {
  gridChart = new GridChart({
    enablePropertyPanel: true,
    allowExport: true,
    enableRtl: (grid as GridComponent).enableRtl,
    locale: (grid as GridComponent).locale,
    updateChartSettings: updateChartSettings
  });
}

function updateChartSettings(args: UpdateChartArgs) 
{
  const chart = args.changes.chart;
  if (!chart) return;

  // Restrict margin values to minimum 20.
  const chartMargin = chart.margin;
  if (chartMargin && !isNullOrUndefined(chartMargin)) {
    if (chartMargin.top < 20) chartMargin.top = 20;
    if (chartMargin.bottom < 20) chartMargin.bottom = 20;
    if (chartMargin.left < 20) chartMargin.left = 20;
    if (chartMargin.right < 20) chartMargin.right = 20;
  }
}

The following example demonstrates enabling the property panel by setting enablePropertyPanel to true, customizing the chart using the chartModel within contextMenuClick event, and dynamically controlling or customizing the behavior of the updateChartSettings event.

import { ColumnDirective, ColumnsDirective, ContextMenu, GridComponent, Inject } from '@syncfusion/ej2-react-grids';
import { GridChart} from '@syncfusion/ej2-grid-chart';
import * as React from 'react';
import { salesDatas } from './datasource';
import { isNullOrUndefined } from '@syncfusion/ej2-base';


function App() {
  let grid;
  let gridChart;
  const selectionSettings = { type: 'Multiple' };

  function created() {
    gridChart = new GridChart({
      enablePropertyPanel: true,
      allowExport: true,
      enableRtl: grid.enableRtl,
      locale: grid.locale,
      updateChartSettings: updateChartSettings
    });
  }

  function contextMenuClick(args) {
    if (args.chartType) {
      const chartArgs = {
        gridInstance: args.gridInstance,
        chartType: args.chartType,
        records: args.records
      };
      const chartModel = {
        primaryXAxis: {
          valueType: 'Category',
          labelRotation: 315
        },
        margin: {
          top: 20,
          bottom: 20,
          right: 20,
          left: 20
        },
        tooltip: {
          enable: true,
          textStyle: {
            size: '16px',
            fontFamily: 'Arial, Helvetica, sans-serif'
          }
        },
        title: 'Sales Data',
        titleStyle: {
          size: '24px',
          fontFamily: 'Arial, Helvetica, sans-serif',
          fontWeight: 'Bold'
        },
        subTitle: 'Sales data for various products over the months',
        load: (args) => {
          if (args.chart.titleStyle) {
            args.chart.titleStyle.color = '#1976d2';
          }
        }
      };
      const accumulationChartModel = {
        title :'Sales Distribution'
      };
      const model = {
        chart: chartModel,
        accumulationChart: accumulationChartModel
      };
      const categorySeries = {
        category: ['Product', 'Month'],
        series: ['Online', 'Retail']
      };
      gridChart.render(chartArgs, model, categorySeries);
    }
  }

  function updateChartSettings(args) {
    const chart = args.changes.chart;
    if (!chart) return;
    const chartMargin = chart.margin;
    if (chartMargin && !isNullOrUndefined(chartMargin)) {
      if (chartMargin.top < 20) chartMargin.top = 20;
      if (chartMargin.bottom < 20) chartMargin.bottom = 20;
      if (chartMargin.left < 20) chartMargin.left = 20;
      if (chartMargin.right < 20) chartMargin.right = 20;
    }
  }

  return (
    <div>
      <GridComponent dataSource={salesDatas} height={340} ref={g => grid = g}  created={created}
        contextMenuClick={contextMenuClick}
        allowSelection={true}
        contextMenuItems={[
          'Bar', 'StackingBar', 'StackingBar100',
          'Pie', 'Column', 'StackingColumn', 'StackingColumn100',
          'Line', 'StackingLine', 'StackingLine100',
          'Area', 'StackingArea', 'StackingArea100', 'Scatter'
        ]}
        selectionSettings={selectionSettings} >
        <ColumnsDirective>
          <ColumnDirective type='checkbox' width='50' />
          <ColumnDirective field='Product' headerText='Product' width='90' />
          <ColumnDirective field='Month' headerText='Month' width='180' />
          <ColumnDirective field='Online' headerText='Online' width='120' textAlign='Right' />
          <ColumnDirective field='Retail' headerText='Retail' width='110' textAlign='Right' />
          <ColumnDirective field='Total' headerText='Total' width='110' textAlign='Right' />
        </ColumnsDirective>
        <Inject services={[ContextMenu]} />
      </GridComponent>
    </div>
  );
}

export default App;
import { ColumnDirective, ColumnsDirective, ContextMenuClickEventArgs, ContextMenu,  GridComponent, Inject, SelectionSettingsModel} from '@syncfusion/ej2-react-grids';
import { GridChart, UpdateChartArgs, CategorySeries, ChartChanges } from '@syncfusion/ej2-grid-chart';
import { ChartModel, AccumulationChartModel, ILoadedEventArgs } from '@syncfusion/ej2-charts';
import * as React from 'react';
import { salesDatas } from './datasource';
import { isNullOrUndefined } from '@syncfusion/ej2-base';

interface SalesRecord {
  Product: string;
  Month: string;
  Online: number;
  Retail: number;
  Total: number;
}

function App() {
  let grid: GridComponent | null;
  let gridChart: GridChart;
  const selectionSettings: SelectionSettingsModel = { type: 'Multiple' };

  function created() {
    gridChart = new GridChart({
      enablePropertyPanel: true,
      allowExport: true,
      enableRtl: (grid as GridComponent).enableRtl,
      locale: (grid as GridComponent).locale,
      updateChartSettings: updateChartSettings
    });
  }

  function contextMenuClick(args: ContextMenuClickEventArgs) {
    if (args.chartType) {
      const chartArgs = {
        gridInstance: (args.gridInstance as GridComponent),
        chartType: args.chartType,
        records: (args.records as SalesRecord[])
      };
      const chartModel: ChartModel = {
        primaryXAxis: {
          valueType: 'Category',
          labelRotation: 315
        },
        margin: {
          top: 20,
          bottom: 20,
          right: 20,
          left: 20
        },
        tooltip: {
          enable: true,
          textStyle: {
            size: '16px',
            fontFamily: 'Arial, Helvetica, sans-serif'
          }
        },
        title: 'Sales Data',
        titleStyle: {
          size: '24px',
          fontFamily: 'Arial, Helvetica, sans-serif',
          fontWeight: 'Bold'
        },
        subTitle: 'Sales data for various products over the months',
        load: (args: ILoadedEventArgs) => {
          if (args.chart.titleStyle) {
            args.chart.titleStyle.color = '#1976d2';
          }
        }
      };
      const accumulationChartModel: AccumulationChartModel = {
        title :'Sales Distribution'
      }
      const model: ChartChanges = {
        chart: chartModel,
        accumulationChart: accumulationChartModel
      };
      const categorySeries: CategorySeries = {
        category: ['Product', 'Month'],
        series: ['Online', 'Retail']
      };
      (gridChart as GridChart).render(chartArgs, model, categorySeries);
    }
  }

  function updateChartSettings(args: UpdateChartArgs) {
    const chart = args.changes.chart;
    if (!chart) return;
    const chartMargin = chart.margin;
    if (chartMargin && !isNullOrUndefined(chartMargin)) {
      if (chartMargin.top < 20) chartMargin.top = 20;
      if (chartMargin.bottom < 20) chartMargin.bottom = 20;
      if (chartMargin.left < 20) chartMargin.left = 20;
      if (chartMargin.right < 20) chartMargin.right = 20;
    }
  }

  return (
    <div>
      <GridComponent
        dataSource={salesDatas}
        height={340}
        ref={g => (grid = g)}
        created={created}
        contextMenuClick={contextMenuClick}
        allowSelection={true}
        contextMenuItems={[
          'Bar', 'StackingBar', 'StackingBar100',
          'Pie', 'Column', 'StackingColumn', 'StackingColumn100',
          'Line', 'StackingLine', 'StackingLine100',
          'Area', 'StackingArea', 'StackingArea100', 'Scatter'
        ]}
        selectionSettings={selectionSettings}
      >
        <ColumnsDirective>
          <ColumnDirective type="checkbox" width="50" />
          <ColumnDirective field="Product" headerText="Product" width="90" />
          <ColumnDirective field="Month" headerText="Month" width="180" />
          <ColumnDirective field="Online" headerText="Online" width="120" textAlign="Right" />
          <ColumnDirective field="Retail" headerText="Retail" width="110" textAlign="Right" />
          <ColumnDirective field="Total" headerText="Total" width="110" textAlign="Right" />
        </ColumnsDirective>
        <Inject services={[ContextMenu]} />
      </GridComponent>
    </div>
  );
}

export default App;
export const salesDatas = [
  { Product: "Laptop", Month: "January", Online: 1500, Retail: 2000, Total: 3500 },
  { Product: "Mobile", Month: "February", Online: 1600, Retail: 2500, Total: 4100 },
  { Product: "Tablet", Month: "March", Online: 1800, Retail: 2200, Total: 4000 },
  { Product: "Smartwatch", Month: "April", Online: 2000, Retail: 2100, Total: 4100 },
  { Product: "Camera", Month: "May", Online: 2200, Retail: 2300, Total: 4500 },
  { Product: "Headphones", Month: "June", Online: 1700, Retail: 1800, Total: 3500 },
  { Product: "Smart Speaker", Month: "July", Online: 1900, Retail: 2000, Total: 3900 },
  { Product: "Printer", Month: "August", Online: 2100, Retail: 1900, Total: 4000 },
  { Product: "Monitor", Month: "September", Online: 2000, Retail: 1900, Total: 3900 },
  { Product: "Keyboard", Month: "October", Online: 1600, Retail: 1700, Total: 3300 },
  { Product: "Mouse", Month: "November", Online: 1700, Retail: 1600, Total: 3300 },
  { Product: "Router", Month: "December", Online: 1800, Retail: 2000, Total: 3800 }
];
export const salesDatas: Object[] = [
  { Product: "Laptop", Month: "January", Online: 1500, Retail: 2000, Total: 3500 },
  { Product: "Mobile", Month: "February", Online: 1600, Retail: 2500, Total: 4100 },
  { Product: "Tablet", Month: "March", Online: 1800, Retail: 2200, Total: 4000 },
  { Product: "Smartwatch", Month: "April", Online: 2000, Retail: 2100, Total: 4100 },
  { Product: "Camera", Month: "May", Online: 2200, Retail: 2300, Total: 4500 },
  { Product: "Headphones", Month: "June", Online: 1700, Retail: 1800, Total: 3500 },
  { Product: "Smart Speaker", Month: "July", Online: 1900, Retail: 2000, Total: 3900 },
  { Product: "Printer", Month: "August", Online: 2100, Retail: 1900, Total: 4000 },
  { Product: "Monitor", Month: "September", Online: 2000, Retail: 1900, Total: 3900 },
  { Product: "Keyboard", Month: "October", Online: 1600, Retail: 1700, Total: 3300 },
  { Product: "Mouse", Month: "November", Online: 1700, Retail: 1600, Total: 3300 },
  { Product: "Router", Month: "December", Online: 1800, Retail: 2000, Total: 3800 }
];