{"id":11883,"date":"2023-11-21T14:00:00","date_gmt":"2023-11-21T11:00:00","guid":{"rendered":"https:\/\/dhtmlx.com\/blog\/?p=11883"},"modified":"2026-09-15T14:19:01","modified_gmt":"2026-09-15T11:19:01","slug":"building-jira-like-project-roadmap-dhtmlx-gantt","status":"publish","type":"post","link":"https:\/\/dhtmlx.com\/blog\/building-jira-like-project-roadmap-dhtmlx-gantt\/","title":{"rendered":"Building a Jira-Like Project Roadmap with DHTMLX Gantt"},"content":{"rendered":"<p>When using DHTMLX Gantt in web projects, developers frequently have to meet various requirements related to the UI appearance. So they must be sure of the customization capabilities of our <a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxGantt\/\" rel=\"noopener\" target=\"_blank\">JavaScript Gantt chart library<\/a>. Therefore, it is time to continue our series of Gantt customization use cases. <\/p>\n<p>In the new episode, you will learn how to build a Jira-like project roadmap using our Gantt component.<\/p>\n<h5>Use Case: Project Roadmap with Custom Timeline Icons, Status Bar, Timeline Resizer, and More<\/h5>\n<p>A project roadmap offers an easy-to-follow way to keep everyone interested in key project insights up to date. No wonder this functionality is often requested in project management apps and becomes a nice addition to other popular tools such as Gantt charts. In the previous <a href=\"https:\/\/dhtmlx.com\/blog\/deep-dhtmlx-gantt-customization-project-roadmap-split-tasks-milestones-organized-via-swimlanes\/\" rel=\"noopener\" target=\"_blank\">blog post<\/a> of the series, we demonstrated that it is not a problem to create a project roadmap using DHTMLX Gantt, but we would like to back up this claim with a new challenging scenario.<\/p>\n<p>This time you will learn how our Gantt library helps create a project roadmap similar to the one made with <a href=\"https:\/\/www.atlassian.com\/software\/jira\/product-discovery\/features\/roadmaps\" rel=\"noopener\" target=\"_blank\">Jira Align<\/a>. That\u2019s what it looks like:<br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2023\/11\/image2-1024x384.png\" alt=\"project roadmap built with DHTMLX Gantt\" width=\"1024\" height=\"384\" class=\"alignnone size-large wp-image-11884\" srcset=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2023\/11\/image2-1024x384.png 1024w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2023\/11\/image2-300x112.png 300w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2023\/11\/image2-768x288.png 768w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2023\/11\/image2.png 1905w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><a href=\"https:\/\/snippet.dhtmlx.com\/pjiegd1q?mode=wide\" rel=\"noopener\" target=\"_blank\">Check the code snippet ><\/a><\/p>\n<p>This roadmap sample visualizes the project workflow, where end-users can clearly understand how their work lines up against other tasks in planning intervals. In practice, such roadmaps can be useful in achieving the following goals:<\/p>\n<ul>\n<li>planning future work,<\/li>\n<li>tracking the progress of already planned work,<\/li>\n<li>reporting progress against roadmap commitments.<\/li>\n<\/ul>\n<p>If you take a look at the timeline, you can see custom icons of different colors with specified numeric values. They are backlog elements (subtask, improvement, user story, etc.) related to particular project tasks. When backlog elements turn out to be outside of the task timeframe, they are highlighted in red to attract the user\u2019s attention. The total number of backlog elements for each task is shown in the \u201cItem\u201d column of the grid. <\/p>\n<p>One more noteworthy parameter that you can see in the roadmap grid is called \u201cStory Points\u201d. It denotes a conventional unit used to assess time spent on a given task. The quantity and duration of story points for each task are specified by users. <\/p>\n<p>In other respects, the roadmap structure is quite clear and straightforward. So we can proceed to share with you the practical customization steps that will allow you to build the same project roadmap with DHTMLX Gantt.<\/p>\n<h5>Customization Guide<\/h5>\n<h6>Time Scales and Today\u2019s Marker<\/h6>\n<p>A timescale is a crucial element of any tool with a time-bound structure like a project roadmap. Therefore, we start with the configuration and customization of scales and today&#8217;s marker. The roadmap timeline includes two time scales &#8211; &#8220;month&#8221; and &#8220;day&#8221;. To set these scales, you should specify the corresponding options using the <strong>unit<\/strong> property in the <strong>scales<\/strong> config:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">scales<\/span> <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> unit<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;month&quot;<\/span><span class=\"sy0\">,<\/span> step<span class=\"sy0\">:<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> date<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;%F&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> unit<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;day&quot;<\/span><span class=\"sy0\">,<\/span> step<span class=\"sy0\">:<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> date<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;%d&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The today\u2019s marker is added to the timeline area with the <strong>addMarker<\/strong> method:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> todayMarker <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">addMarker<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; start_date<span class=\"sy0\">:<\/span> today<span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; css<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;today&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; text<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Today&quot;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The marker&#8217;s appearance can be changed using CSS styles. The <strong>css<\/strong> parameter specifies the class name for the marker. This parameter can be used as a selector to add your styles for the marker.<\/p>\n<p>You won\u2019t need the background color in the vertical line of the marker, so you can disable this parameter and show the left border. The <strong>border-left<\/strong> property helps add a dashed line to the marker instead of a solid one:<\/p>\n<div class=\"codecolorer-container css default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"css codecolorer\"><span class=\"re1\">.today<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">border-left<\/span><span class=\"sy0\">:<\/span> <span class=\"re3\">2px<\/span> <span class=\"kw2\">dashed<\/span> <span class=\"kw4\">gray<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">background<\/span><span class=\"sy0\">:<\/span> unset<span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>After these changes, it is necessary to specify the background color under the text of the marker, otherwise the text won\u2019t be visible:<\/p>\n<div class=\"codecolorer-container css default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"css codecolorer\"><span class=\"re1\">.gantt_marker<\/span> <span class=\"re1\">.gantt_marker_content<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">background<\/span><span class=\"sy0\">:<\/span> <span class=\"kw4\">gray<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>Now we can consider more complex customizations of the roadmap interface.<\/p>\n<h6>Custom Icons for Work Items<\/h6>\n<p>Custom icons for work items shown in the roadmap timeline are probably the most curious elements in this scenario. We explained their meaning above, and now we want to unveil how these icons are implemented under the hood. <\/p>\n<p>In practice, these square icons are added to tasks in the timeline area with an additional layer with custom elements using the <strong>addTaskLayer<\/strong> method. To ensure that these elements do not disappear after the reinitialization, you need to add code inside the event handler for the <strong>onGanttReady<\/strong> event.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">attachEvent<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;onGanttReady&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; gantt.<span class=\"me1\">addTaskLayer<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span>task<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><\/div><\/div>\n<p>The <strong>addTaskLayer<\/strong> method works for all project tasks. Thus, you should start by checking the presence of saved values in a particular task property (items).<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">items<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><\/div><\/div>\n<p>For such saved values, you\u2019ll have to create the main element of the additional layer for the task. This element will be returned at the end of the function, and custom icons for work items will be added to it.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> mainEl <span class=\"sy0\">=<\/span> document.<span class=\"me1\">createElement<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'div'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>After that, it is necessary to iterate through all the values in <strong>task.items<\/strong>:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span>timestamp <span class=\"kw1\">in<\/span> task.<span class=\"me1\">items<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><\/div><\/div>\n<p>The next step is to take the <strong>unix timestamp<\/strong> value and convert it into a date. The result value should be stored in a separate variable.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> itemDate <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> <span class=\"kw4\">Date<\/span><span class=\"br0\">&#40;<\/span><span class=\"sy0\">+<\/span>timestamp<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> value <span class=\"sy0\">=<\/span> task.<span class=\"me1\">items<\/span><span class=\"br0\">&#91;<\/span>timestamp<span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Make use of the <strong>getTaskPosition<\/strong> method to specify the task object and the date where the custom icon should be displayed. It is needed to determine the coordinates of the icon square on the timeline.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> sizes <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">getTaskPosition<\/span><span class=\"br0\">&#40;<\/span>task<span class=\"sy0\">,<\/span> itemDate<span class=\"sy0\">,<\/span> itemDate<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Then you need to create an HTML element, where you will specify a particular class name and a value (number) and add an attribute with the task ID.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> el <span class=\"sy0\">=<\/span> document.<span class=\"me1\">createElement<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'div'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">className<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'work_item'<\/span><span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">innerHTML<\/span> <span class=\"sy0\">=<\/span> value<span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">setAttribute<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;data-taskId&quot;<\/span><span class=\"sy0\">,<\/span> task.<span class=\"me1\">id<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The custom icon must be displayed in the center of the cell. By default, the element width is 15px.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">let elWidth <span class=\"sy0\">=<\/span> <span class=\"nu0\">15<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>So if half the width of timeline cells is less than the width of the custom element, then the element will automatically shrink.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">let cellWidth <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">getScale<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">col_width<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>elWidth <span class=\"sy0\">&gt;<\/span> cellWidth <span class=\"sy0\">\/<\/span> <span class=\"nu0\">2<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp;elWidth <span class=\"sy0\">=<\/span> cellWidth <span class=\"sy0\">\/<\/span> <span class=\"nu0\">2<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>Taking into account the width of the element and the width of timeline cells, calculate the number of required left margins to place the element in the center of the cell:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">let marginLeft <span class=\"sy0\">=<\/span> <span class=\"br0\">&#40;<\/span>cellWidth <span class=\"sy0\">-<\/span> elWidth<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">\/<\/span> <span class=\"nu0\">2<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The position (coordinates) of the element is specified using styles:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">el.<span class=\"me1\">style<\/span>.<span class=\"me1\">left<\/span> <span class=\"sy0\">=<\/span> sizes.<span class=\"me1\">left<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">'px'<\/span><span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">style<\/span>.<span class=\"me1\">top<\/span> <span class=\"sy0\">=<\/span> sizes.<span class=\"me1\">top<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">'px'<\/span><span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">style<\/span>.<span class=\"me1\">marginLeft<\/span> <span class=\"sy0\">=<\/span> marginLeft <span class=\"sy0\">+<\/span> <span class=\"st0\">'px'<\/span><span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">style<\/span>.<span class=\"me1\">width<\/span> <span class=\"sy0\">=<\/span> elWidth <span class=\"sy0\">+<\/span> <span class=\"st0\">&quot;px&quot;<\/span><\/div><\/div>\n<p>The default color of the custom icon for work items is gray. This option is used when no other color is specified for the task. In case the date of the icon is not included in the date range of the task, it will be highlighted in red.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">let background <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;Gray&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"sy0\">+<\/span>itemDate <span class=\"sy0\">&lt;<\/span> <span class=\"sy0\">+<\/span>task.<span class=\"me1\">start_date<\/span> <span class=\"sy0\">||<\/span> <span class=\"sy0\">+<\/span>itemDate <span class=\"sy0\">&gt;<\/span> <span class=\"sy0\">+<\/span>task.<span class=\"me1\">end_date<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; background <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;DarkRed&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>If the custom icon is placed inside task dates on the timeline, its color must be taken from the parent of this task. In individual and parent tasks, the custom icon will have the color of these tasks.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">else<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp;<span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">parent<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp;<span class=\"kw1\">const<\/span> parent <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">getTask<\/span><span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">parent<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp;background <span class=\"sy0\">=<\/span> parent.<span class=\"me1\">color<\/span> <span class=\"sy0\">||<\/span> background<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp;<span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp;<span class=\"kw1\">else<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp;background <span class=\"sy0\">=<\/span> task.<span class=\"me1\">color<\/span> <span class=\"sy0\">||<\/span> background<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp;<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>After that, set the icon color using styles and attach it to the main element of the additional layer for the task:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">el.<span class=\"me1\">style<\/span>.<span class=\"me1\">background<\/span> <span class=\"sy0\">=<\/span> background<span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">style<\/span>.<span class=\"me1\">color<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;#eee&quot;<\/span><br \/>\n<br \/>\nmainEl.<span class=\"me1\">appendChild<\/span><span class=\"br0\">&#40;<\/span>el<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>To make the custom icon look somehow different from the taskbar, we added a style rule to make colors more saturated:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">filter<span class=\"sy0\">:<\/span> saturate<span class=\"br0\">&#40;<\/span><span class=\"nu0\">180<\/span><span class=\"sy0\">%<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>This way, it won&#8217;t affect the text color if it&#8217;s white, black, or gray.<\/p>\n<p>Then, you have to add an event handler for the <strong>onEmptyClick<\/strong> event. This event is called when clicking on any timeline cell as well as on any point of the roadmap interface without elements associated with tasks such as taskbars and task rows.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">attachEvent<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;onEmptyClick&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span>e<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><\/div><\/div>\n<p>At first, try to get a task row or a custom icon element using the <strong>closest()<\/strong> method:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> taskRow <span class=\"sy0\">=<\/span> e.<span class=\"me1\">target<\/span>.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.gantt_task_row&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> customElement <span class=\"sy0\">=<\/span> e.<span class=\"me1\">target<\/span>.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.work_item&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The click position relative to the timeline is saved to a variable.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> position <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">utils<\/span>.<span class=\"me1\">dom<\/span>.<span class=\"me1\">getRelativeEventPosition<\/span><span class=\"br0\">&#40;<\/span>e<span class=\"sy0\">,<\/span> gantt.$task_data<span class=\"br0\">&#41;<\/span>.<span class=\"me1\">x<\/span><\/div><\/div>\n<p>After clicking on the task row or custom icon, you get the task ID from the HTML element and then the task itself using the <strong>getTask()<\/strong> method.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> taskId <span class=\"sy0\">=<\/span> targetElement.<span class=\"me1\">dataset<\/span>.<span class=\"me1\">taskId<\/span> <span class=\"sy0\">||<\/span> targetElement.<span class=\"me1\">dataset<\/span>.<span class=\"me1\">taskid<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> task <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">getTask<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>After that, it is necessary to get the timeline date for the click position using the <strong>dateFromPos()<\/strong> method. Dates come with a time parameter, so it will be more convenient to round time to the start of the day using the <strong>gantt.date.day_start()<\/strong> method. This step makes it easier to iterate through date elements in the <strong>addTaskLayer()<\/strong> method.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> clickDate <span class=\"sy0\">=<\/span> <span class=\"sy0\">+<\/span>gantt.<span class=\"me1\">date<\/span>.<span class=\"me1\">day_start<\/span><span class=\"br0\">&#40;<\/span>gantt.<span class=\"me1\">dateFromPos<\/span><span class=\"br0\">&#40;<\/span>position<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<h6>Custom Dialog Window for Work Items<\/h6>\n<p>In custom icons for work items, it is possible to change the displayed numeric value on the fly. To do that, it is necessary to click on the needed icon and introduce the necessary changes in the opened dialog window with the help of three buttons. So let us explain to you how to implement this functionality. <\/p>\n<p>You\u2019ll need to use  the <strong>modalbox()<\/strong> method to show a custom dialog window. Here you should specify an input element with the type &#8220;number&#8221; to make it more convenient to set values. This window also includes buttons for saving and canceling changes, as well as for deleting icon values and icons themselves.<\/p>\n<p>Save the dialog window to a variable to be able to access it later and get the value from the HTML element without seeing the dialog window on the screen.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">let modalbox <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">modalbox<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; title<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Work Item&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; text<span class=\"sy0\">:<\/span> `<span class=\"sy0\">&lt;<\/span>div<span class=\"sy0\">&gt;&lt;<\/span>label<span class=\"sy0\">&gt;<\/span>Value<span class=\"sy0\">:<\/span> <span class=\"sy0\">&lt;<\/span>input type<span class=\"sy0\">=<\/span><span class=\"st0\">'number'<\/span> min<span class=\"sy0\">=<\/span><span class=\"nu0\">0<\/span> <span class=\"kw5\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">'items_value'<\/span> <span class=\"sy0\">\/&gt;&lt;\/<\/span>label<span class=\"sy0\">&gt;&lt;\/<\/span>div<span class=\"sy0\">&gt;<\/span>`<span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; buttons<span class=\"sy0\">:<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Save&quot;<\/span><span class=\"sy0\">,<\/span> css<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;items_button&quot;<\/span><span class=\"sy0\">,<\/span> value<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;save&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Cancel&quot;<\/span><span class=\"sy0\">,<\/span> css<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;items_button&quot;<\/span><span class=\"sy0\">,<\/span> value<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;cancel&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Delete&quot;<\/span><span class=\"sy0\">,<\/span> css<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;items_button&quot;<\/span><span class=\"sy0\">,<\/span> value<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;delete&quot;<\/span> <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span><\/div><\/div>\n<p>After the dialog window appears on the screen, you should set the value from the task properties. If the task has no value for a given date, it will be set to 0.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">modalbox.<span class=\"me1\">querySelector<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.items_value&quot;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">value<\/span> <span class=\"sy0\">=<\/span> task.<span class=\"me1\">items<\/span><span class=\"br0\">&#91;<\/span>clickDate<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">||<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>In the <strong>callback()<\/strong> method, it is necessary to specify what should happen after each button in the dialog window of the custom icon is clicked:<\/p>\n<ul>\n<li>save &#8211; get the value from the HTML element and add\/update that value for the custom icon date;<\/li>\n<li>delete &#8211; check if the task has a value for the custom icon date and if so, delete this value;<\/li>\n<li>cancel &#8211; there is no specified logic for this button in our sample, but we still included it in the code to make it easier for you to implement your logic here.<\/li>\n<\/ul>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">callback<span class=\"sy0\">:<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span>result<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">switch<\/span> <span class=\"br0\">&#40;<\/span>result<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">case<\/span> <span class=\"st0\">&quot;save&quot;<\/span><span class=\"sy0\">:<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> newValue <span class=\"sy0\">=<\/span> modalbox.<span class=\"me1\">querySelector<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.items_value&quot;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">value<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; task.<span class=\"me1\">items<\/span><span class=\"br0\">&#91;<\/span>clickDate<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">=<\/span> <span class=\"sy0\">+<\/span>newValue<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gantt.<span class=\"me1\">updateTask<\/span><span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">id<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">break<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">case<\/span> <span class=\"st0\">&quot;cancel&quot;<\/span><span class=\"sy0\">:<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">break<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">case<\/span> <span class=\"st0\">&quot;delete&quot;<\/span><span class=\"sy0\">:<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">items<\/span><span class=\"br0\">&#91;<\/span>clickDate<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">delete<\/span> task.<span class=\"me1\">items<\/span><span class=\"br0\">&#91;<\/span>clickDate<span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gantt.<span class=\"me1\">updateTask<\/span><span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">id<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">break<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<h6>Custom Grid Columns<\/h6>\n<p>The grid section of the roadmap also includes several columns that should be explained from the programming perspective. We are talking about 3 columns &#8211; Items, Story Points, and Status.<\/p>\n<p>We start with the &#8220;Items&#8221; column. The total number of work items for each task can be found  in the corresponding grid column. These values are displayed thanks to the use of the <strong>template<\/strong> function in the column configuration. It should be mentioned that there is a dependence on values in the &#8220;Story Points&#8221; column. Tasks without story points should also have 0 work items.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;items&quot;<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Items&quot;<\/span><span class=\"sy0\">,<\/span> align<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;center&quot;<\/span><span class=\"sy0\">,<\/span> width<span class=\"sy0\">:<\/span> <span class=\"nu0\">40<\/span><span class=\"sy0\">,<\/span> resize<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span> template<span class=\"sy0\">:<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span>task<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; let total <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">story_points<\/span> <span class=\"sy0\">&amp;&amp;<\/span> task.<span class=\"me1\">items<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span>item <span class=\"kw1\">in<\/span> task.<span class=\"me1\">items<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; total <span class=\"sy0\">+=<\/span> task.<span class=\"me1\">items<\/span><span class=\"br0\">&#91;<\/span>item<span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> total<span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>To simplify the editing of story points, you need to add an inline editor to the corresponding grid column.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> storyPointsEditor <span class=\"sy0\">=<\/span> <span class=\"br0\">&#123;<\/span> type<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;number&quot;<\/span><span class=\"sy0\">,<\/span> map_to<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;story_points&quot;<\/span><span class=\"sy0\">,<\/span> min<span class=\"sy0\">:<\/span> <span class=\"nu0\">0<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">;<\/span><br \/>\n...<br \/>\n<span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp;name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;story_points&quot;<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Story Points&quot;<\/span><span class=\"sy0\">,<\/span> align<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;center&quot;<\/span><span class=\"sy0\">,<\/span> width<span class=\"sy0\">:<\/span> <span class=\"nu0\">40<\/span><span class=\"sy0\">,<\/span> resize<span class=\"sy0\">:<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span> editor<span class=\"sy0\">:<\/span> storyPointsEditor<span class=\"sy0\">,<\/span> template<span class=\"sy0\">:<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span>task<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class=\"kw1\">return<\/span> task.<span class=\"me1\">story_points<\/span> <span class=\"sy0\">||<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span> <br \/>\n&nbsp; &nbsp; &nbsp;<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><\/div><\/div>\n<p>The &#8220;Status&#8221; column in the roadmap grid shows the progress bar for tasks. This parameter can be changed on the fly by clicking on the required status option. Status data is stored in a separate array:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">serverList<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;status&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> key<span class=\"sy0\">:<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Pending&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> key<span class=\"sy0\">:<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Ready to Start&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> key<span class=\"sy0\">:<\/span> <span class=\"nu0\">2<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;In Progress&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> key<span class=\"sy0\">:<\/span> <span class=\"nu0\">3<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Done&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> key<span class=\"sy0\">:<\/span> <span class=\"nu0\">4<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;On Review&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#123;<\/span> key<span class=\"sy0\">:<\/span> <span class=\"nu0\">5<\/span><span class=\"sy0\">,<\/span> label<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;Accepted&quot;<\/span> <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The lightbox configuration has a standard section (i.e. this type of section is available in Gantt) with the &#8220;select&#8221; type, where the list of status options is specified. The list is taken from the array <strong>gantt.serverList(&#8220;status&#8221;)<\/strong>.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp;name<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;status&quot;<\/span><span class=\"sy0\">,<\/span> height<span class=\"sy0\">:<\/span> <span class=\"nu0\">22<\/span><span class=\"sy0\">,<\/span> map_to<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;status&quot;<\/span><span class=\"sy0\">,<\/span> type<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;select&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp;options<span class=\"sy0\">:<\/span> gantt.<span class=\"me1\">serverList<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;status&quot;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><\/div><\/div>\n<p>To show custom status values in the grid, you\u2019ll have to use the template option in the column configuration. Then add the main HTML element, where all other elements should be placed. The textual status is shown at the top of the cell.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">let statusName <span class=\"sy0\">=<\/span> byId<span class=\"br0\">&#40;<\/span>gantt.<span class=\"me1\">serverList<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'status'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> task.<span class=\"me1\">status<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\nlet html <span class=\"sy0\">=<\/span> `<span class=\"sy0\">&lt;<\/span>div <span class=\"kw5\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;status_column&quot;<\/span><span class=\"sy0\">&gt;&lt;<\/span>div <span class=\"kw5\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;status_name&quot;<\/span><span class=\"sy0\">&gt;<\/span>$<span class=\"br0\">&#123;<\/span>statusName<span class=\"br0\">&#125;<\/span><span class=\"sy0\">&lt;\/<\/span>div<span class=\"sy0\">&gt;&lt;<\/span>div <span class=\"kw5\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;status_progress&quot;<\/span><span class=\"sy0\">&gt;<\/span>`<\/div><\/div>\n<p>When configuring tasks, you need to indicate the status value (not the status name). To match the status number and its text, apply the custom <strong>byId<\/strong> function. It helps to find the required status name by its number.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">function<\/span> byId<span class=\"br0\">&#40;<\/span>list<span class=\"sy0\">,<\/span> id<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">var<\/span> i <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span> i <span class=\"sy0\">&lt;<\/span> list.<span class=\"me1\">length<\/span><span class=\"sy0\">;<\/span> i<span class=\"sy0\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>list<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">key<\/span> <span class=\"sy0\">==<\/span> id<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">return<\/span> list<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">label<\/span> <span class=\"sy0\">||<\/span> <span class=\"st0\">&quot;&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> <span class=\"st0\">&quot;Pending&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>Each task status bears a sequential number and the quantity of colored squares is determined by this number.<\/p>\n<p>Programmatically, it is implemented in the following way:<\/p>\n<ul>\n<li>Go through all the elements of the array with statuses and each time add a square HTML element.<\/li>\n<li>Add a CSS style to the status square to color it if the status number is less or the same as the task status.<\/li>\n<\/ul>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> statuses <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">serverList<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'status'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">for<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw1\">var<\/span> i <span class=\"sy0\">=<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">;<\/span> i <span class=\"sy0\">&lt;<\/span> statuses.<span class=\"me1\">length<\/span><span class=\"sy0\">;<\/span> i<span class=\"sy0\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> item <span class=\"sy0\">=<\/span> statuses<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; let filled <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>item.<span class=\"me1\">key<\/span> <span class=\"sy0\">&lt;=<\/span> task.<span class=\"me1\">status<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; filled <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;filled&quot;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> el <span class=\"sy0\">=<\/span> `<span class=\"sy0\">&lt;<\/span>div <span class=\"kw5\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;bar ${filled}&quot;<\/span> data<span class=\"sy0\">-<\/span>status<span class=\"sy0\">=<\/span>$<span class=\"br0\">&#123;<\/span>item.<span class=\"me1\">key<\/span><span class=\"br0\">&#125;<\/span><span class=\"sy0\">&gt;&lt;\/<\/span>div<span class=\"sy0\">&gt;<\/span>`<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; html <span class=\"sy0\">+=<\/span> el<span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>Use the <strong>onTaskClick<\/strong> event handler to make the status task change after clicks on squares in the status column:<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">attachEvent<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;onTaskClick&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span>id<span class=\"sy0\">,<\/span> e<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><\/div><\/div>\n<p>In square elements, it is necessary to take the status number from the HTML element and change the status of the task object. After that, the task should be updated for rendering the changes. Finally, you need to return <em>false<\/em> so that the <strong>onTaskClick<\/strong> event does not fire when the task status changes. Otherwise, Gantt will select the task from the clicked line and the previous task will no longer be selected.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> statusBar <span class=\"sy0\">=<\/span> e.<span class=\"me1\">target<\/span>.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.status_progress .bar&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>statusBar<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> task <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">getTask<\/span><span class=\"br0\">&#40;<\/span>id<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; task.<span class=\"me1\">status<\/span> <span class=\"sy0\">=<\/span> statusBar.<span class=\"me1\">dataset<\/span>.<span class=\"me1\">status<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; gantt.<span class=\"me1\">updateTask<\/span><span class=\"br0\">&#40;<\/span>id<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"kw1\">return<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<h6>Custom Timeline Resizer<\/h6>\n<p>There is also a double-sided resizer on top of the roadmap that can be used to change the displayed date range. The roadmap includes a date range for tasks and a displayed date range. They are not the same thing. The range of task dates depends on loaded tasks and changes depending on task dates. By default, the displayed date range is not specified and depends on task dates. But if you set your date range, it will remain the same until you change it.<\/p>\n<p>Now we should say a couple of words about the structure of HTML elements for date ranges in the resizer. In the background, there is an element for showing the total range of task dates. In the foreground, you can see two round elements that serve as resizers. Between these two elements, we used another element that highlights the displayed date range relative to the task date range.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"sy0\">&lt;<\/span>div <span class=\"kw5\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;range_resizer&quot;<\/span> title<span class=\"sy0\">=<\/span><span class=\"st0\">&quot;Change the displayed date range&quot;<\/span><span class=\"sy0\">&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sy0\">&lt;<\/span>div <span class=\"kw5\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;total_range&quot;<\/span><span class=\"sy0\">&gt;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"sy0\">&lt;<\/span>div <span class=\"kw5\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;range_indicator&quot;<\/span><span class=\"sy0\">&gt;&lt;\/<\/span>div<span class=\"sy0\">&gt;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"sy0\">&lt;<\/span>div <span class=\"kw5\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;left_resizer&quot;<\/span><span class=\"sy0\">&gt;&lt;\/<\/span>div<span class=\"sy0\">&gt;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"sy0\">&lt;<\/span>div <span class=\"kw5\">class<\/span><span class=\"sy0\">=<\/span><span class=\"st0\">&quot;right_resizer&quot;<\/span><span class=\"sy0\">&gt;&lt;\/<\/span>div<span class=\"sy0\">&gt;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"sy0\">&lt;\/<\/span>div<span class=\"sy0\">&gt;<\/span><br \/>\n<span class=\"sy0\">&lt;\/<\/span>div<span class=\"sy0\">&gt;<\/span><\/div><\/div>\n<p>To make these elements manageable, you have to add event handlers to the <strong>window<\/strong> object. Upon clicking on the mouse button, event handlers check if the mouse is over the left or right resizer. If so, the resizer element is saved in the <strong>resizeElement<\/strong> variable.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">window.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'mousedown'<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span>e<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">const<\/span> element <span class=\"sy0\">=<\/span> e.<span class=\"me1\">target<\/span>.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.left_resizer&quot;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">||<\/span> e.<span class=\"me1\">target<\/span>.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.right_resizer&quot;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>element<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; resizeElement <span class=\"sy0\">=<\/span> element<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>After the mouse button is released, the variable must be reset so that nothing else changes when the mouse pointer is moved.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">window.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'mouseup'<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span>e<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; resizeElement <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The main action takes place inside the <strong>mousemove<\/strong> event if the resizer element is stored in a variable. First, you need to add two constants for specifying half the width of the resizer element (resizerWidth) and the left\/right indents (margin).<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">window.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'mousemove'<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span> <span class=\"br0\">&#40;<\/span>e<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>resizeElement<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> resizerWidth <span class=\"sy0\">=<\/span> <span class=\"nu0\">8<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">const<\/span> margin <span class=\"sy0\">=<\/span> <span class=\"nu0\">10<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Then, add half the width of the resizer to the variable with the new element position. Thus, the element will be positioned in the center (not on the right) when the mouse is moved.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">let newPosition <span class=\"sy0\">=<\/span> e.<span class=\"me1\">pageX<\/span> <span class=\"sy0\">-<\/span> resizerWidth<span class=\"sy0\">;<\/span><\/div><\/div>\n<p>After that, you receive HTML elements of two resizers and the date range for tasks as well as their coordinates.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> totalRange <span class=\"sy0\">=<\/span> document.<span class=\"me1\">querySelector<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.total_range&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> leftResizer <span class=\"sy0\">=<\/span> document.<span class=\"me1\">querySelector<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.left_resizer&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> rightResizer <span class=\"sy0\">=<\/span> document.<span class=\"me1\">querySelector<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.right_resizer&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">const<\/span> totalRect <span class=\"sy0\">=<\/span> totalRange.<span class=\"me1\">getBoundingClientRect<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> leftRect <span class=\"sy0\">=<\/span> leftResizer.<span class=\"me1\">getBoundingClientRect<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> rightRect <span class=\"sy0\">=<\/span> rightResizer.<span class=\"me1\">getBoundingClientRect<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Then you have to modify a new resizer\u2019s position depending on the coordinates and the type of resizer (left or right). Resizers should not extend beyond the date range element and should be placed correctly relative to each other.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>resizeElement.<span class=\"me1\">className<\/span> <span class=\"sy0\">==<\/span> <span class=\"st0\">&quot;left_resizer&quot;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>newPosition <span class=\"sy0\">&lt;<\/span> totalRect.<span class=\"me1\">x<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; newPosition <span class=\"sy0\">=<\/span> totalRect.<span class=\"me1\">x<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>newPosition <span class=\"sy0\">+<\/span> resizerWidth <span class=\"sy0\">&gt;=<\/span> rightRect.<span class=\"me1\">x<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; newPosition <span class=\"sy0\">=<\/span> rightRect.<span class=\"me1\">x<\/span> <span class=\"sy0\">-<\/span> resizerWidth<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"kw1\">else<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>newPosition <span class=\"sy0\">&gt;<\/span> totalRect.<span class=\"me1\">x<\/span> <span class=\"sy0\">+<\/span> totalRect.<span class=\"me1\">width<\/span> <span class=\"sy0\">-<\/span> resizerWidth <span class=\"sy0\">*<\/span> <span class=\"nu0\">2<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; newPosition <span class=\"sy0\">=<\/span> totalRect.<span class=\"me1\">x<\/span> <span class=\"sy0\">+<\/span> totalRect.<span class=\"me1\">width<\/span> <span class=\"sy0\">-<\/span> resizerWidth <span class=\"sy0\">*<\/span> <span class=\"nu0\">2<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>newPosition <span class=\"sy0\">-<\/span> resizerWidth <span class=\"sy0\">&lt;=<\/span> leftRect.<span class=\"me1\">x<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; newPosition <span class=\"sy0\">=<\/span> leftRect.<span class=\"me1\">x<\/span> <span class=\"sy0\">+<\/span> resizerWidth<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>Add a new coordinate to the resizer that is being dragged.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">resizeElement.<span class=\"me1\">style<\/span>.<span class=\"me1\">left<\/span> <span class=\"sy0\">=<\/span> newPosition <span class=\"sy0\">+<\/span> <span class=\"st0\">&quot;px&quot;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Set the coordinates for the indicator element of the displayed resizer\u2019s date range.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> rangeIndicator <span class=\"sy0\">=<\/span> document.<span class=\"me1\">querySelector<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.range_indicator&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\nrangeIndicator.<span class=\"me1\">style<\/span>.<span class=\"me1\">left<\/span> <span class=\"sy0\">=<\/span> leftResizer.<span class=\"me1\">offsetLeft<\/span> <span class=\"sy0\">+<\/span> margin <span class=\"sy0\">+<\/span> <span class=\"st0\">&quot;px&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\nrangeIndicator.<span class=\"me1\">style<\/span>.<span class=\"me1\">width<\/span> <span class=\"sy0\">=<\/span> rightResizer.<span class=\"me1\">offsetLeft<\/span> <span class=\"sy0\">-<\/span> leftResizer.<span class=\"me1\">offsetLeft<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">&quot;px&quot;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The next step is to correlate the coordinates of two resizers with the roadmap data. Here you should get the range of task dates and count the duration in days within this range.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> range <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">getSubtaskDates<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> rangeDuration <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">calculateDuration<\/span><span class=\"br0\">&#40;<\/span>range.<span class=\"me1\">start_date<\/span><span class=\"sy0\">,<\/span> range.<span class=\"me1\">end_date<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Now we should mention the logic used for converting values. For the left resizer, you should take its coordinate along the x-axis (<strong>offsetLeft<\/strong>) and subtract the left margin. The result value should be divided by the duration of the date range for tasks and multiplied by the width of the element indicating the date range for tasks. A similar logic is applied for the right resizer, only you have to add the margin instead of subtracting it.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">const<\/span> leftPos <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">round<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#40;<\/span>leftResizer.<span class=\"me1\">offsetLeft<\/span> <span class=\"sy0\">-<\/span> margin<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">\/<\/span> totalRect.<span class=\"me1\">width<\/span> <span class=\"sy0\">*<\/span> rangeDuration<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">const<\/span> rightPos <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">round<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#40;<\/span>rightResizer.<span class=\"me1\">offsetLeft<\/span> <span class=\"sy0\">+<\/span> margin<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">\/<\/span> totalRect.<span class=\"me1\">width<\/span> <span class=\"sy0\">*<\/span> rangeDuration<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The results will be numbers of days that must be added to the start date of the task date range. You have to add these values to the <strong>start_date<\/strong> and <strong>end_date<\/strong> configs. To repaint changes, you\u2019ll need the <strong>render()<\/strong> method.<\/p>\n<div class=\"codecolorer-container javascript default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">start_date<\/span> <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">date<\/span>.<span class=\"me1\">add<\/span><span class=\"br0\">&#40;<\/span>range.<span class=\"me1\">start_date<\/span><span class=\"sy0\">,<\/span> leftPos<span class=\"sy0\">,<\/span> <span class=\"st0\">&quot;day&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\ngantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">end_date<\/span> <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">date<\/span>.<span class=\"me1\">add<\/span><span class=\"br0\">&#40;<\/span>range.<span class=\"me1\">start_date<\/span><span class=\"sy0\">,<\/span> rightPos<span class=\"sy0\">,<\/span> <span class=\"st0\">&quot;day&quot;<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<br \/>\ngantt.<span class=\"me1\">render<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><\/div><\/div>\n<p>These are the main steps that will allow you to build a Jira-like roadmap similar to our <a href=\"https:\/\/snippet.dhtmlx.com\/pjiegd1q?mode=wide\" rel=\"noopener\" target=\"_blank\">sample<\/a>.<\/p>\n<h5>Final Words<\/h5>\n<p>As you can see, DHTMLX Gantt is well-suited for building project roadmaps that look like popular ready-made planning tools. Enhanced customization capabilities of our JavaScript library enable you to implement various custom elements, making it much easier to meet any project requirements related to the roadmap appearance. If you want to test DHTMLX Gantt in your project, download a <a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxGantt\/download.shtml\" rel=\"noopener\" target=\"_blank\">free 30-day trial version<\/a>.<\/p>\n<p>We invite you to share with us your customization scenario and we might choose it for one of our future articles of the series.<\/p>\n<h5>Related Materials:<\/h5>\n<ul>\n<li><a href=\"https:\/\/dhtmlx.com\/blog\/deep-dhtmlx-gantt-customization-project-roadmap-split-tasks-milestones-organized-via-swimlanes\/\" rel=\"noopener\" target=\"_blank\">Deep DHTMLX Gantt Customization: Project Roadmap with Split Tasks and Milestones Organized via Swimlanes<\/a><\/li>\n<li><a href=\"https:\/\/dhtmlx.com\/blog\/deep-dhtmlx-gantt-customization-tasks-month-marker-grid\/\" rel=\"noopener\" target=\"_blank\">Deep DHTMLX Gantt Customization: New Looks of Tasks, Month Marker, and Customized Grid<\/a><\/li>\n<li><a href=\"https:\/\/snippet.dhtmlx.com\/eq70o558?tag=gantt&#038;mode=wide\" rel=\"noopener\" target=\"_blank\">200+ Code Snippets with DHTMLX Gantt<\/a><\/li>\n<li><a href=\"https:\/\/docs.dhtmlx.com\/gantt\/\" rel=\"noopener\" target=\"_blank\">DHTMLX Gantt Documentation<\/a><\/li>\n<li><a href=\"https:\/\/docs.dhtmlx.com\/gantt\/demos\/\" rel=\"noopener\" target=\"_blank\">100+ DHTMLX Gantt Samples<\/a><\/li>\n<li><a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxGantt\/download.shtml\" rel=\"noopener\" target=\"_blank\">30-day Free Trial Version<\/a><\/li>\n","protected":false},"excerpt":{"rendered":"<p>When using DHTMLX Gantt in web projects, developers frequently have to meet various requirements related to the UI appearance. So they must be sure of the customization capabilities of &#8230;<\/p>\n","protected":false},"author":101014,"featured_media":11885,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[71],"tags":[33,20],"class_list":["post-11883","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-all-posts","tag-gantt"],"_links":{"self":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/11883","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/users\/101014"}],"replies":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/comments?post=11883"}],"version-history":[{"count":17,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/11883\/revisions"}],"predecessor-version":[{"id":15884,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/11883\/revisions\/15884"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media\/11885"}],"wp:attachment":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media?parent=11883"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/categories?post=11883"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/tags?post=11883"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}