Data Markers in React Gantt Chart Component

31 Jan 202624 minutes to read

Data markers are visual indicators that highlight significant events, milestones, or important dates within individual project tasks. These markers provide immediate visual context about critical moments in task timelines, enabling effective identification of key dates and tracking of important events at the task level. Understanding data markers implementation ensures effective project visualization and milestone tracking throughout project development cycles.

Data markers utilize specific properties to define their appearance, positioning, and interactive behavior within task timelines:

Date specification: The date property establishes the exact timeline position where the marker appears. This date value determines marker placement relative to the task’s start and end dates, ensuring accurate event representation.

Visual styling: The iconClass property defines the CSS class that controls marker visual appearance. This property enables custom styling through icon fonts, background images, or CSS-based graphics to distinguish different marker types.

Identification: The name property provides unique identification for each marker. This name serves as an internal reference and can be used for programmatic marker manipulation or event handling.

Interactive content: The tooltip property supplies descriptive text that displays when users hover over markers. This property enhances user experience by providing detailed context about marker significance and related event information.

Tooltip Rendering Requirements: Data marker tooltips render only when the tooltip property contains valid content values. Empty or undefined tooltip properties result in no tooltip display, maintaining clean visual presentation for markers without additional descriptions.

Data mapping and configuration properties

Data markers represent schedule events for specific tasks through visual indicators positioned at designated dates within task timelines. The component renders markers as icon-based elements that display at precise timeline locations, providing instant visual reference for important task-related events.

Data structure requirements: Data markers are defined in the data source as arrays of objects containing marker specifications. Each marker object includes date information, visual styling, identification details, and optional tooltip content for enhanced user interaction.

Mapping configuration: The marker array connects to the Gantt Chart component through the taskFields.indicators property mapping. This configuration establishes the relationship between data source marker definitions and component rendering logic.

Multiple marker support: Tasks can display multiple data markers simultaneously, allowing comprehensive event tracking within individual task contexts. Each marker maintains independent configuration while sharing the same task timeline space.
The following implementation demonstrates comprehensive data marker integration within a Gantt chart, showcasing multiple markers per task with varied styling and tooltip configurations:

import { GanttComponent } from '@syncfusion/ej2-react-gantt';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { data } from './datasource';

function App() {
    const taskFields = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        resourceInfo: 'resources',
        duration: 'Duration',
        progress: 'Progress',
        dependency: 'Predecessor',
        parentID: 'ParentID',
        indicators: 'Indicators'
    };
    return <GanttComponent dataSource={data} taskFields={taskFields} height='430px'>
    </GanttComponent>
};
ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject, Selection, Toolbar } from '@syncfusion/ej2-react-gantt';
import type { TaskFieldsModel, ResourceFieldsModel, EditSettingsModel } from '@syncfusion/ej2-react-gantt';
import { data, resources } from './datasource';

function App() {
  const taskFields: TaskFieldsModel = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    endDate: 'EndDate',        
    duration: 'Duration',
    progress: 'Progress',
    dependency: 'Predecessor',
    parentID: 'ParentID',
    resourceInfo: 'resources',
    indicators: 'Indicators'
  };

  const resourceFields: ResourceFieldsModel = {
    id: 'resourceId',
    name: 'resourceName'
  };

  const editSettings: EditSettingsModel = {
    allowAdding: true,
    allowEditing: true,
    allowDeleting: true,
    allowTaskbarEditing: true,
    showDeleteConfirmDialog: true
  };

  const toolbar = ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'];

  return (
    <div style=>
      <GanttComponent
        dataSource={data}
        taskFields={taskFields}
        resourceFields={resourceFields}
        resources={resources}
        height="430px"
        allowSelection={true}
        allowSorting={true}
        enableContextMenu={true}
        highlightWeekends={true}
        treeColumnIndex={1}
        toolbar={toolbar}
        editSettings={editSettings}
        projectStartDate={new Date(2026, 0, 25)}
        projectEndDate={new Date(2026, 1, 28)}
      >
        <ColumnsDirective>
          <ColumnDirective field="TaskID" headerText="ID" width="70" textAlign="Right" />
          <ColumnDirective field="TaskName" headerText="Task Name" width="180" />
          <ColumnDirective field="StartDate" headerText="Start" />
          <ColumnDirective field="Duration" headerText="Duration (d)" />
          <ColumnDirective field="Progress" headerText="Progress (%)" />
          <ColumnDirective field="Predecessor" headerText="Depends On" />
          <ColumnDirective field="resources" headerText="Resources" />
        </ColumnsDirective>
        <Inject services={[Selection, Toolbar]} />
      </GanttComponent>
    </div>
  );
}

