Performance tips for EJ2 Angular Gantt control

18 Oct 202524 minutes to read

This guide provides practical techniques to optimize the Angular Gantt component’s performance, particularly when working with large datasets. Learn how to implement best practices that maintain smooth user experience while handling substantial amounts of project data efficiently.

Improving loading performance with large datasets

A Gantt chart renders rows, columns, and taskbars in the DOM. For example, displaying 10 rows and 10 columns creates 100 elements in the grid area DOM and 10 elements in the chart area DOM. To ensure optimal loading performance, limit the number of rendered rows and columns when working with large datasets.

Optimizing performance with virtualization

Virtualization techniques significantly improve application efficiency when handling large datasets by rendering only visible content:

  1. Row virtualization: The virtual scrolling feature enables efficient handling of large data volumes by loading only visible rows within the Gantt viewport rather than rendering the entire dataset. This optimization occurs during vertical scroll actions. For detailed implementation, refer to the row virtualization documentation.

  2. Timeline virtualization: This feature optimizes timeline rendering by loading only visible timeline cells (typically three viewport widths). Additional timeline cells render on-demand during horizontal scrolling. For implementation details, see the timeline virtualization documentation.

  3. Load on demand: This feature renders large task collections with optimal performance. With virtualization enabled, only root-level records load initially. Child tasks load dynamically when expanding parent nodes or scrolling vertically, ensuring only necessary data renders based on the current viewport position.

Optimizing performance with AutoCalculateDateScheduling

By default, the Angular Gantt component automatically calculates start and end dates in the dataSource based on working time, holidays, weekends, and predecessors. For large datasets, these calculations can impact performance.

Set the autoCalculateDateScheduling property to false to improve initial load performance. This disables parent-child validation, data validation, and predecessor validation, allowing faster rendering.

Important: When disabling autoCalculateDateScheduling, provide complete data including start date, end date, and duration in your data source.

import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import { GanttModule, VirtualScrollService } from '@syncfusion/ej2-angular-gantt'
import { ToolbarItem, EditSettingsModel } from '@syncfusion/ej2-angular-gantt';
import { virtualData } from './data';

@Component({
    imports: [GanttModule],
    providers: [VirtualScrollService],
    standalone: true,
    selector: 'app-root',
    template:
        `<ejs-gantt height="450px" [dataSource]="data" [taskFields]="taskSettings" [treeColumnIndex]="1"
        [splitterSettings]="splitterSettings" [columns]="columns" [labelSettings]="labelSettings"
        [allowSelection]="true" [enableVirtualization]="true"  [autoCalculateDateScheduling]="false" [editSettings] = "editSettings" [highlightWeekends]="true"></ejs-gantt>`,
    encapsulation: ViewEncapsulation.None
})

export class AppComponent implements OnInit {
    public data?: object[];
    public taskSettings?: object;
    public splitterSettings?: object;
    public columns?: object[];
    public editSettings?: EditSettingsModel;
    public toolbar?: ToolbarItem[];
    public labelSettings?: object;

