Перетаскивание задач на временной шкале

Перетаскивание облегчает изменение дат начала и окончания задач, а также их длительности.
По умолчанию функция drag-and-drop включена, что позволяет пользователям перемещать задачи по своим строкам на временной шкале.

Для настройки поведения drag-and-drop можно использовать следующие события:

  • onBeforeTaskDrag — для блокировки перетаскивания отдельных задач
  • onTaskDrag — для ограничения области перетаскивания или применения пользовательской логики во время перетаскивания задачи
  • onAfterTaskDrag — для обработки задач после их перемещения

Вот несколько распространённых сценариев, когда настройка поведения перетаскивания может быть полезна:

  1. Блокировка перетаскивания для определённых задач.
  2. Запрет перетаскивания задач за пределы определённых дат.
  3. Перетаскивание дочерних задач вместе с родительской.
  4. Перетаскивание проектов вместе с подзадачами.
  5. Установка минимальной длительности задачи.
  6. Включение автопрокрутки при перетаскивании задач.

Блокировка перетаскивания для определённых задач

Чтобы отключить перетаскивание для некоторых задач, используйте событие onBeforeTaskDrag:

gantt.attachEvent("onBeforeTaskDrag", function(id, mode, e){
    if(gantt.getGlobalTaskIndex(id)%2==0){
        return false;      // блокирует перетаскивание, если глобальный индекс задачи нечётный
    }
    return true;           // разрешает перетаскивание, если глобальный индекс задачи чётный
});

Запрет перетаскивания задач за пределы определённых дат

Чтобы ограничить возможность перетаскивания задач за пределы определённых дат, используйте событие onTaskDrag.

Событие onTaskDrag:

  • Вызывается каждый раз, когда пользователь перемещает мышь при перетаскивании, изменении размера или обновлении прогресса задачи на временной шкале.
  • Тип действия перетаскивания передаётся вторым аргументом — mode.
  • Все возможные режимы перетаскивания перечислены в свойстве drag_mode.

Вкратце, процесс выглядит так:

  1. Пользователь перетаскивает задачу.
  2. dhtmlxGantt пересчитывает дату задачи на основе нового положения.
  3. dhtmlxGantt вызывает событие onTaskDrag.
  4. dhtmlxGantt перерисовывает задачу на диаграмме.

    Поскольку событие onTaskDrag вызывается после пересчёта, вы можете безопасно задать пользовательские значения для перетаскиваемой задачи внутри обработчика события — они не будут перезаписаны. Это гарантирует, что задача отобразится именно там, где вы хотите.


Например, чтобы запретить пользователям перетаскивать задачи за пределы диапазона "31 марта 2020 — 11 апреля 2020":

Используйте следующий код:

Запрет перетаскивания задач за пределы интервала — [31.03.2020, 11.04.2020]

var leftLimit = new Date(2020, 2 ,31), rightLimit = new Date(2020, 3 ,12);
 
gantt.attachEvent("onTaskDrag", function(id, mode, task, original){
    var modes = gantt.config.drag_mode;
    if(mode == modes.move || mode == modes.resize){
 
        var diff = original.duration*(1000*60*60*24);
 
        if(+task.end_date > +rightLimit){
            task.end_date = new Date(rightLimit);
            if(mode == modes.move)
                task.start_date = new Date(task.end_date - diff);
            }
        if(+task.start_date < +leftLimit){
            task.start_date = new Date(leftLimit);
            if(mode == modes.move)
                task.end_date = new Date(+task.start_date + diff);
        }
    }
});

Related sample:  Drag parent task with its children

Перетаскивание дочерних задач вместе с родительской

Чтобы при перемещении родительской задачи перетаскивались и её дочерние задачи, используйте событие onTaskDrag (подробнее об этом событии см. выше):

gantt.attachEvent("onTaskDrag", function(id, mode, task, original){
    var modes = gantt.config.drag_mode;
    if(mode == modes.move){
        var diff = task.start_date - original.start_date;
        gantt.eachTask(function(child){
            child.start_date = new Date(+child.start_date + diff);
            child.end_date = new Date(+child.end_date + diff);
            gantt.refreshTask(child.id, true);
        },id );
    }
});
// округляет позиции дочерних задач по текущему масштабу
gantt.attachEvent("onAfterTaskDrag", function(id, mode, e){
    var modes = gantt.config.drag_mode;
    if(mode == modes.move ){
        var state = gantt.getState();
        gantt.eachTask(function(child){          
            child.start_date = gantt.roundDate({
                date:child.start_date, 
                unit:state.scale_unit, 
                step:state.scale_step
            });         
            child.end_date = gantt.calculateEndDate(child.start_date, 
                child.duration, gantt.config.duration_unit);
            gantt.updateTask(child.id);
        },id );
    }
});

