How to use gantt in react app

Hello webix_B_123,

I want to filter the tasks based on the search input , so that only matching tasks are visible, and still keep the highlighting as shown in the example.

To filter the tasks based on the search input and keep the highlighting you need to apply the custom filter function from the customized Local class( row 147):

local.filter("#text#",value);

Also you can configure filtering with filterMode setting of the Tasks collection. You can define it in the default init function of the customized TreeView class (row 64):

   const tasks = this.Local.tasks();

      tasks.define({
        filterMode: {
          showSubItems: false,
        }
      });

Please check the example: Code Snippet

1. Refreshing Gantt without Recreating

If you want to reload the data at any moment - the reload method will work.
If it’s necessary not just to refresh but to change the data source URL, then the url method in the Backend Service needs to be customized additionally:

class Backend extends gantt.services.Backend {
    /**
     * Returns absolute url based on relative one
     * @param {string} path - relative url, e.g. "tasks", "links"
     * @returns {string} absolute url, e.g. "https://docs.webix.com/gantt-backend/tasks"
     */
    url(path) {
      // this._url is an initial url in Gantt confic, you can replace it here
      return this._url + path;
    }
  }

Please check the example: Code Snippet

2. Calling Custom Save API on Add/Edit/Delete

Applying url property you can define your own path to load the data to the gantt. You can call custom save API on Add/Edit/Delete in the default methods of the customized MyBackend class (row 5). More detailed information about loading data into the gantt you can find here . How to customize backend service you can find here. Descriptions of the default methods and return values of the backend service are here.

Please check the example of loading data into the gantt: Code Snippet

3. Suppressing Auto API Calls (e.g., /undefinedtasks/3/position)

To use your custom API you can redefine the default reorderTask(id, config) method. But you need to take into account the parameters and returned values of this method.
In the example below row 43: Code Snippet

4. Other Auto Calls – Did I Miss Anything?

All the methods that are applyed in the gantt backend service you can find in the sources/models/Backend.js directory and in this article.

5. Customizing Tooltips

To customize or override the tooltips shown on Gantt tasks you need to override the default method GetTooltip(obj, _) of the gantt.views[‘chart/bars’] which recieves the obj parameter with task data information, _ parameter which is the translator function of jet locale plugin and returns a string with HTML content of a tooltip for tasks (row 50 ):

    GetTooltip(obj, _) {
      const parser = webix.i18n.longDateFormatStr;
      let tip = `${obj.text || _("(no title)")}<br>
<br>${_("Start date")}: ${parser(obj.start_date)}`;

      if (obj.type != "milestone") {
        tip += `<br>${_("End date")}: ${parser(obj.end_date)}
<br>${_("Lasts")} ${obj.duration} ${obj.duration > 1 ? _("days") : _("day")}`;
      }
      return tip;
    }

Please check the example: Code Snippet

6. Hiding Fields in Edit Drawer

To hide some default fields in a task editor you need to customize the gantt.views[‘task/form’] and get access to the child views of the gantt form editor in the default init function where you can hide the fields you need (row 51):

  init() {
      super.init()
      const childViews = this.Form.getChildViews()
      console.log("childViews", childViews)
      const slider = childViews[5].hide()
      const start = childViews[2].hide()
      const end = childViews[3].hide()
      }

Please check the example: Code Snippet

Many thanks for the detailed solutions for all the queries, I will implement these and get back to you if I encounter any issues.

@Natalia_Shilova @Listopad @Mari You can replicate the issue here: Code Snippet

When using the scroll-to-today functionality with zoom enabled, it does not work as expected — instead of scrolling to today, it jumps to the right end.

@Natalia_Shilova @Mari Can anyone please reply on this scroll to today issue?

To make the scroll-to-today functionality work you need to calculate the day to scroll to, based on the value of the scale, that is currently set.
In this example Code Snippet the initial value of scale includes day so we use 86400000 milliseconds (1 day) to get the coordinates of day to scroll to (row 15):

 // get X coords from scale cell position
        const x = (d - scales.start) / 86400000 * scales.cellWidth;

In the example with the scale where instead of day the month value is used you need to calculate it using 2629800000 (month in milliseconds):

// get X coords from scale cell position 
        const x = (d - scales.start) / 2629800000 * scales.cellWidth;

And also to calculate the scroll position correctly it is important to specify the scaleStart and scaleEnd properties in the gantt config:

      {
        view: "gantt",
        id: "gantt1",
        url: "https://docs.webix.com/gantt-backend/",
        override: new Map([[gantt.services.Backend, MyBackend], [gantt.views["chart/bars"], CustomBars]]),
        scaleStart: new Date(today.getFullYear(), 0, 1),
        scaleEnd: new Date(today.getFullYear(), 11, 31),
        scales: [yearScale, quarterScale, monthScale],
        scaleCellWidth: 400,
        on: {
          onInit(app) {
            const tasks = app.getService("local").tasks();
            tasks.waitData.then(() => {
              app.callEvent("chart:scroll", [today])
            });
          } 
        },
      }

Plsease check the example: Code Snippet

Thanks @Natalia_Shilova for the solution, I will check and let you know

Why are scale_start and scale_end mandatory?
In our case, the Gantt chart start and end dates are dynamic — they depend on the entire dataset.
Determining these dates is not straightforward; we would need to perform multiple loops over the data to calculate the overall start and end range.

may I know, any in build methods there to get start end dates of gantt?

I think we are already setting scale start and end dates dynamically in the code.


import * as webix from '@xbs/webix-pro';
import {
  yearScale,
  quarterScale,
  monthScale,
  weekScale,
  dayScale,
  hourScale,
  cellWidths,
} from './scales';
import { focusOnTodayInGantt } from '../TimelinesGantt';
import { WebixGantt } from '../../types/gantt.types';

let originalStartDate: Date | null = null;
let originalEndDate: Date | null = null;

type ScaleType = 'year' | 'quarter' | 'month' | 'week' | 'day' | 'hour';

function resetScales(
  newScaleType: ScaleType,
  previousScaleType: ScaleType,
  gantt: WebixGantt
): void {
  const current = gantt.getService('local').getScales();

  if (!(originalEndDate || originalStartDate)) {
    originalStartDate = webix.Date.add(
      current.start,
      1,
      previousScaleType,
      true
    );
    originalEndDate = webix.Date.add(current.end, -1, previousScaleType, true);
  }

  const cellWidth = cellWidths[newScaleType];
  const scales = getScales(newScaleType);

  const start = webix.Date.add(
    originalStartDate as Date,
    -1,
    newScaleType,
    true
  );
  const end = webix.Date.add(originalEndDate as Date, 1, newScaleType, true);

  gantt
    .getService('local')
    .setScales(
      start,
      end,
      !(newScaleType === 'day'),
      cellWidth,
      current.cellHeight,
      scales
    );
  focusOnTodayInGantt(gantt.$app);
}

function getScales(minScale: ScaleType): unknown[] {
  const scales = [x];
  switch (minScale) {
    case 'year':
      scales.push(yearScale);
      break;
    case 'quarter':
      scales.push(yearScale, quarterScale);
      break;
    case 'month':
      scales.push(yearScale, quarterScale, monthScale);
      break;
    case 'week':
      scales.push(quarterScale, monthScale, weekScale);
      break;
    case 'day':
      scales.push(yearScale, monthScale, dayScale);
      break;
    case 'hour':
      scales.push(monthScale, dayScale, hourScale);
      break;
  }
  return scales;
}

export { resetScales };
export type { ScaleType };

@Natalia_Shilova This solution works fine, thanks.