{"id":9017,"date":"2021-07-08T13:00:46","date_gmt":"2021-07-08T10:00:46","guid":{"rendered":"https:\/\/dhtmlx.com\/blog\/?p=9017"},"modified":"2026-09-15T14:20:33","modified_gmt":"2026-09-15T11:20:33","slug":"custom-content-timeline-javascript-gantt-part-2","status":"publish","type":"post","link":"https:\/\/dhtmlx.com\/blog\/custom-content-timeline-javascript-gantt-part-2\/","title":{"rendered":"Custom Content in the Timeline of JavaScript Gantt (Part 2)"},"content":{"rendered":"<p>It is time to continue our quest for discovering the powerful customization capabilities of DHTMLX Gantt. <a href=\"https:\/\/dhtmlx.com\/blog\/custom-content-timeline-javascript-gantt-part-1\/\" rel=\"noopener\" target=\"_blank\">Last time<\/a>, we started to become familiar with the examples of using custom content in the timeline of JavaScript Gantt with the help of the <strong>addTaskLayer <\/strong> method. Now we will take a step further and explore more complex cases of enriching Gantt charts with custom elements. <\/p>\n<p>Today, you will learn how to place custom items on tasks, add a draggable baseline and insert a progress knob in it, apply custom milestones, and even take advantage of recurring events.<\/p>\n<p>Let&#8217;s get to it!<\/p>\n<h5>Custom elements on tasks<\/h5>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image2-1024x240.png\" alt=\"DHTMLX Gantt - custom content\" width=\"1024\" height=\"240\" class=\"aligncenter size-large wp-image-9019\" srcset=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image2-1024x240.png 1024w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image2-300x70.png 300w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image2-768x180.png 768w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image2.png 1072w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/> <em><a href=\"https:\/\/snippet.dhtmlx.com\/5\/0c055a26b\" rel=\"noopener\" target=\"_blank\">Check the sample ><\/a><\/em><\/p>\n<p>If it is necessary to add several custom elements for each task, you don&#8217;t have to apply multiple layers (by using <strong>addTaskLayer <\/strong>several times). Instead, it is possible to create a single HTML element and specify it after the <strong>return<\/strong> statement. You can add any number of child elements to this element.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> mainDiv <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 \/>\nmainDiv.<span class=\"me1\">className<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'icons'<\/span><br \/>\n<span class=\"co1\">\/\/generate custom elements<\/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\">0<\/span><span class=\"sy0\">;<\/span> i <span class=\"sy0\">&lt;<\/span> <span class=\"nu0\">4<\/span><span class=\"sy0\">;<\/span> i<span class=\"sy0\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; <span class=\"kw1\">var<\/span> elementDate <span class=\"sy0\">=<\/span> task<span class=\"br0\">&#91;<\/span><span class=\"st0\">'custom_element_date_'<\/span> <span class=\"sy0\">+<\/span> icons<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"sy0\">||<\/span> gantt.<span class=\"me1\">date<\/span>.<span class=\"me1\">add<\/span><span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">start_date<\/span><span class=\"sy0\">,<\/span> i<span class=\"sy0\">,<\/span> <span class=\"st0\">'day'<\/span><span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; <span class=\"kw1\">var<\/span> sizes <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">getTaskPosition<\/span><span class=\"br0\">&#40;<\/span>task<span class=\"sy0\">,<\/span> elementDate<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"kw1\">var<\/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 \/>\n&nbsp; mainDiv.<span class=\"me1\">appendChild<\/span><span class=\"br0\">&#40;<\/span>el<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span> <br \/>\n<span class=\"kw1\">return<\/span> mainDiv<span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Our goal here is to add several elements for each task. In this example, you assign the <strong>icon<\/strong> property (that is actually the element\u2019s name) to each element to make them distinguishable. This name is also used inside the <strong>class<\/strong> element to specify the <strong>font awesome<\/strong> icon.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> icons <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; <span class=\"st0\">'wrench'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; <span class=\"st0\">'eye'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; <span class=\"st0\">'check-circle-o'<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; <span class=\"st0\">'trophy'<\/span><br \/>\n<span class=\"br0\">&#93;<\/span><br \/>\n&nbsp;<br \/>\n<span class=\"kw1\">var<\/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\">setAttribute<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;data-task&quot;<\/span><span class=\"sy0\">,<\/span> task.<span class=\"me1\">id<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">setAttribute<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;data-icon&quot;<\/span><span class=\"sy0\">,<\/span> icons<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">className<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'icon fa fa-'<\/span> <span class=\"sy0\">+<\/span> icons<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>Given that each element will get different dates, you have to save these dates under the corresponding names in the <strong>task<\/strong> properties. To avoid any confusion with other properties, add <strong>custom_element_date_<\/strong> to each property name.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> elementDate <span class=\"sy0\">=<\/span> task<span class=\"br0\">&#91;<\/span><span class=\"st0\">'custom_element_date_'<\/span><span class=\"sy0\">+<\/span>icons<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"sy0\">||<\/span> gantt.<span class=\"me1\">date<\/span>.<span class=\"me1\">add<\/span><span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">start_date<\/span><span class=\"sy0\">,<\/span> i<span class=\"sy0\">,<\/span> <span class=\"st0\">'day'<\/span><span class=\"br0\">&#41;<\/span><\/div><\/div>\n<p>After that, you get a <a href=\"https:\/\/snippet.dhtmlx.com\/5\/0c055a26b\" rel=\"noopener\" target=\"_blank\">custom element with several icons<\/a> that can be placed on a project task in the timeline.<\/p>\n<h5>Drag-and-drop for custom elements<\/h5>\n<p>Before we continue exploring the following two examples of using custom content in DHTMLX Gantt, it is necessary to focus on the question of enabling drag-and-drop for custom elements. The thing is that there is no built-in function for the implementation of a custom drag-and-drop in DHTMLX Gantt. But it can be done manually and the whole process is rather simple. <\/p>\n<p>Here you need to capture three DOM events (<strong>mousedown<\/strong>, <strong>mousemove<\/strong>, <strong>mouseup<\/strong>) and define a couple of flags to store the state of drag-and-drop between these events.<\/p>\n<p>1. The <strong>mousedown<\/strong> event signals that drag-and-drop is starting. However, this may also be the first stage of a regular <strong>click<\/strong> event, which shouldn&#8217;t activate drag-and-drop. At this step, you have to set a flag, meaning that drag-and-drop is requested, and remember the initial mouse position as well as any other data that will be required later.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> dndRequested <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> dndActivated <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> startPosition <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> startTimestamp <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><br \/>\n<span class=\"kw1\">var<\/span> taskId <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> domUtils <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">utils<\/span>.<span class=\"me1\">dom<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"co1\">\/\/ in this sample we'll drag `.baseline` elements inside `gantt.$task_data` container<\/span><br \/>\ngantt.<span class=\"me1\">event<\/span><span class=\"br0\">&#40;<\/span>gantt.$task_data<span class=\"sy0\">,<\/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; <span class=\"co1\">\/\/ use element.closest or gantt.utils.dom.closest to locate the draggable element<\/span><br \/>\n&nbsp; <span class=\"kw1\">var<\/span> draggableElement <span class=\"sy0\">=<\/span> domUtils.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span>e.<span class=\"me1\">target<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">'.baseline'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp;<br \/>\n&nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>draggableElement<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ we don't know yet whether a user is going to drag the element or just click it<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ store the event info, we'll check it at 'mousemove'<\/span><br \/>\n&nbsp; &nbsp; dndRequested <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; startTimestamp <span class=\"sy0\">=<\/span> <span class=\"kw4\">Date<\/span>.<span class=\"me1\">now<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; startPosition <span class=\"sy0\">=<\/span> domUtils.<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=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; taskId <span class=\"sy0\">=<\/span> draggableElement.<span class=\"me1\">getAttribute<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;data-task&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&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>Note that the event handler is added using <strong><a href=\"https:\/\/docs.dhtmlx.com\/gantt\/api__gantt_event.html\" rel=\"noopener\" target=\"_blank\">gantt.event<\/a><\/strong> rather than native <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/EventTarget\/addEventListener\" rel=\"noopener\" target=\"_blank\">Element.addEventListener<\/a>. It is done because Gantt can be destroyed using the <strong>gantt.destructor<\/strong> method and all events attached using <strong>gantt.event<\/strong> will be cleared automatically. If you make use of the native method and <strong>gantt.destructor<\/strong>, you may need to clear event handlers manually in order to avoid memory leaks.<\/p>\n<p>2. The actual drag-and-drop will start in the <strong>mousemove<\/strong> handler. Instead of initiating drag-and-drop when a user clicks the mouse, compare the current mouse position with the initial position saved in <strong>mousedown<\/strong>. This way you can start drag-and-drop only when the current position differs enough from the initial one. If you don&#8217;t want to set a minimum threshold for drag-and-drop, you can also estimate the time passed since <strong>mousedown<\/strong>.<\/p>\n<p>Once you determine that drag-and-drop has started, you can use the <strong>mousemove<\/strong> event handler to update the position of the dragged element on the screen. If you drag a custom layer element, the expected approach for refreshing it is to modify the underlying object and repaint it using Gantt API (<strong><a href=\"https:\/\/docs.dhtmlx.com\/gantt\/api__gantt_refreshtask.html\" rel=\"noopener\" target=\"_blank\">gantt.refreshTask<\/a><\/strong>), rather than modifying the DOM element directly.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">event<\/span><span class=\"br0\">&#40;<\/span>window<span class=\"sy0\">,<\/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; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>dndRequested <span class=\"sy0\">&amp;&amp;<\/span> gantt.<span class=\"me1\">isTaskExists<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ we captured 'mousemove' after 'mousedown' event<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> currentPosition <span class=\"sy0\">=<\/span> domUtils.<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=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"sy0\">!<\/span>dndActivated<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ 'mousemove' may be a part of the regular click process, we don't want to invoke dnd on regular click<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ we check whether mouse position has changed significantly, or if the user holds a mouse longer than it usually happens for regular click &nbsp; &nbsp; &nbsp;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">Math<\/span>.<span class=\"me1\">abs<\/span><span class=\"br0\">&#40;<\/span>currentPosition.<span class=\"me1\">x<\/span> <span class=\"sy0\">-<\/span> startPosition.<span class=\"me1\">x<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">&gt;<\/span> <span class=\"nu0\">5<\/span> <span class=\"sy0\">||<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw4\">Date<\/span>.<span class=\"me1\">now<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">-<\/span> startTimestamp<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">&gt;<\/span> <span class=\"nu0\">500<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ if so - we assume dnd has started<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; dndActivated <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span> <br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>dndActivated<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ here we can update the position of the dragged element.<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ when we drag an element added via `gantt.addTaskLayer`, it's better to update the task object <\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ and repaint it via `gantt.refreshTask`<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ you can also get the corresponding date of the time scale:<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> pointerDate <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">dateFromPos<\/span><span class=\"br0\">&#40;<\/span>currentPosition.<span class=\"me1\">x<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; gantt.<span class=\"me1\">getTask<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span>.<span class=\"me1\">baseline_date<\/span> <span class=\"sy0\">=<\/span> pointerDate<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; gantt.<span class=\"me1\">refreshTask<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span> <br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp;<br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/div>\n<p>3. Finally, you should capture the <strong>mouseup<\/strong> event. If drag-and-drop has been started &#8211; apply changes to the moved object, call the <strong><a href=\"https:\/\/docs.dhtmlx.com\/gantt\/api__gantt_updatetask.html\" rel=\"noopener\" target=\"_blank\">gantt.updateTask<\/a><\/strong> method, if necessary, and clear all temporary flags.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">event<\/span><span class=\"br0\">&#40;<\/span>window<span class=\"sy0\">,<\/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; <span class=\"co1\">\/\/ apply changes if drag-and-drop was in progress<\/span><br \/>\n&nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>dndActivated<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ validate and finalize changes if needed<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/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><br \/>\n&nbsp; &nbsp; task.<span class=\"me1\">baseline_date<\/span> <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">roundDate<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; date<span class=\"sy0\">:<\/span> task.<span class=\"me1\">baseline_date<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; unit<span class=\"sy0\">:<\/span> <span class=\"st0\">&quot;hour&quot;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; step<span class=\"sy0\">:<\/span> <span class=\"nu0\">1<\/span> &nbsp; &nbsp;<br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ call gantt.updateTask to invoke the update of data &nbsp; &nbsp; <\/span><br \/>\n&nbsp; &nbsp; gantt.<span class=\"me1\">updateTask<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; <span class=\"co1\">\/\/ clear all flags we've set at previous stages<\/span><br \/>\n&nbsp; dndRequested <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; dndActivated <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; startPosition <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; startTimestamp <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; taskId <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/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>With this knowledge at hand, let us proceed to more practical cases including drag-and-drop functionality.<\/p>\n<h5>Draggable baselines<\/h5>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/draggable-baseline-1.gif\" alt=\"DHTMLX Gantt -draggable baseline in the Gantt Timeline\" width=\"922\" height=\"280\" class=\"aligncenter size-full wp-image-9048\" \/> <em><a href=\"https:\/\/snippet.dhtmlx.com\/5\/e3edf6d6b\" rel=\"noopener\" target=\"_blank\">Check the sample ><\/a><\/em><\/p>\n<p>As we\u2019ve learned from the previous section, you&#8217;ll need to write some code to make baselines draggable.<\/p>\n<p>Before implementing drag-and-drop, you need to make a small change to the <strong>addTaskLayer<\/strong> function. Namely, you have to add an ID of a related task to attributes of a rendered baseline element. Use this attribute in the <strong>mousedown<\/strong> handler to find out to which task the baseline belongs to.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/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\">setAttribute<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;data-task&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>Now, you can get to the actual implementation. The <strong>mousedown<\/strong> handler will look very similar to the one we had in the example above. However, there is an important difference &#8211; a baseline is an element with variable width. A user can start drag-and-drop from any point of the bar and the baseline should be moved smoothly regardless of the initial cursor position. <\/p>\n<p>You don&#8217;t want to assign a start date of the baseline to a cursor position, since the user may start drag-and-drop by pointing to the middle of the bar. In such a case, the start date of baseline will immediately jump to the pointer position. Instead, when drag-and-drop starts, you can remember the horizontal distance from the left edge of the baseline bar to the cursor position &#8211; this is the position of the start date of baseline relative to the pointer position. Then, when you need to calculate the new start date of the baseline, you calculate it as follows:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">dateFromPos<\/span><span class=\"br0\">&#40;<\/span>mousePosition.<span class=\"me1\">x<\/span> <span class=\"sy0\">-<\/span> clickOffset<span class=\"br0\">&#41;<\/span>.<\/div><\/div>\n<p>Pay attention to the <strong>clickOffset<\/strong> variable:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> domUtils <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">utils<\/span>.<span class=\"me1\">dom<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> taskId <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> clickOffset <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> dndRequested <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> dndActivated <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> startTimestamp <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> startPosition <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp;<br \/>\ngantt.<span class=\"me1\">event<\/span><span class=\"br0\">&#40;<\/span>gantt.$task_data<span class=\"sy0\">,<\/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> &nbsp;<br \/>\n&nbsp; <span class=\"kw1\">var<\/span> draggableElement <span class=\"sy0\">=<\/span> domUtils.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span>e.<span class=\"me1\">target<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">'.baseline'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>draggableElement<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; taskId <span class=\"sy0\">=<\/span> draggableElement.<span class=\"me1\">getAttribute<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;data-task&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; clickOffset <span class=\"sy0\">=<\/span> domUtils.<span class=\"me1\">getRelativeEventPosition<\/span><span class=\"br0\">&#40;<\/span>e<span class=\"sy0\">,<\/span> draggableElement<span class=\"br0\">&#41;<\/span>.<span class=\"me1\">x<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp;<br \/>\n&nbsp; &nbsp; dndRequested <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; startTimestamp <span class=\"sy0\">=<\/span> <span class=\"kw4\">Date<\/span>.<span class=\"me1\">now<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; startPosition <span class=\"sy0\">=<\/span> domUtils.<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=\"sy0\">;<\/span><br \/>\n&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>In the <strong>mousemove<\/strong> event handler, you obtain the mouse position and calculate the date of the baseline.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">event<\/span><span class=\"br0\">&#40;<\/span>window<span class=\"sy0\">,<\/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; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>dndRequested <span class=\"sy0\">&amp;&amp;<\/span> gantt.<span class=\"me1\">isTaskExists<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp;<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> position <span class=\"sy0\">=<\/span> domUtils.<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><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"sy0\">!<\/span>dndActivated<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">Math<\/span>.<span class=\"me1\">abs<\/span><span class=\"br0\">&#40;<\/span>position <span class=\"sy0\">-<\/span> startPosition.<span class=\"me1\">x<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">&gt;<\/span> <span class=\"nu0\">2<\/span> <span class=\"sy0\">||<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw4\">Date<\/span>.<span class=\"me1\">now<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">-<\/span> startTimestamp<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">&gt;<\/span> <span class=\"nu0\">500<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; dndActivated <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp;<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>dndActivated<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/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><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> plannedDuration <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">calculateDuration<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; start_date<span class=\"sy0\">:<\/span> task.<span class=\"me1\">planned_start<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; end_date<span class=\"sy0\">:<\/span> task.<span class=\"me1\">planned_end<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; task<span class=\"sy0\">:<\/span> task<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp;<br \/>\n&nbsp; &nbsp; &nbsp; task.<span class=\"me1\">planned_start<\/span> <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">dateFromPos<\/span><span class=\"br0\">&#40;<\/span>position <span class=\"sy0\">-<\/span> clickOffset<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; task.<span class=\"me1\">planned_end<\/span> <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">calculateEndDate<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; start_date<span class=\"sy0\">:<\/span> task.<span class=\"me1\">planned_start<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; duration<span class=\"sy0\">:<\/span> plannedDuration<span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; task<span class=\"sy0\">:<\/span> task<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; gantt.<span class=\"me1\">refreshTask<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&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>The <strong>mouseup<\/strong> event handler looks exactly the same as in the previous example. You just need to submit the changes and reset all temporary variables:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">event<\/span><span class=\"br0\">&#40;<\/span>window<span class=\"sy0\">,<\/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> &nbsp; <br \/>\n&nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>dndActivated<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; gantt.<span class=\"me1\">updateTask<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp;<br \/>\n&nbsp; taskId <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; clickOffset <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; dndRequested <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; dndActivated <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; startTimestamp <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; startPosition <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/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>As a result, you get a <a href=\"https:\/\/snippet.dhtmlx.com\/5\/e3edf6d6b\" rel=\"noopener\" target=\"_blank\">draggable baseline<\/a> that can be easily moved along the timeline with a mouse.<\/p>\n<h5>Baselines with a draggable progress knob<\/h5>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/draganddropfv.gif\" alt=\"Gantt chart baseline with a draggable progress knob\" width=\"991\" height=\"198\" class=\"aligncenter size-full wp-image-9042\" \/> <em><a href=\"https:\/\/snippet.dhtmlx.com\/5\/6fc3a9f7a\" rel=\"noopener\" target=\"_blank\">Check the sample ><\/a><\/em><\/p>\n<p>Custom baselines can also be equipped with other HTML elements such as a progress bar. It is also possible to add the ability to change and save progress values with a knob. Here you need 3 elements &#8211; baseline, progress bar, and progress knob. <\/p>\n<p>First of all, you have to add one extra property to our task object. As an example, you can call it <strong>task.baseline_progress<\/strong>. It will contain the progress value as a number between zero and one:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">task.<span class=\"me1\">baseline_progress<\/span> <span class=\"sy0\">=<\/span> <span class=\"nu0\">0.5<\/span><span class=\"sy0\">;<\/span><span class=\"co1\">\/\/ 50%<\/span><\/div><\/div>\n<p>Then you&#8217;ll be able to use it to show the progress bar of the baseline. That is how the modified <strong>gantt.addTaskLayer<\/strong> function will look like this:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/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\">setAttribute<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;data-task&quot;<\/span><span class=\"sy0\">,<\/span> task.<span class=\"me1\">id<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">className<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'baseline'<\/span><span class=\"sy0\">;<\/span><br \/>\n...<br \/>\n<span class=\"co1\">\/\/ adding progress bar<\/span><br \/>\n<span class=\"kw1\">var<\/span> progress <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 \/>\nprogress.<span class=\"me1\">className<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'baseline_progressbar'<\/span><span class=\"sy0\">;<\/span><br \/>\nprogress.<span class=\"me1\">style<\/span>.<span class=\"me1\">width<\/span> <span class=\"sy0\">=<\/span> task.<span class=\"me1\">baseline_progress<\/span> <span class=\"sy0\">*<\/span> <span class=\"nu0\">100<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">&quot;%&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">appendChild<\/span><span class=\"br0\">&#40;<\/span>progress<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"co1\">\/\/adding progress bar drag<\/span><br \/>\n<span class=\"kw1\">var<\/span> progress_drag <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 \/>\nprogress_drag.<span class=\"me1\">className<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'baseline_progress_drag'<\/span><span class=\"sy0\">;<\/span><br \/>\nprogress_drag.<span class=\"me1\">style<\/span>.<span class=\"me1\">left<\/span> <span class=\"sy0\">=<\/span> task.<span class=\"me1\">baseline_progress<\/span> <span class=\"sy0\">*<\/span> <span class=\"nu0\">100<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">&quot;%&quot;<\/span><span class=\"sy0\">;<\/span><br \/>\nel.<span class=\"me1\">appendChild<\/span><span class=\"br0\">&#40;<\/span>progress_drag<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">return<\/span> el<span class=\"sy0\">;<\/span><\/div><\/div>\n<p>The progress bar inside the baseline element is filled according to the value of the <strong>task.baseline_progress<\/strong> property. Once you implement the drag-and-drop function, it will modify the <strong>task.baseline_progress<\/strong> property when the user drags the progress knob.<\/p>\n<p>After changing the markup of the draggable element, the overall logic remains mainly the same. The draggable element is now <strong>baseline_progress_drag<\/strong>, and in order to get the ID of the task you need to traverse elements upwards until you get to the <strong>baseline<\/strong> element which stores the task\u2019s ID:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">event<\/span><span class=\"br0\">&#40;<\/span>gantt.$task_data<span class=\"sy0\">,<\/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> &nbsp;<br \/>\n&nbsp; <span class=\"kw1\">var<\/span> draggableElement <span class=\"sy0\">=<\/span> domUtils.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span>e.<span class=\"me1\">target<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">'.baseline_progress_drag'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>draggableElement<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; taskId <span class=\"sy0\">=<\/span> domUtils.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span>draggableElement<span class=\"sy0\">,<\/span> <span class=\"st0\">&quot;.baseline&quot;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">getAttribute<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;data-task&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span> &nbsp; &nbsp; &nbsp;<br \/>\n&nbsp; &nbsp; dndRequested <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; startTimestamp <span class=\"sy0\">=<\/span> <span class=\"kw4\">Date<\/span>.<span class=\"me1\">now<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; startPosition <span class=\"sy0\">=<\/span> domUtils.<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=\"sy0\">;<\/span><br \/>\n&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>It is the same story with the <strong>mousemove<\/strong> handler. The code is very similar to the previous examples.<\/p>\n<p>The new progress value can be calculated with the <strong>gantt.utils.dom.getRelativeEventPosition<\/strong> (event, node) helper &#8211; a relative position of the pointer inside the element. In other words, if the mouse pointer is in the upper left corner of the node, the <strong>{x: 0, y: 0)<\/strong> object will be returned. When the pointer is in the lower right corner, you will get <strong>{x: node.offsetWidth, y: node.offsetHeight}<\/strong> regardless of the element\u2019s position on the page.<\/p>\n<p>Using this method and the offset size of the baseline, you can determine the position of the task pointer relative to the size of the baseline element (at 0%, 50%, 90% of the full width) and calculate the percentage with the necessary precision.<\/p>\n<p>Alternatively, you could use a pointer date using <strong>gantt.dateFromPos<\/strong> and calculate the progress from the date difference between the pointer date and the start\/end dates of the baseline rather than from coordinates.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">event<\/span><span class=\"br0\">&#40;<\/span>window<span class=\"sy0\">,<\/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; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>dndRequested <span class=\"sy0\">&amp;&amp;<\/span> gantt.<span class=\"me1\">isTaskExists<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> position <span class=\"sy0\">=<\/span> domUtils.<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><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span><span class=\"sy0\">!<\/span>dndActivated<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">Math<\/span>.<span class=\"me1\">abs<\/span><span class=\"br0\">&#40;<\/span>position <span class=\"sy0\">-<\/span> startPosition.<span class=\"me1\">x<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">&gt;<\/span> <span class=\"nu0\">2<\/span> <span class=\"sy0\">||<\/span> <span class=\"br0\">&#40;<\/span><span class=\"kw4\">Date<\/span>.<span class=\"me1\">now<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">-<\/span> startTimestamp<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">&gt;<\/span> <span class=\"nu0\">500<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; dndActivated <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>dndActivated<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> baselineElement <span class=\"sy0\">=<\/span> gantt.$root.<span class=\"me1\">querySelector<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;.baseline[data-task='&quot;<\/span><span class=\"sy0\">+<\/span>taskId<span class=\"sy0\">+<\/span><span class=\"st0\">&quot;'&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/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><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> positionRelative <span class=\"sy0\">=<\/span> domUtils.<span class=\"me1\">getRelativeEventPosition<\/span><span class=\"br0\">&#40;<\/span>e<span class=\"sy0\">,<\/span> baselineElement<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> dragPos <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">max<\/span><span class=\"br0\">&#40;<\/span>positionRelative.<span class=\"me1\">x<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> fullWidth <span class=\"sy0\">=<\/span> baselineElement.<span class=\"me1\">offsetWidth<\/span> <span class=\"sy0\">||<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> computedProgress <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">min<\/span><span class=\"br0\">&#40;<\/span>dragPos<span class=\"sy0\">,<\/span> fullWidth<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">\/<\/span> fullWidth<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> roundedProgress <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">round<\/span><span class=\"br0\">&#40;<\/span>computedProgress <span class=\"sy0\">*<\/span> <span class=\"nu0\">100<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">\/<\/span> <span class=\"nu0\">100<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; task.<span class=\"me1\">baseline_progress<\/span> <span class=\"sy0\">=<\/span> roundedProgress<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; gantt.<span class=\"me1\">refreshTask<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&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>Like in the previous examples, you can use the <strong>mouseup<\/strong> event to check (via flags) if the drag-and-drop action actually happened, invoke custom functions if needed, and clear the flags.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">event<\/span><span class=\"br0\">&#40;<\/span>window<span class=\"sy0\">,<\/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> &nbsp; <br \/>\n&nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>dndActivated<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; gantt.<span class=\"me1\">updateTask<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/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><br \/>\n&nbsp; &nbsp; gantt.<span class=\"me1\">message<\/span><span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">text<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">&quot; baseline progress is now &quot;<\/span> <span class=\"sy0\">+<\/span> task.<span class=\"me1\">baseline_progress<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp;<br \/>\n&nbsp; taskId <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; dndRequested <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; dndActivated <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; startTimestamp <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; startPosition <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/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>A fancier way of calling custom functions after drag-and-drop would be to call a <a href=\"https:\/\/docs.dhtmlx.com\/gantt\/api__gantt_callevent.html\" rel=\"noopener\" target=\"_blank\">custom API event<\/a>, which you could capture in other parts of your code:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">event<\/span><span class=\"br0\">&#40;<\/span>window<span class=\"sy0\">,<\/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> &nbsp; <br \/>\n&nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>dndActivated<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ signal that baseline progress has changed<\/span><br \/>\n&nbsp; &nbsp; gantt.<span class=\"me1\">callEvent<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;onAfterBaselineProgressDrag&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#91;<\/span>taskId<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span> &nbsp; &nbsp; &nbsp;<br \/>\n&nbsp; &nbsp; gantt.<span class=\"me1\">updateTask<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; taskId <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; dndRequested <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; dndActivated <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; startTimestamp <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; startPosition <span class=\"sy0\">=<\/span> <span class=\"kw2\">null<\/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>Then, you can catch this event the following way:<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" 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;onAfterBaselineProgressDrag&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>taskId<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; <span class=\"kw1\">var<\/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><br \/>\n&nbsp; gantt.<span class=\"me1\">message<\/span><span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">text<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">&quot; baseline progress is now &quot;<\/span> <span class=\"sy0\">+<\/span> task.<span class=\"me1\">baseline_progress<\/span><span class=\"br0\">&#41;<\/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>After all these code manipulations, we\u2019ll get a <a href=\"https:\/\/snippet.dhtmlx.com\/5\/6fc3a9f7a\" rel=\"noopener\" target=\"_blank\">custom baseline<\/a> complemented with a progress bar and a knob allowing users to alter and save progress values.<\/p>\n<h5>Custom milestones<\/h5>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image4.gif\" alt=\"DHTMLX Gantt - Custom milestones\" width=\"1014\" height=\"560\" class=\"aligncenter size-full wp-image-9030\" \/> <em><a href=\"https:\/\/snippet.dhtmlx.com\/5\/c3f9c5297\" rel=\"noopener\" target=\"_blank\">Check the sample ><\/a><\/em><\/p>\n<p>If a milestone is not seen on the screen, it can be useful to draw a vertical line going up to the top to remind users about important dates on the project.<\/p>\n<p>By default, elements of an additional layer are rendered only when the taskbar, to which this element belongs, is visible on the screen. But you can use a more complex configuration of the additional layer to change it. The <strong>addTaskLayer<\/strong> method uses a function, but you can also set an object with specific parameters inside this method. In this object, you need to use the <strong>renderer<\/strong> property &#8211; an object with functions responsible for rendering elements.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">addTaskLayer<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; renderer<span class=\"sy0\">:<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; render<span class=\"sy0\">:<\/span> <span class=\"kw1\">function<\/span> draw_planned<span class=\"br0\">&#40;<\/span>task<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span> <br \/>\n&nbsp;<br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co1\">\/\/ define getRectangle in order to hook layer with smart rendering<\/span><br \/>\n&nbsp; &nbsp; getRectangle<span class=\"sy0\">:<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>task<span class=\"sy0\">,<\/span> view<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&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>The <strong>render<\/strong> is a function that helps to create custom elements, and the <strong>getRectangle<\/strong> parameter defines the position of these elements. Inside the <strong>render<\/strong> parameter, add the function for creating custom elements utilized in the previous examples. In the <strong>getRectangle<\/strong> function, you have to define the position of the task using the <strong>getTaskPosition<\/strong> method.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">render<span class=\"sy0\">:<\/span> <span class=\"kw1\">function<\/span> draw_planned<span class=\"br0\">&#40;<\/span>task<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span> <br \/>\n&nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">type<\/span> <span class=\"sy0\">==<\/span> <span class=\"st0\">'milestone'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> sizes <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">getTaskPosition<\/span><span class=\"br0\">&#40;<\/span>task<span class=\"sy0\">,<\/span> task.<span class=\"me1\">start_date<\/span><span class=\"sy0\">,<\/span> task.<span class=\"me1\">end_date<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/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 \/>\n&nbsp; &nbsp; el.<span class=\"me1\">className<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'milestoneLine'<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; 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 \/>\n&nbsp; &nbsp; el.<span class=\"me1\">style<\/span>.<span class=\"me1\">width<\/span> <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">'px'<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; el.<span class=\"me1\">style<\/span>.<span class=\"me1\">height<\/span> <span class=\"sy0\">=<\/span> sizes.<span class=\"me1\">height<\/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 \/>\n&nbsp; &nbsp; el.<span class=\"me1\">style<\/span>.<span class=\"me1\">top<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'0px'<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> el<span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; <span class=\"kw1\">return<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><span class=\"sy0\">,<\/span><\/div><\/div>\n<p>The next step is to change the parameters of the object that returns this method. You need to replace the value of the <strong>top<\/strong> parameter with <strong>0<\/strong> so that the upgoing line will start from the timeline. The height of the element is set as infinite. Since the Gantt chart consists of multiple elements, the custom element will not go outside the Gantt container.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">getRectangle<span class=\"sy0\">:<\/span> <span class=\"kw1\">function<\/span><span class=\"br0\">&#40;<\/span>task<span class=\"sy0\">,<\/span> view<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; <span class=\"kw1\">var<\/span> position <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">getTaskPosition<\/span><span class=\"br0\">&#40;<\/span>task<span class=\"sy0\">,<\/span> task.<span class=\"me1\">start_date<\/span><span class=\"sy0\">,<\/span> task.<span class=\"me1\">end_date<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; position.<span class=\"me1\">top<\/span> <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; position.<span class=\"me1\">height<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">Infinity<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"kw1\">return<\/span> position<span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/div>\n<p>As an alternative to the customization approach to adding <a href=\"https:\/\/snippet.dhtmlx.com\/5\/c3f9c5297\" rel=\"noopener\" target=\"_blank\">custom milestones<\/a> into your project described above, now you can provide a high-level project summary using rollup tasks. This feature was added to DHTMLX Gantt in the latest update (<a href=\"https:\/\/dhtmlx.com\/blog\/dhtmlx-gantt-7-1-part-time-resource-assignment-rollup-tasks\/\" rel=\"noopener\" target=\"_blank\">v7.1<\/a>). <\/p>\n<h5>Recurring tasks<\/h5>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image5-1024x233.png\" alt=\"DHTMLX Gantt - Recurring tasks in the  Gantt timeline\" width=\"1024\" height=\"233\" class=\"aligncenter size-large wp-image-9032\" srcset=\"https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image5-1024x233.png 1024w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image5-300x68.png 300w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image5-768x175.png 768w, https:\/\/dhtmlx.com\/blog\/wp-content\/uploads\/2021\/07\/image5.png 1098w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/> <em><a href=\"https:\/\/snippet.dhtmlx.com\/5\/7faa7b03a\" rel=\"noopener\" target=\"_blank\">Check the sample ><\/a><\/em><\/p>\n<p>If the project includes a range of similar tasks that must be performed at specific time intervals, you can make them recur.<\/p>\n<p>For this purpose, you have to create buttons in the grid that will allow you to add or remove recurring elements (tasks). To do this, use the <strong>template<\/strong> intended for displaying any data or HTML elements.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">config<\/span>.<span class=\"me1\">columns<\/span><span class=\"sy0\">=<\/span><span class=\"br0\">&#91;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#123;<\/span>name<span class=\"sy0\">:<\/span><span class=\"st0\">&quot;recurrency&quot;<\/span><span class=\"sy0\">,<\/span> &nbsp; label<span class=\"sy0\">:<\/span><span class=\"st0\">&quot;recurrency&quot;<\/span><span class=\"sy0\">,<\/span> width<span class=\"sy0\">:<\/span><span class=\"nu0\">70<\/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; <span class=\"kw1\">var<\/span> add <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;&lt;img class='add_recurrency' height=30 alt='v' src='https:\/\/encrypted-tbn0.gstatic.com\/images?q=tbn:ANd9GcRctAwCv6r8ffBNojuSyf2PZ5CxcDYMp6i4OxmMOiQ76S2AbPAK2g'&gt;&quot;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> remove <span class=\"sy0\">=<\/span> <span class=\"st0\">&quot;&lt;img class='remove_recurrency' height=30 alt='x' src='https:\/\/img.freepik.com\/free-vector\/letter-x-alphabet-inside-circle-icon-design_7095-384.jpg?size=338&amp;ext=jpg'&gt;&quot;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> add <span class=\"sy0\">+<\/span> remove<br \/>\n&nbsp; <span class=\"br0\">&#125;<\/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>Then add the <strong>onTaskClick<\/strong> event handler that will fire when the mouse button is pressed. It is a more preferable option to adding <strong>onclick<\/strong> events inside HTML elements in the grid, which won\u2019t work in Salesforce and other frameworks with limitations on inline functions.<\/p>\n<p>When the <strong>onTaskClick<\/strong> event gets triggered in the grid after the click, take the custom element and use the <strong>closest<\/strong> method to find out if the right element was clicked. If the element for adding recurring elements is clicked, use the built-in <strong>prompt<\/strong> method and indicate the entered value for the task. Otherwise, you have to remove this value.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" 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><br \/>\n&nbsp; <span class=\"kw1\">var<\/span> domHelpers <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">utils<\/span>.<span class=\"me1\">dom<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp;<br \/>\n&nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>domHelpers.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span>e.<span class=\"me1\">target<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">&quot;.add_recurrency&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/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\">recurrency<\/span> <span class=\"sy0\">=<\/span> prompt<span class=\"br0\">&#40;<\/span><span class=\"st0\">&quot;Enter the number of recurrency&quot;<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&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; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; <span class=\"kw1\">else<\/span> <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>domHelpers.<span class=\"me1\">closest<\/span><span class=\"br0\">&#40;<\/span>e.<span class=\"me1\">target<\/span><span class=\"sy0\">,<\/span> <span class=\"st0\">&quot;.remove_recurrency&quot;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/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\">recurrency<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&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; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; <span class=\"kw1\">return<\/span><\/div><\/div>\n<p>Check if the task has a value in the <strong>recurrency<\/strong> property of the function for adding an extra layer. If yes, depending on this value, create the number of elements for repeating the task.<\/p>\n<div class=\"codecolorer-container javascript default codecolorer-noborder\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"javascript codecolorer\">gantt.<span class=\"me1\">addTaskLayer<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw1\">function<\/span> draw_planned<span class=\"br0\">&#40;<\/span>task<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">recurrency<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> main_div <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 \/>\n&nbsp; &nbsp; main_div.<span class=\"me1\">className<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'recurring_tasks'<\/span><span class=\"sy0\">;<\/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\">1<\/span><span class=\"sy0\">;<\/span> i <span class=\"sy0\">&lt;=<\/span> task.<span class=\"me1\">recurrency<\/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; <span class=\"kw1\">var<\/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 \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> el_start_date <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">date<\/span>.<span class=\"me1\">add<\/span><span class=\"br0\">&#40;<\/span>task.<span class=\"me1\">start_date<\/span><span class=\"sy0\">,<\/span> i<span class=\"sy0\">,<\/span> <span class=\"st0\">'week'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> el_end_date <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">calculateEndDate<\/span><span class=\"br0\">&#40;<\/span>el_start_date<span class=\"sy0\">,<\/span> task.<span class=\"me1\">duration<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> sizes <span class=\"sy0\">=<\/span> gantt.<span class=\"me1\">getTaskPosition<\/span><span class=\"br0\">&#40;<\/span>task<span class=\"sy0\">,<\/span> el_start_date<span class=\"sy0\">,<\/span> el_end_date<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; el.<span class=\"me1\">className<\/span> <span class=\"sy0\">=<\/span> <span class=\"st0\">'recurring_task'<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; 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 \/>\n&nbsp; &nbsp; &nbsp; el.<span class=\"me1\">style<\/span>.<span class=\"me1\">width<\/span> <span class=\"sy0\">=<\/span> sizes.<span class=\"me1\">width<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">'px'<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; el.<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 \/>\n&nbsp; &nbsp; &nbsp; el.<span class=\"me1\">style<\/span>.<span class=\"me1\">height<\/span> <span class=\"sy0\">=<\/span> sizes.<span class=\"me1\">height<\/span> <span class=\"sy0\">+<\/span> <span class=\"st0\">'px'<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; el.<span class=\"me1\">innerHTML<\/span> <span class=\"sy0\">=<\/span> &nbsp;task.<span class=\"me1\">text<\/span><br \/>\n&nbsp; &nbsp; &nbsp; main_div.<span class=\"me1\">appendChild<\/span><span class=\"br0\">&#40;<\/span>el<span class=\"br0\">&#41;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> main_div<span class=\"sy0\">;<\/span><br \/>\n&nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; <span class=\"kw1\">return<\/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>Following these steps, you can display <a href=\"https:\/\/snippet.dhtmlx.com\/5\/7faa7b03a\" rel=\"noopener\" target=\"_blank\">recurring events<\/a> in the Gantt timeline the same way as in the DHTMLX Scheduler component.<\/p>\n<h5>Final words<\/h5>\n<p>The ability to work with custom content is really important for project managers working with Gantt charts via web apps. A range of useful examples reviewed in this and previous articles on the topic prove that DHTMLX Gantt has a lot to offer in this regard. <\/p>\n<p>If you are looking for a project management tool with enhanced customization capabilities, try DHTMLX Gantt for free by downloading a <a href=\"https:\/\/dhtmlx.com\/docs\/products\/dhtmlxGantt\/download.shtml\" rel=\"noopener\" target=\"_blank\">30-day trial version<\/a>.<\/p>\n<h5>Related materials:<\/h5>\n<ul>\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\">DHTMLX Gantt Samples<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>It is time to continue our quest for discovering the powerful customization capabilities of DHTMLX Gantt. Last time, we started to become familiar with the examples of using custom &#8230;<\/p>\n","protected":false},"author":101014,"featured_media":9018,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[71],"tags":[33,20],"class_list":["post-9017","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\/9017","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=9017"}],"version-history":[{"count":26,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/9017\/revisions"}],"predecessor-version":[{"id":15886,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/posts\/9017\/revisions\/15886"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media\/9018"}],"wp:attachment":[{"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/media?parent=9017"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/categories?post=9017"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dhtmlx.com\/blog\/wp-json\/wp\/v2\/tags?post=9017"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}