export default App;
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Gantt</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/32.1.19/tailwind3.css" rel="stylesheet" type="text/css"/>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
     <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }
    </style>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
        <div id='root'>
            <div id='loader'>Loading....</div>
        </div>
</body>

</html>

Custom event bind to data markers

Data markers support interactive functionality through click event binding, enabling custom actions when markers are selected. This interaction capability allows the implementation of detailed views, status updates, or navigation to related information based on marker context.

Event binding implementation: Click events are bound to data markers using the dataBound event of the Gantt Chart component. This event fires after data binding completes, ensuring all marker elements are rendered and available for event attachment.

DOM element selection: Data markers render with the CSS class .e-indicator-span, which serves as the selector for identifying marker elements within the DOM. This class provides a reliable reference for event binding regardless of marker styling or content variations.

The following implementation demonstrates how to open the edit dialog for a specific task when its data marker is clicked:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Toolbar, Edit, Inject } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
    let ganttInstance = null;
    const taskSettings = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        endDate: 'EndDate',
        duration: 'Duration',
        progress: 'Progress',
        parentID: 'ParentID',
        indicators: 'Indicators'
    };

    const editSettings = {
        allowEditing: true
    };

    const toolbar = ['Edit'];

    const dataBound = () => {
        const elements = document.querySelectorAll('.e-indicator-span');
        elements.forEach((el) => {
            el.addEventListener('click', (event) => {
                const indicator = event.target;
                const taskbar = indicator.closest('.e-chart-row');

                if (taskbar && ganttInstance) {
                    const rowIndex = Number(taskbar.getAttribute('data-rowindex'));
                    const record = ganttInstance.flatData[rowIndex];
                    console.log(record.ganttProperties);
                    if (record.ganttProperties.taskId) {
                        ganttInstance.openEditDialog(record.ganttProperties.taskId);
                    }
                }
            });
        });
    };

    return (
        <GanttComponent
            id="Gantt"
            height="450px"
            dataSource={data}
            taskFields={taskSettings}
            editSettings={editSettings}
            toolbar={toolbar}
            dataBound={dataBound}
            ref={gantt => ganttInstance = gantt}
        >
            <Inject services={[Toolbar, Edit]} />
        </GanttComponent>
    );
}

ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { GanttComponent, Toolbar, Edit, Inject } from '@syncfusion/ej2-react-gantt';
import { data } from './datasource';
function App() {
  let ganttInstance: GanttComponent | null = null;
  const taskSettings: object = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    endDate: 'EndDate',
    duration: 'Duration',
    progress: 'Progress',
    parentID: 'ParentID',
    indicators: 'Indicators'
  };

  const editSettings: object = {
    allowEditing: true
  };

  const toolbar: string[] = ['Edit'];

  const dataBound = (): void => {
    const elements = document.querySelectorAll('.e-indicator-span');
    elements.forEach((el) => {
      el.addEventListener('click', (event: Event) => {
        const indicator = event.target as HTMLElement;
        const taskbar = indicator.closest('.e-chart-row') as HTMLElement;

        if (taskbar && ganttInstance) {
          const rowIndex = Number(taskbar.getAttribute('data-rowindex'));
          const record = ganttInstance.flatData[rowIndex];
          console.log(record.ganttProperties);
          if (record.ganttProperties.taskId) {
            ganttInstance.openEditDialog(record.ganttProperties.taskId);
          }
        }
      });
    });
  };

  return (
    <GanttComponent
      id="Gantt"
      height="450px"
      dataSource={data}
      taskFields={taskSettings}
      editSettings={editSettings}
      toolbar={toolbar}
      dataBound={dataBound}
      ref={gantt => ganttInstance = gantt}
    >
      <Inject services={[Toolbar, Edit]} />
    </GanttComponent>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Gantt</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/32.1.19/tailwind3.css" rel="stylesheet" type="text/css"/>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
     <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }
    </style>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
        <div id='root'>
            <div id='loader'>Loading....</div>
        </div>
