This page shows an example on how to use Gantt chart to show a parent and its children. I used Account object for it, but the below code will work for any standard custom object as long as there is a ParentId
field.

Apex Controller:
public with sharing class GanttChartHierarchy {
public List<SObject> sobjectRecordsList {get; set;}
public String sobjSerializeString {get; set;}
public GanttChartHierarchy() {
AggregateResult[] parentWithChildren = [SELECT COUNT(Id) countChildren, ParentId FROM Account GROUP BY ParentId];
Set<Id> parentIdsSet = new Set<Id>();
for (AggregateResult agResult : parentWithChildren) {
if( agResult.get('ParentId') != null ) {
parentIdsSet.add( (Id)agResult.get('ParentId') );
}
}
sobjectRecordsList = [SELECT Id, Name, start_date__c, end_date__c, ParentId, (SELECT Id, Name FROM ChildAccounts) FROM Account WHERE Id IN: parentIdsSet];
sobjSerializeString = JSON.serialize(sobjectRecordsList);
}
}
Visualforce Page:
<apex:page controller="GanttChartHierarchy" standardStylesheets="false" showHeader="false">
<head>
<apex:stylesheet value="{!URLFOR($Resource.Timeline, 'gantt/codebase/dhtmlxgantt.css')}"/>
<apex:includeScript value="{!URLFOR($Resource.Timeline, 'gantt/codebase/dhtmlxgantt.js')}"/>
<style type="text/css" media="screen">
html, body { margin:0px; padding:0px; height:100%; overflow:hidden; }
</style>
</head>
<body>
<div id="gantt_here" style='width:100%; height:100%;'></div>
<script type="text/javascript">
let ganttDataArr = [];
let sobjResultJSON = {!sobjSerializeString}; // store the apex variable that we serialized.
// iterate over all accounts that are returned by apex
for (let key of Object.keys(sobjResultJSON)) {
let ganttDataObj = {};
ganttDataObj["id"] = sobjResultJSON[key]["Id"];
ganttDataObj["text"] = sobjResultJSON[key]["Name"];
if (sobjResultJSON[key]["Start_Date__c"] != null) {
ganttDataObj["start_date"] = new Date(sobjResultJSON[key]["Start_Date__c"]);
} else {
ganttDataObj["start_date"] = new Date();
}
ganttDataObj["duration"] = 18;
ganttDataObj["progress"] = "0.6";
ganttDataObj["open"] = true;
if( sobjResultJSON[key]["ChildAccounts"].totalSize > 0 ) {
for (let childKey = 0; childKey < sobjResultJSON[key]["ChildAccounts"].totalSize; childKey++) {
let ganttChildDataObj = {};
ganttChildDataObj["id"] = sobjResultJSON[key]["ChildAccounts"]["records"][childKey]["Id"];
ganttChildDataObj["text"] = sobjResultJSON[key]["ChildAccounts"]["records"][childKey]["Name"];
if (sobjResultJSON[key]["ChildAccounts"]["records"][childKey]["Start_Date__c"] != null) {
ganttChildDataObj["start_date"] = new Date(sobjResultJSON[key]["ChildAccounts"]["records"][childKey]["Start_Date__c"]);
} else {
ganttChildDataObj["start_date"] = new Date();
}
ganttChildDataObj["duration"] = 18/sobjResultJSON[key]["ChildAccounts"].totalSize;
ganttChildDataObj["order"] = '10';
ganttChildDataObj["progress"] = "0.6";
ganttChildDataObj["parent"] = sobjResultJSON[key]["Id"];
ganttDataArr.push(ganttChildDataObj);
}
}
ganttDataArr.push(ganttDataObj);
}
let tasks = {
data: ganttDataArr,
links:[
{ id:1, source:1, target:2, type:"1"},
{ id:2, source:2, target:3, type:"0"},
{ id:3, source:3, target:4, type:"0"},
{ id:4, source:2, target:5, type:"2"},
]
};
gantt.init("gantt_here");
gantt.parse(tasks);
</script>
</body>
</apex:page>