Skip to main content

Gantt Charts

A Gantt chart visualizes tasks against a time axis — each task is drawn as a horizontal bar spanning its start and end dates. Optional metadata such as completion percentage, assignee, or priority can be attached to each bar. Typical use cases include project scheduling, sprint planning, and resource allocation.

SciChart.js has no dedicated Gantt series. Gantt charts are assembled from FastRectangleRenderableSeriesšŸ“˜ for the task bars, a CategoryAxisšŸ“˜ for the task rows on the Y axis, and a DateTimeNumericAxisšŸ“˜ for the timeline on the X axis.

tip

The JavaScript Gantt Chart Example can be found in the SciChart.JS Examples Suite on GitHub, or in the live demo at scichart.com/demo.

Above: The JavaScript Gantt Chart example from the SciChart.js Demo

Core Building Blocks​

A Gantt chart in SciChart.js is assembled from:

Examples​

Basic Gantt Chart​

The simplest Gantt chart uses a plain NumericAxis on both axes and a FastRectangleRenderableSeries with EColumnMode.StartEnd and EColumnYMode.TopBottom. Each task occupies one integer row on the Y axis with a bar height less than 1 to leave gaps between rows.

This simplified example uses NumericAxis on both axes with integer coordinates. For the full approach with real dates and task labels, see the Project Timeline Example below.

// Each task is a horizontal bar defined by [xStart, yBottom, xEnd, yTop]
// Y rows are integer indices; bar height is 0.6 to leave gaps between rows
const BAR_HEIGHT = 0.6;

const tasks = [
{ start: 0, end: 3 },
{ start: 2, end: 6 },
{ start: 5, end: 12 },
{ start: 10, end: 14 },
{ start: 13, end: 15 },
];

const xValues = tasks.map(t => t.start);
const x1Values = tasks.map(t => t.end);
// Center each bar on its integer index so axis ticks land in the middle of each bar
const yValues = tasks.map((_, i) => i - BAR_HEIGHT / 2);
const y1Values = tasks.map((_, i) => i + BAR_HEIGHT / 2);

const ganttSeries = new FastRectangleRenderableSeries(wasmContext, {
dataSeries: new XyxyDataSeries(wasmContext, { xValues, yValues, x1Values, y1Values }),
columnXMode: EColumnMode.StartEnd,
columnYMode: EColumnYMode.TopBottom,
fill: "steelblue",
strokeThickness: 0,
opacity: 0.85,
topCornerRadius: 4,
bottomCornerRadius: 4
});

Data Format​

For a real project timeline, convert task objects into the four flat arrays that XyxyDataSeries expects. Dates are passed as Unix millisecond timestamps via Date.getTime(). Metadata attached to each data point is later used by tooltips and data labels.

The prepareGanttData function from the project-timeline demo:

function prepareGanttData(tasks: GanttTask[]) {
const xValues: number[] = [];
const yValues: number[] = [];
const x1Values: number[] = [];
const y1Values: number[] = [];
const metadata: { isSelected: boolean; name: string; start: Date; end: Date; percentComplete: number }[] = [];

tasks.forEach((task, i) => {
xValues.push(task.startDate.getTime());
x1Values.push(task.endDate.getTime());
// CategoryAxis is reversed: index 0 = top row, so y increases downward
yValues.push(i);
y1Values.push(i + BAR_HEIGHT);
metadata.push({ isSelected: false, name: task.name, start: task.startDate, end: task.endDate, percentComplete: task.percentComplete });
});

return { xValues, yValues, x1Values, y1Values, metadata };
}

Metadata is attached to the XyxyDataSeries constructor:

new XyxyDataSeries(wasmContext, { xValues, yValues, x1Values, y1Values, metadata })

Axis Setup​

DateTimeNumericAxis (X)​

The X axis uses DateTimeNumericAxis with labelFormat: ENumericFormat.Date_DDMMYYYY so tick labels are automatically formatted as readable dates:

// X axis: date/time timeline
sciChartSurface.xAxes.add(new DateTimeNumericAxis(wasmContext, {
labelFormat: ENumericFormat.Date_DDMMYYYY,
growBy: new NumberRange(0.02, 0.05)
}));

CategoryAxis (Y)​

The Y axis uses CategoryAxis with flippedCoordinates: true so that row index 0 appears at the top (matching typical Gantt chart conventions). A custom formatLabel on the label provider maps integer row indices to task name strings:

// Y axis: category labels for each project stage, reversed so row 0 is at the top
const yAxis = new CategoryAxis(wasmContext, {
axisAlignment: EAxisAlignment.Left,
flippedCoordinates: true,
growBy: new NumberRange(0.05, 0.05),
labelStyle: { padding: { left: 0, right: 0, top: 0, bottom: 40 } }
});
// Map integer row indices to task name strings
yAxis.labelProvider.formatLabel = (dataValue: number) =>
TASKS[Math.round(dataValue)]?.name ?? "";
sciChartSurface.yAxes.add(yAxis);