Перетаскивание проектов вместе с подзадачами

Эта возможность доступна только в редакции Gantt PRO.

По умолчанию задачи, помеченные как тип project, не могут быть перетаскиваемыми. Вы можете включить перетаскивание проектов с помощью опции drag_project:

gantt.config.drag_project = true;

Related sample:  Draggable projects

Перетаскивание зависимых задач вместе с независимыми

Существует несколько способов перемещения задач вместе с их зависимыми задачами. Подробную информацию вы найдёте в отдельной статье: Перетаскивание задач вместе с их зависимыми задачами.

Установка минимальной длительности задачи

Вы можете задать минимальную длительность задачи с помощью настройки min_duration.

Этот параметр определяет минимальный размер задачи при изменении её длительности и предотвращает появление задач с нулевой длительностью.

Значение указывается в миллисекундах:

// 1 день
gantt.config.min_duration = 24*60*60*1000;
 
//ИЛИ
 
// 1 час
gantt.config.min_duration = 60*60*1000;

Автопрокрутка при перетаскивании задач

При работе с крупными Gantt-диаграммами перетаскивание задачи на большое расстояние или создание связей между удалёнными задачами может быть затруднено.

Функция autoscroll помогает автоматически прокручивать диаграмму во время перетаскивания. Она включена по умолчанию, но может быть управляемой через опцию autoscroll.

gantt.config.autoscroll = false;
gantt.init("gantt_here");

Также вы можете настроить скорость автопрокрутки (в миллисекундах) с помощью свойства autoscroll_speed:

gantt.config.autoscroll = true;
gantt.config.autoscroll_speed = 50;
 
gantt.init("gantt_here");

Отключение изменения размера для определённых задач

Чтобы запретить изменение размера некоторых задач, есть два подхода:

  1. Скрыть ручки изменения размера в интерфейсе с помощью CSS. Используйте шаблон task_class, чтобы добавить пользовательский CSS-класс для определённых задач:
gantt.templates.task_class = function(start, end, task){
    if(task.no_resize) { // no_resize — это пользовательское свойство для примера
        return "no_resize";
    }
    return "";

Затем скройте ручки изменения размера с помощью CSS:

.no_resize .gantt_task_drag{
   display: none !important;
}
  1. Заблокировать изменение размера программно с помощью события onBeforeTaskDrag. Если обработчик возвращает false, изменение размера будет запрещено:
gantt.attachEvent("onBeforeTaskDrag", function(id, mode, e){
    if(mode === "resize" && gantt.getTask(id).no_resize){
        return false;
    }
    return true;
});

Определение, какая сторона задачи изменяется по размеру

Режим "resize" в drag-and-drop означает, что пользователь изменяет либо дату начала, либо дату окончания задачи.

Чтобы определить, какая дата изменяется, проверьте флаг gantt.getState().drag_from_start:

gantt.attachEvent("onBeforeTaskDrag", function(id, mode, e){
    if(mode === "resize"){
        if(gantt.getState().drag_from_start === true) {
            // изменяется дата начала
        } else {
            // изменяется дата окончания
        }
    }
    return true;
});

Отключение изменения даты начала или окончания задачи

Ручки изменения размера можно выбрать с помощью следующих селекторов:

  • .gantt_task_drag[data-bind-property="start_date"]
  • .gantt_task_drag[data-bind-property="end_date"]

Чтобы отключить изменение даты начала, используйте такой CSS:

.gantt_task_drag[data-bind-property="start_date"]{
   display: none !important;
}

Аналогично, чтобы отключить изменение даты окончания:

.gantt_task_drag[data-bind-property="end_date"]{
   display: none !important;
}

В качестве альтернативы, вы можете запретить изменение размера через событие onBeforeTaskDrag. Если обработчик возвращает false, изменение размера будет запрещено:

gantt.attachEvent("onBeforeTaskDrag", function(id, mode, e){
    if(mode === "resize"){
        if(gantt.getState().drag_from_start === true) {
             return false;
        } else {
             // изменение даты окончания разрешено
        }
    }
    return true;
});
К началу