    public ngOnInit(): void {
        this.data = virtualData,
        this.taskSettings = {
            id: 'TaskID',
            name: 'TaskName',
            startDate: 'StartDate',
            endDate: 'EndDate',
            duration: 'Duration',
            progress: 'Progress',
            parentID: 'parentID'
        };
        this.columns = [
            { field: 'TaskID' },
            { field: 'TaskName' },
            { field: 'StartDate' },
            { field: 'Duration' },
            { field: 'Progress' }
        ];
        this.splitterSettings = {
            columnIndex: 2
        };
        this.editSettings = {
            allowAdding: true,
            allowEditing: true,
            allowDeleting: true,
            allowTaskbarEditing: true,
            showDeleteConfirmDialog: true
        },
        this.toolbar = ['Add', 'Cancel', 'CollapseAll', 'Delete', 'Edit', 'ExpandAll', 'NextTimeSpan', 'PrevTimeSpan', 'Search', 'Update', 'Indent', 'Outdent']
        this.labelSettings = {
            leftLabel: 'TaskName',
            taskLabel: 'Progress'
        };
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
export let  tempData: any[]  =[
    {
        TaskID: 1, TaskName: 'Product concept',StartDate: new Date('04/02/2019'), EndDate: new Date('04/21/2019'),
        parentID: 0
    },
    {
        TaskID: 2, TaskName: 'Defining the product and its usage', StartDate: new Date('04/02/2019'),
        Duration: 3, Progress: 30, parentID: 1
    },
    {
        TaskID: 3, TaskName: 'Defining target audience', StartDate: new Date('04/02/2019'),
        parentID: 1, Duration: 3
    },
    {
        TaskID: 4, TaskName: 'Prepare product sketch and notes', StartDate: new Date('04/05/2019'),
        Duration: 2, parentID: 1, Progress: 30
    },
    {
        TaskID: 5, TaskName: 'Concept approval', StartDate: new Date('04/08/2019'),
        parentID: 0, Duration: 0
    },
    {
        TaskID: 6, TaskName: 'Market research', StartDate: new Date('04/02/2019'),
        parentID: 0, EndDate: new Date('04/21/2019')
    },
    {
        TaskID: 7, TaskName: 'Demand analysis', StartDate: new Date('04/04/2019'),
        EndDate: new Date('04/21/2019'), parentID: 6
    },
    {
        TaskID: 8, TaskName: 'Customer strength', StartDate: new Date('04/09/2019'),
        Duration: 4, parentID: 7, Progress: 30
    },
    {
        TaskID: 9, TaskName: 'Market opportunity analysis', StartDate: new Date('04/09/2019'),
        Duration: 4, parentID: 7
    },
    {
        TaskID: 10, TaskName: 'Competitor analysis', StartDate: new Date('04/15/2019'),
        Duration: 4, parentID: 6, Progress: 30
    },
    {
        TaskID: 11, TaskName: 'Product strength analsysis', StartDate: new Date('04/15/2019'),
        Duration: 4, parentID: 6
    },
    {
        TaskID: 12, TaskName: 'Research complete', StartDate: new Date('04/18/2019'),
        Duration: 0, parentID: 6
    },
    {
        TaskID: 13, TaskName: 'Product design and development', StartDate: new Date('04/04/2019'),
        parentID: 0, EndDate: new Date('04/21/2019')
    },
    {
        TaskID: 14, TaskName: 'Functionality design', StartDate: new Date('04/19/2019'),
        Duration: 3, parentID: 13, Progress: 30
    },
    {
        TaskID: 15, TaskName: 'Quality design', StartDate: new Date('04/19/2019'),
        Duration: 3, parentID: 13
    },
    {
        TaskID: 16, TaskName: 'Define reliability', StartDate: new Date('04/24/2019'),
        Duration: 2, Progress: 30, parentID: 13
    },
    {
        TaskID: 17, TaskName: 'Identifying raw materials', StartDate: new Date('04/24/2019'),
        Duration: 2, parentID: 13
    },
    {
        TaskID: 18, TaskName: 'Define cost plan', StartDate: new Date('04/04/2019'),
        parentID: 13, EndDate: new Date('04/21/2019')
    },
    {
        TaskID: 19, TaskName: 'Manufacturing cost', StartDate: new Date('04/26/2019'),
        Duration: 2, Progress: 30, parentID: 18
    },
    {
        TaskID: 20, TaskName: 'Selling cost', StartDate: new Date('04/26/2019'),
        Duration: 2, parentID: 18
    },
    {
        TaskID: 21, TaskName: 'Development of the final design', StartDate: new Date('04/30/2019'),
        parentID: 13, EndDate: new Date('04/21/2019')
    },
    {
        TaskID: 22, TaskName: 'Defining dimensions and package volume', StartDate: new Date('04/30/2019'),
        Duration: 2, parentID: 21, Progress: 30
    },
    {
        TaskID: 23, TaskName: 'Develop design to meet industry standards', StartDate: new Date('05/02/2019'),
        Duration: 2, parentID: 21
    },
    {
        TaskID: 24, TaskName: 'Include all the details', StartDate: new Date('05/06/2019'),
        Duration: 3, parentID: 21
    },
    {
        TaskID: 25, TaskName: 'CAD computer-aided design', StartDate: new Date('05/09/2019'),
        Duration: 3, parentID: 13, Progress: 30
    },
    {
        TaskID: 26, TaskName: 'CAM computer-aided manufacturing', StartDate: new Date('09/14/2019'),
        Duration: 3, parentID: 13
    },
    {
        TaskID: 27, TaskName: 'Design complete', StartDate: new Date('05/16/2019'),
        Duration: 0, parentID: 13
    },
    {
        TaskID: 28, TaskName: 'Prototype testing', StartDate: new Date('05/17/2019'),
        Duration: 4, Progress: 30, parentID: 0
    },
    {
        TaskID: 29, TaskName: 'Include feedback', StartDate: new Date('05/17/2019'),
        Duration: 4, parentID: 0
    },
    {
        TaskID: 30, TaskName: 'Manufacturing', StartDate: new Date('05/23/2019'),
        Duration: 5, Progress: 30, parentID: 0
    },
    {
        TaskID: 31, TaskName: 'Assembling materials to finsihed goods', StartDate: new Date('05/30/2019'),
        Duration: 5, parentID: 0
    },
    {
        TaskID: 32, TaskName: 'Feedback and testing', StartDate: new Date('04/04/2019'),
        parentID: 0, EndDate: new Date('04/21/2019'),
    },
    {
        TaskID: 33, TaskName: 'Internal testing and feedback', StartDate: new Date('06/06/2019'),
        Duration: 3, parentID: 32, Progress: 45
    },
    {
        TaskID: 34, TaskName: 'Customer testing and feedback', StartDate: new Date('06/11/2019'),
        Duration: 3, parentID: 32, Progress: 50
    },
    {
        TaskID: 35, TaskName: 'Final product development', StartDate: new Date('04/04/2019'),
        parentID: 0, EndDate: new Date('04/21/2019'),
    },
    {
        TaskID: 36, TaskName: 'Important improvements', StartDate: new Date('06/14/2019'),
        Duration: 4, Progress: 30, parentID: 35
    },
    {
        TaskID: 37, TaskName: 'Address any unforeseen issues', StartDate: new Date('06/14/2019'),
        Duration: 4, Progress: 30, parentID: 35
    },
    {
        TaskID: 38, TaskName: 'Final product', StartDate: new Date('04/04/2019'),
        parentID: 0, EndDate: new Date('04/21/2019'),
    },
    {
        TaskID: 39, TaskName: 'Branding product', StartDate: new Date('06/20/2019'),
        Duration: 4, parentID: 38
    },
    {
        TaskID: 40, TaskName: 'Marketing and presales', StartDate: new Date('06/26/2019'), Duration: 4,
        Progress: 30, parentID: 38
    }
];

export let virtualData: any[] = [];
let projId: number = 1;
for (let i: number = 0; i < 50; i++) {
    let x: number = virtualData.length + 1;
    let parent: any = {};
    /* tslint:disable:no-string-literal */
    parent['TaskID'] = x;
    parent['TaskName'] = 'Project ' + (i + 1);
    virtualData.push(parent);
    for (let j: number = 0; j < tempData.length; j++) {
        let subtasks: any = {};
        /* tslint:disable:no-string-literal */
        subtasks['TaskID'] = tempData[j].TaskID + x;
        subtasks['TaskName'] = tempData[j].TaskName;
        subtasks['StartDate'] = tempData[j].StartDate;
        subtasks['Duration'] = tempData[j].Duration;
        subtasks['Progress'] = tempData[j].Progress;
        subtasks['parentID'] = tempData[j].parentID + x;
        virtualData.push(subtasks);

When setting autoCalculateDateScheduling property to false, you must provide a valid data source; otherwise, the Gantt chart will render with invalid dates.

Optimizing custom content rendering

When integrating images or template elements into Gantt columns, use the Column Template feature instead of customizing data through rowDataBound or queryCellInfo events. These events trigger for each row and cell, potentially causing rendering delays and element persistence issues over time.

Optimizing loading performance by referring individual script and CSS

Enhance initial rendering performance by using the Custom Resource Generator (CRG) to download only required component scripts. The default ej2.min.js includes all Syncfusion components, which may increase load times. CRG allows selective component and module selection, reducing bundle size and improving loading performance.

Performance benchmarks

The following tables show typical load times for various Gantt configurations, comparing non-virtualized and virtualized scenarios:

Test environment

  • Component Version: Syncfusion Angular Gantt 31.1.17
  • Angular Version: 20.1.0
  • Browser: Edge 138
  • Operating System: Windows 11
  • CPU: 12th Gen Intel® Core™ i5-1235U
  • RAM: 16GB

Non-virtualized scenario (2,500 tasks)

Scenario Load time (seconds)
Default hierarchy(Parent-Child) 3.8
+ Predecessor 5.4
+ Resources 6.5
+ Split taskbars 7.8

Virtualized scenario (25,000 tasks)

Scenario Load time (seconds)
Default hierarchy(Parent-Child) 2.1
+ Predecessor 5.6
+ Resources 6.2
+ Split taskbars 6.8

Optimizing server-side data operations with adaptors

The Angular Gantt component supports various adaptors (OData, ODataV4, WebAPI, URL) for server-side data operations and CRUD functionalities. Using these adaptors with the DataManager component enables seamless remote data binding and action execution.

During data operations like filtering and sorting, corresponding action queries generate according to adaptor requirements. Handle these actions on the application side and return processed data to the Gantt. For efficient data processing, return processed data in this order:

  • Filtering
  • Sorting
  • Aggregates

Avoiding MaxJsonLength errors with large datasets

The Angular Gantt component operates on a client-server basis, sending data as JSON objects. Large JSON object serialization can cause MaxJsonLength errors. Resolve this by increasing the maximum length for JSON serialization in your web.config file or at the deserialization point.

Solution 1

<configuration> 
   <system.web.extensions>
       <scripting>
           <webServices>
               <jsonSerialization maxJsonLength="25000000"/>
           </webServices>
       </scripting>
   </system.web.extensions>
</configuration>

Solution 2

var serializer = new JavaScriptSerializer { MaxJsonLength = Int32.MaxValue };

Optimizing Angular apps with multiple gantts and templates

Performance issues in applications with multiple Gantt components relate to Angular’s change detection mechanism rather than the Syncfusion component itself. Large DOM populations cause performance issues due to continuous change detection.

For more information on common reasons for slowdowns in Angular apps, you can refer to the documentation link:

Angular provides two change detection strategies:

  • Default change detection: Uses the CheckAlways strategy with automatic change detection until explicitly deactivated. This can cause continuous detection for all template references.

  • OnPush change detection: Uses the CheckOnce strategy, disabling automatic change detection until reactivated. This triggers detection only for specific inputs rather than all template references.

Implement OnPush change detection strategy using:

 @Component({ 
  selector: "app-root", 
  templateUrl: "app.component.html", 
  providers: [ReorderService], 
  changeDetection: ChangeDetectionStrategy.OnPush 
})

For additional guidance on OnPush strategy implementation:

Microsoft Excel limitations for large exports

Microsoft Excel supports only 1,048,576 records per sheet by default, making direct export of millions of records unfeasible. For large datasets, consider exporting to CSV (Comma-Separated Values) or other formats that handle large data more efficiently than Excel. For detailed Excel specifications, refer to the Microsoft documentation.

Tree shaking and bundle size optimization

The Syncfusion Angular Gantt component supports tree shaking through modular, tree-shakable packages. Import specific modules based on requirements:

import { GanttModule } from '@syncfusion/ej2-angular-gantt';
import { FilterService, SortService, SelectionService } from '@syncfusion/ej2-angular-gantt';

The following table shows example production build sizes with incremental feature additions:

Module Raw size Transfer size
Empty app 220.26 kB 60.71 kB
GanttModule 2.55 MB 473.29 kB
+ SortService 2.56 MB 475.69 kB
+ SelectionService 2.58 MB 477.38 kB
+ FilterService 2.99 MB 538.76 kB
+ ReorderService 3.00 MB 541.35 kB
+ ExcelService 3.14 MB 569.72 kB
  • Raw size: Uncompressed bundle size
  • Transfer size: Compressed size for network transfer

Tree shaking maintains manageable bundle sizes by including only imported features. Using GanttAllModule significantly increases bundle size by including all features regardless of usage.

For detailed implementation, refer to the Syncfusion Angular Tree Shaking documentation.

See also