Here TASKS is the module-level array of GanttTask objects defined in the Data Format section.

Styling​

Task bars support rounded corners, opacity, stroke, and data labels. The metaDataSelector callback reads the completion percentage from the per-point metadata and renders it inside each bar.

The snippet below assumes metadata has been prepared by the prepareGanttData function shown in the Data Format section above.

const ganttSeries = new FastRectangleRenderableSeries(wasmContext, {
dataSeries: new XyxyDataSeries(wasmContext, { xValues, yValues, x1Values, y1Values, metadata }),
columnXMode: EColumnMode.StartEnd,
columnYMode: EColumnYMode.TopBottom,
fill: "#4a90d9",
stroke: "white",
strokeThickness: 1,
opacity: 0.5,
topCornerRadius: 4,
bottomCornerRadius: 4,
dataLabels: {
style: { fontSize: 14, fontFamily: "Arial" },
color: "white",
// display completion percentage from metadata
metaDataSelector: (m) => {
const meta = m as { isSelected: boolean; name: string; start: Date; end: Date; percentComplete: number };
return meta ? `${meta.percentComplete}%` : "";
}
}
});

Tooltips​

A CursorModifier with a custom tooltipDataTemplate reads the point metadata to show the task name, start date, end date, and completion percentage on hover:

// Tooltip: show task name, start date, end date on hover
const tooltipDataTemplate: TCursorTooltipDataTemplate = (seriesInfos) => {
return seriesInfos
.filter(si => si.isHit)
.map(si => {
const m = si.pointMetadata as { isSelected: boolean; name: string; start: Date; end: Date; percentComplete: number };
if (!m) return "";
return [
m.name,
`Start: ${m.start.toLocaleDateString()}`,
`End: ${m.end.toLocaleDateString()}`,
`Complete: ${m.percentComplete}%`
].join("\n");
});
};

Chart Modifiers​

The project timeline uses pan and zoom restricted to the X direction so the task list on the Y axis stays fixed, plus a CursorModifier for tooltips:

sciChartSurface.chartModifiers.add(
new ZoomPanModifier({ xyDirection: EXyDirection.XDirection }),
new ZoomExtentsModifier(),
new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
new CursorModifier({ showTooltip: true, tooltipDataTemplate })
);

Project Timeline Example​

The full project timeline example adds a CategoryAxis, DateTimeNumericAxis, per-task metadata, data labels showing completion percentage, and interactive tooltips via CursorModifier.

// X axis: date/time timeline
sciChartSurface.xAxes.add(new DateTimeNumericAxis(wasmContext, {
growBy: new NumberRange(0.02, 0.05)
}));

// Y axis: category labels for each project stage, reversed so row 0 is at the top
const yAxis = new CategoryAxis(wasmContext, {
axisAlignment: EAxisAlignment.Left,
flippedCoordinates: true,
visibleRange: new NumberRange(-0.5, TASKS.length - 0.5),
autoRange: EAutoRange.Never,
drawMajorBands: false,
drawMinorGridLines: false,
});
// Map integer row indices to task name strings
yAxis.labelProvider.formatLabel = (dataValue: number) =>
TASKS[Math.round(dataValue)]?.name ?? "";
sciChartSurface.yAxes.add(yAxis);

const { xValues, yValues, x1Values, y1Values, metadata } = prepareGanttData(TASKS);

const ganttSeries = new FastRectangleRenderableSeries(wasmContext, {
dataSeries: new XyxyDataSeries(wasmContext, { xValues, yValues, x1Values, y1Values, metadata }),
columnXMode: EColumnMode.StartEnd,
columnYMode: EColumnYMode.TopBottom,
fill: "#4a90d9",
stroke: "white",
strokeThickness: 1,
opacity: 0.5,
topCornerRadius: 4,
bottomCornerRadius: 4,
dataLabels: {
style: { fontSize: 14, fontFamily: "Arial" },
color: "white",
// display completion percentage from metadata
metaDataSelector: (m) => {
const meta = m as { isSelected: boolean; name: string; start: Date; end: Date; percentComplete: number };
return meta ? `${meta.percentComplete}%` : "";
}
}
});

sciChartSurface.renderableSeries.add(ganttSeries);

// Tooltip: show task name, start date, end date on hover
const tooltipDataTemplate: TCursorTooltipDataTemplate = (seriesInfos) => {
return seriesInfos
.filter(si => si.isHit)
.map(si => {
const m = si.pointMetadata as { isSelected: boolean; name: string; start: Date; end: Date; percentComplete: number };
if (!m) return "";
return [
m.name,
`Start: ${m.start.toLocaleDateString()}`,
`End: ${m.end.toLocaleDateString()}`,
`Complete: ${m.percentComplete}%`
].join("\n");
});
};

sciChartSurface.chartModifiers.add(
new ZoomPanModifier({ xyDirection: EXyDirection.XDirection }),
new ZoomExtentsModifier(),
new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
new CursorModifier({ showTooltip: true, tooltipDataTemplate })
);

See Also​