</body>

</html>

Custom event bind to data markers

Event handler considerations: The click event handler locates the parent task row using DOM traversal methods, extracts the task information from the current view data, and calls the openEditDialog method with the appropriate task ID to display the edit dialog for the selected task.

Apply custom styling for indicator span

You can programmatically modify the styling of the indicator by targeting the .e-indicator-span class.

import { GanttComponent } from '@syncfusion/ej2-react-gantt';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { data } from './datasource';

function App() {
    const taskFields = {
        id: 'TaskID',
        name: 'TaskName',
        startDate: 'StartDate',
        resourceInfo: 'resources',
        duration: 'Duration',
        progress: 'Progress',
        dependency: 'Predecessor',
        parentID: 'ParentID',
        indicators: 'Indicators'
    };
    return <GanttComponent dataSource={data} taskFields={taskFields} height='430px'>
    </GanttComponent>
};
ReactDOM.render(<App />, document.getElementById('root'));
import * as React from 'react';
import { GanttComponent, ColumnsDirective, ColumnDirective, Inject, Selection, Toolbar } from '@syncfusion/ej2-react-gantt';
import type { TaskFieldsModel, ResourceFieldsModel, EditSettingsModel } from '@syncfusion/ej2-react-gantt';
import { data, resources } from './datasource';

function App() {
  const taskFields: TaskFieldsModel = {
    id: 'TaskID',
    name: 'TaskName',
    startDate: 'StartDate',
    endDate: 'EndDate',        
    duration: 'Duration',
    progress: 'Progress',
    dependency: 'Predecessor',
    parentID: 'ParentID',
    resourceInfo: 'resources',
    indicators: 'Indicators'
  };

  const resourceFields: ResourceFieldsModel = {
    id: 'resourceId',
    name: 'resourceName'
  };

  const editSettings: EditSettingsModel = {
    allowAdding: true,
    allowEditing: true,
    allowDeleting: true,
    allowTaskbarEditing: true,
    showDeleteConfirmDialog: true
  };

  const toolbar = ['Add', 'Edit', 'Update', 'Delete', 'Cancel', 'ExpandAll', 'CollapseAll'];

  return (
    <div style=>
      <GanttComponent
        dataSource={data}
        taskFields={taskFields}
        resourceFields={resourceFields}
        resources={resources}
        height="430px"
        allowSelection={true}
        allowSorting={true}
        enableContextMenu={true}
        highlightWeekends={true}
        treeColumnIndex={1}
        toolbar={toolbar}
        editSettings={editSettings}
        projectStartDate={new Date(2026, 0, 25)}
        projectEndDate={new Date(2026, 1, 28)}
      >
        <ColumnsDirective>
          <ColumnDirective field="TaskID" headerText="ID" width="70" textAlign="Right" />
          <ColumnDirective field="TaskName" headerText="Task Name" width="180" />
          <ColumnDirective field="StartDate" headerText="Start" />
          <ColumnDirective field="Duration" headerText="Duration (d)" />
          <ColumnDirective field="Progress" headerText="Progress (%)" />
          <ColumnDirective field="Predecessor" headerText="Depends On" />
          <ColumnDirective field="resources" headerText="Resources" />
        </ColumnsDirective>
        <Inject services={[Selection, Toolbar]} />
      </GanttComponent>
    </div>
  );
}

export default App;
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React Gantt</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/32.1.19/tailwind3.css" rel="stylesheet" type="text/css"/>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
     <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }
    </style>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
        <div id='root'>
            <div id='loader'>Loading....</div>
        </div>
</body>

</html>