There are as many requirements as many projects. We often receive requests from developers about how far they can go in customizing DHTMLX Gantt. Not everyone knows that our JS Gantt chart allows changing virtually every aspect of its appearance. The resulting Gantt built with DHTMLX can look very different from the original one.
We start a new series of articles on the blog, where we will uncover the most exemplary cases of customizing DHTMLX Gantt to demonstrate its versatility.
Use Case: New Project Appearance, Current Month Marker, and Collapsible Grid
The default view of DHTMLX Gantt displays project and task names written inside bars. The project bar usually has a rectangle shape, just like the task bar, and differs from tasks in color. However, this is not the only way to show projects and tasks in DHTMLX Gantt. Our Gantt chart library is very flexible in terms of customization and allows visualizing data in almost any imaginable way. Don’t take our word for it, but look at a live example.
Here, you can see projects nicely depicted with thin, colorful lines and labels on top, project dates and duration marked next to their names. Thus, end-users can quickly grasp how much time each project will take.
Task labels are also located to the right of the task bar. The current month is clearly highlighted in the timescale not to get lost on the timeline. Besides, there is a toggle button for collapsing the grid section to make more room for the Gantt chart.
Such a customization contributes to the transparency of the workflow and can be especially useful for small and medium-sized projects. It also makes your Gantt more user-friendly and easier to manage, switching between the view with an expanded grid section and a full-screen chart.
Customization Guide
Let’s delve into what is under the hood of such a Gantt chart made by DHTMLX.
Current Month Marker
We start with the time scales and the vertical marker used in the Gantt timeline. The configuration of scales is specified via the scales
property:
gantt.config.scales = [
{
unit: "quarter", step: 1, format: function (date) {
const quarter = (date.getMonth() % 3) + 1;
const year = date.getFullYear();
return `<b>Q${quarter}</b> ${year}`;
}
},
{
unit: "month", step: 1, format: function (date) {
const monthName = gantt.date.date_to_str("%F")(date)
const nextDate = gantt.date.add(date, 1, "month");
if (+date <= +today && +today <= +nextDate) {
return `<div class="current_month">${monthName}</div>`;
}
else {
return monthName;
}
}
},
]
In the array of the scales
config, we specify two built-in types of scales, “quarter” and “month”. In the cells of both scale types, we can display any values or HTML elements, but they won’t change the width of cells. For instance, one of the cells in the lower scale with names of months includes a custom element with a specific class for coloring this cell with CSS styles. This element highlights the current month, which is specified in the today
parameter:
const today = new Date(2023, 05, 18)
const todayMarker = gantt.addMarker({
start_date: today,
css: "today",
});
The today
parameter is also used in the addMarker()
method for adding a vertical marker that highlights the current month. In the marker configuration, we specify the Date
object that sets the marker’s date and the CSS class for adding the marker color. Since we do not apply the text
parameter in the addMarker()
method, the marker will be shown as a simple line.
Task Behavior
It is necessary to say a few words about the interaction with tasks in the Gantt timeline. End-users can move a given task along the timeline to any specific point and it won’t snap to the beginning or end of any cell. To make it happen, we changed the value of the round_dnd_dates
parameter to false
in the gantt.config
object:
gantt.config.round_dnd_dates = false;
Following the requirements of this demo project, we also added the ability to move project tasks and disabled the display of dependencies (links) between tasks and the progress of tasks:
gantt.config.drag_project = true;
gantt.config.drag_progress = false;
gantt.config.drag_links = false;
Grid
Let’s move on to the grid section. In the grid part of the Gantt chart, there are two columns. The first column contains the names of tasks, while the second one provides their timeframes. Using the template
function, you can add any text or HTML elements in the cells of the grid column:
gantt.config.columns = [
{ name: "text", label: " ", width: 300, tree: true },
{
name: "dates", label: getToggleButton(), align: "center", template: function (task) {
if (task.type == "project") {
return ""
}
return taskDatesFormat(task)
}
},
];
Now we want to focus on the taskDatesFormat
function that returns the needed string from a task object:
function taskDatesFormat(task) {
let startMonth = gantt.date.date_to_str("%M");
let endMonth = startMonth;
let day = gantt.date.date_to_str("%j");
if (task.start_date.getMonth() == task.end_date.getMonth()) {
endMonth = gantt.date.date_to_str("");
}
const start_date = `${startMonth(task.start_date)} ${day(task.start_date)} - `;
const end_date = `${endMonth(task.end_date)} ${day(task.end_date)}`;
return start_date + end_date;
}
This function works as follows:
It converts the task start date into a string, thereby showing only the month’s name.
If a task starts and ends in the same month, the month’s name will be seen only before the start date. If start and end dates belong to different months, the start month will show before the start date and the end month – before the end date.
Dates follow the name of the month.
There is a special toggle button that allows collapsing and expanding the grid section. To add this button, we specified the getToggleButton()
function inside the label parameter. Depending on the current state of the grid, this function returns different values. When the button is clicked, we change the return value and the width in the grid_width
config:
function toggleGrid() {
if (gridToggleText == "lt") {
gantt.config.grid_width = 80;
gridToggleText = "gt"
}
else {
gantt.config.grid_width = initialGridWidth;
gridToggleText = "lt"
}
gantt.config.columns[1].label = getToggleButton();
gantt.render();
}
Alternatively, the grid size can be changed with a resizer. The min_grid_column_width
parameter sets the minimum width for each column, so you cannot make the grid smaller than the specified size. Since our Gantt chart has two columns and the value of the min_grid_column_width
parameter is 30px, the minimum grid width is 60px.
gantt.config.min_grid_column_width = 30;
Colored circles in the grid area are specified in the grid_folder
template:
gantt.templates.grid_folder = function (task) {
return `<div style="color:${task.color}" class="project_icon"> • </div>`;
};
The returned custom element includes a special symbol "•". The color and size of circles are specified with CSS styles.
The grid_folder
template is displayed for tasks with child elements, while an empty string ("") is returned in the grid_file
template for other tasks:
gantt.templates.grid_file = function (item) {
return "";
};
The task_row_class
template hides a border under tasks with child elements:
gantt.templates.task_row_class = function (start, end, task) {
if (task.type == "project") {
return "project_row";
}
};
Task Appearance
Finally, let’s shed some light on how to customize projects and tasks in the Gantt chart. Since there should be no text inside taskbars, the task_text
template returns an empty string:
gantt.templates.task_text = function (start, end, task) {
return "";
};
Text labels are displayed on the right side with the help of the rightside_text
template:
gantt.templates.rightside_text = function (start, end, task) {
if (task.type != "project") {
return task.text;
}
};
In our demo, the rightside_text
template doesn’t return anything for project tasks. Instead, we use the addTaskLayer()
method, which allows displaying any text or HTML element inside the Gantt timeline. For project tasks, we return a task name, its duration, and dates in the same format used in the Gantt grid with the help of the custom taskDatesFormat
function. These values are separated from one another with a special dot symbol "•". The positioning of custom elements is calculated using the getTaskPosition()
method:
gantt.addTaskLayer(function (task) {
if (task.type == "project") {
const sizes = gantt.getTaskPosition(task, task.start_date, task.end_date);
const el = document.createElement('div');
const dot = `<span class="dot">•</span>`
el.innerHTML = task.text + dot + taskDatesFormat(task) + dot + task.duration + "days";
el.style.left = sizes.left + 10 + 'px';
el.style.top = sizes.top + 'px';
el.style.zIndex = 1;
el.style.marginTop = "7px";
el.style.position = "absolute";
el.style.lineHeight = "16px";
return el;
}
});
That’s it! With this step-by-step guide, you can achieve the same result and create a custom Gantt chart like in our use case.
Conclusion
The rich API of the DHTMLX Gantt component allows you to customize the look and feel of almost any element to your liking. So, if your web project lacks a Gantt chart and you have a clear vision of how it should look, DHTMLX Gantt will help bring your idea to life much faster. You can estimate its capabilities by downloading a free 30-day trial version.
Also, feel free to send us your ideas for Gantt customizations – and our tech support team will do their best to help you achieve the desired result.
The article is originally published on the DHTMLX blog.