По умолчанию, dhtmlxGantt измеряет продолжительность задач в календарном времени, что означает, что выходные и праздники включены в общую продолжительность.
Обратитесь к статье Отображение даты окончания задачи и включение конечных дат для получения деталей о том, как форматируются даты окончания задачи.
Если вы хотите, чтобы продолжительность задач рассчитывалась только на основе рабочего времени, вы можете использовать опцию work_time:
Включение расчетов рабочего времени для продолжительности задач
gantt.config.work_time = true; // исключает нерабочее время из расчетов gantt.config.skip_off_time = true; // скрывает нерабочее время на графике
gantt.init("gantt_here");
Имейте в виду, что конфигурационная опция skip_off_time доступна только в PRO версии.
Related sample: Duration includes only working days
В зависимости от значения duration_unit, dhtmlxGantt рассчитывает продолжительность задач в различных единицах времени (например, если duration_unit = "hour"
, продолжительность измеряется в рабочих часах).
Эта функция доступна только в PRO издании.
Начиная с версии 6.3, dhtmlxGantt поддерживает указание продолжительности задач в десятичных форматах, таких как "2.5 дня", "0.5 часа" или "3.75 часа", с использованием модуля Форматировщик Продолжительности.
Стоит отметить, что Gantt внутренне хранит продолжительность задач как целочисленные значения. Модуль помогает преобразовывать введенные пользователем десятичные значения в формат, хранящийся в Gantt (например, "1.5 часа" становится 90
минутами) и наоборот, преобразовывая хранимые значения обратно в читаемый формат (например, 12
часов становится "0.5 дня").
Продолжительность задач может быть выражена как дробные значения поддерживаемых единиц, таких как часы или дни, но не минуты, как определено настройкой duration_unit.
Чтобы отображать продолжительность задач в десятичном формате, выполните следующие шаги:
gantt.config.work_time = true;
gantt.config.duration_unit = "minute";
Убедитесь, что продолжительность задач хранится в меньших единицах, чем отображаемый десятичный формат. Например: - Чтобы позволить пользователям указывать продолжительность в дробных частях часа (например, "0.5 часа"), установите duration_unit в "minute". - Чтобы позволить пользователям указывать продолжительность в дробных частях дня, установите duration_unit в "hour". В этом случае "0.5 дня" будет работать, но "0.5 часа" округлится до 1 часа, так как продолжительность хранится как целые часы.
По умолчанию, даты задач привязываются к временной шкале. Если ваша шкала установлена на дни, вам, возможно, потребуется отключить привязку, чтобы позволить перетаскивать задачи на конкретные часы. Отключите round_dnd_dates и настройте time_step соответствующим образом.
Например:
// Шаги времени по 15 минут, требует "minute" как единицу продолжительности
gantt.config.time_step = 15;
gantt.config.round_dnd_dates = false;
или
// Шаги времени по 1 часу, подходит, когда единица продолжительности "hour"
gantt.config.time_step = 60;
gantt.config.round_dnd_dates = false;
// Форматирование продолжительности
var formatter = gantt.ext.formatters.durationFormatter({
enter: "day",
store: "minute", // duration_unit
format: "day",
hoursPerDay: 8,
hoursPerWeek: 40,
daysPerMonth: 30
});
gantt.config.columns = [
{name: "text", tree: true, width: 170, resize: true, editor: textEditor},
{name: "start_date", align: "center", resize: true, editor: dateEditor},
{name: "duration", label:"Duration", resize: true, align: "center",
template: function(task) { return formatter.format(task.duration); }, width: 100},
{name: "add", width: 44}
];
gantt.config.lightbox.sections = [
{name: "description", height: 70, map_to: "text", type: "textarea", focus: true},
{name: "time", type: "duration", map_to: "auto", formatter: formatter}
];
var durationEditor = {
type: "duration",
map_to: "duration",
formatter: formatter, min:0, max:1000
};
gantt.config.columns = [
{name: "text", tree: true, width: 170, resize: true},
{name: "start_date", align: "center", resize: true},
{name: "duration", label:"Duration", resize: true, align: "center",
template: function(task) {
return formatter.format(task.duration);
}, editor: durationEditor, width: 100}, {name: "add", width: 44}
];
Если продолжительность уже хранится в таких единицах, как минуты или часы, вы все равно можете использовать модуль Форматировщик Продолжительности для отображения их в десятичном формате.
По умолчанию, рабочее время определяется как:
Чтобы настроить эти параметры, используйте метод setWorkTime:
Настройка рабочего времени
// Установить рабочие часы для будних дней
gantt.setWorkTime({ hours:["9:00-18:00"] });
// Обозначить пятницы как выходные дни
gantt.setWorkTime({ day:5, hours:false });
// Установить конкретные часы для пятниц и суббот
gantt.setWorkTime({day : 5, hours : ["8:00-12:00"]});
gantt.setWorkTime({day : 6, hours : ["8:00-12:00"]});
// Сделать конкретную дату рабочим днем
gantt.setWorkTime({date : new Date(2019, 2, 31)});
// Сделать конкретную дату выходным днем
gantt.setWorkTime({date:new Date(2019,0,1), hours:false})
Related sample: Custom working days and time
При установке рабочих часов убедитесь, что атрибут hours в setWorkTime
находится в порядке возрастания. В противном случае некоторые интервалы будут проигнорированы. Например:
// Эти настройки не будут работать как ожидается
gantt.setWorkTime({day : 5, hours : ["16:00-18:00", "14:00-15:00", "08:00-10:00"]});
gantt.setWorkTime({day : 5, hours : ["16:00-18:00", "00:00-04:00", "05:00-06:00"]});
Для ночных смен разделите часы на два дня:
gantt.setWorkTime({day : 5, hours : ["16:00-18:00"]});
gantt.setWorkTime({day : 6, hours : ["00:00-04:00", "05:00-06:00"]});
Вы можете определить различные правила рабочего времени для определенных периодов, используя атрибут customWeeks в setWorkTime
. Например, установите разные часы для зимних месяцев:
// Настройка рабочих часов для зимних месяцев
gantt.setWorkTime({
customWeeks: {
winter: {
from: new Date(2018, 11, 1), // 1 декабря 2018 года
to: new Date(2019, 2, 1), // 1 марта 2019 года
hours: ["9:00-13:00", "14:00-16:00"],
days: [ 1, 1, 1, 1, 0, 0, 0]
}
}
});
Если вам нужно указать рабочие часы с минутами (например, "8:15-12:45"), установите duration_unit в "minute".
Настройка рабочих часов с точностью до минуты
gantt.config.duration_unit = "minute";
// Установка рабочих часов с точностью до минуты
gantt.setWorkTime({hours:["8:15-12:45"]});
Старый формат рабочего времени (использовавшийся до версии 7.0) все еще поддерживается:
gantt.setWorkTime({hours:[9, 18]})
Когда вы вызываете метод для той же даты несколько раз, последнее правило рабочего времени заменит предыдущее. Чтобы изменить или удалить существующее правило, вы можете использовать метод gantt.setWorkTime()
с новой конфигурацией:
gantt.setWorkTime({hours:["8:00-12:00"]});
gantt.setWorkTime({hours:["13:00-17:00"]});
// Результирующее рабочее время будет с 13:00 до 17:00,
// а не комбинацией двух команд.
Чтобы удалить настройку рабочего времени, вы можете использовать метод gantt.unsetWorkTime()
:
// Устанавливает рабочее время для рабочих дней на ["8:00-12:00"]
gantt.setWorkTime({hours:["8:00-12:00"]});
// Удаляет рабочее время
gantt.unsetWorkTime({hours:["8:00-12:00"]});
Чтобы узнать, попадает ли конкретная дата в рабочее время, используйте метод gantt.isWorkTime()
:
// Обозначает 1 января 2019 года как выходной
gantt.setWorkTime({date:new Date(2019,0,1), hours:false});
gantt.isWorkTime(new Date(2019,0,1)) // -> false
// Устанавливает 15 марта 2019 года как рабочий день с 9:00 до 18:00
gantt.setWorkTime({date : new Date(2019, 2, 15), hours:["8:00-17:00"]});
gantt.isWorkTime(new Date(2019, 2, 15,10,0), "hour"); // -> true gantt.isWorkTime(new Date(2019, 2, 15,8,0), "hour"); // -> false
Related sample: Correct task position on drag
Чтобы получить рабочие часы для конкретной даты, вы можете использовать метод gantt.getWorkHours()
:
gantt.getWorkHours(new Date(2019,3,30))// -> ["8:00-17:00"]
Если вам нужен ближайший рабочий день к заданной дате, используйте метод gantt.getClosestWorkTime()
:
gantt.getClosestWorkTime(new Date(2019,3,30));
Иногда вы можете захотеть определить рабочие часы, которые повторяются в определенные дни, например, сделать последний пятницу каждого месяца коротким днем или обозначить 25 декабря как праздник. В настоящее время dhtmlxGantt не имеет встроенных опций для этого. Он позволяет вам:
Для исключений из этих правил вам потребуется вручную определить соответствующие даты и применить настройки индивидуально.
Например, если проект длится пять лет, и вы хотите, чтобы 1 января всегда был выходным днем, вы можете жестко закодировать это так:
gantt.setWorkTime({hours:false, date: new Date(2021, 0, 1)});
gantt.setWorkTime({hours:false, date: new Date(2022, 0, 1)});
gantt.setWorkTime({hours:false, date: new Date(2023, 0, 1)});
gantt.setWorkTime({hours:false, date: new Date(2024, 0, 1)});
gantt.setWorkTime({hours:false, date: new Date(2025, 0, 1)});
Чтобы установить последний пятницу каждого месяца как короткий день, вы можете использовать следующий код:
function lastFridayOfMonth(date) {
var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
if (lastDay.getDay() < 5) {
lastDay.setDate(lastDay.getDate() - 7);
}
lastDay.setDate(lastDay.getDate() - (lastDay.getDay() - 5));
return lastDay;
}
var projectStart = new Date(2020, 5, 1);
var projectEnd = new Date(2025, 5, 1);
var currentDate = new Date(projectStart);
while (currentDate.valueOf() <= projectEnd.valueOf()) {
var lastFriday = lastFridayOfMonth(currentDate);
gantt.setWorkTime({hours:["8:00-12:00", "13:00-15:00"], date: lastFriday});
currentDate = gantt.date.add(currentDate, 1, "month");
}
Чтобы визуально выделить нерабочие времена на графике, вы можете использовать шаблон gantt.templates.timeline_cell_class
:
gantt.templates.timeline_cell_class = function(task, date){
if (!gantt.isWorkTime({task:task, date: date}))
return "week_end";
return "";
};
Related sample: Custom working days and time
Вы можете ознакомиться с более подробной информацией в статье подсветка временных интервалов.
Чтобы скрыть нерабочие времена, обратитесь к технике, описанной в статье настраиваемая шкала.
Помимо глобальных настроек рабочего времени, Gantt поддерживает несколько календарей рабочего времени, которые могут быть назначены отдельным задачам или группам задач.
Вы можете создать новый календарь, используя метод gantt.createCalendar()
. Этот метод предоставляет два варианта:
var calendar = gantt.createCalendar();
var newCalendar = gantt.createCalendar(calendar);
После создания календарь отсоединен от Gantt и не будет влиять ни на что, пока не будет добавлен.
После создания календаря добавьте его в Gantt, используя метод gantt.addCalendar()
. Вы можете:
var calendarId = gantt.addCalendar(calendar);
worktime
с рабочими днями и часами:var calendarId = gantt.addCalendar({
id: "custom", // не обязательно
worktime: {
hours: ["8:00-17:00"],
days: [1, 1, 1, 1, 1, 1, 1]
}
});
Эта опция также может быть использована для создания календаря.
Начиная с версии 7.1, вы можете установить разные рабочие часы для определенных периодов в одном календаре. Например, вы можете определить отдельное расписание для зимних месяцев, используя свойство customWeeks
в методе addCalendar
:
var calendarId = gantt.addCalendar({
id: "global", // не обязательно
worktime: {
hours: ["8:00-17:00"],
days: [1, 1, 1, 1, 1, 1, 1],
customWeeks: {
winter: {
from: new Date(2018, 11, 1), // 1 декабря 2018 года
to: new Date(2019, 2, 1), // 1 марта 2019 года
hours: ["9:00-13:00", "14:00-16:00"],
days: [1, 1, 1, 1, 0, 0, 0]
}
}
},
});
Related sample: Different worktimes for different time periods
Чтобы обновить рабочие часы для определенных дней в календаре, используйте метод setWorkTime()
:
var calendar = gantt.getCalendar("custom");
calendar.setWorkTime({day: 6, hours: ["8:00-12:00"]});
calendar.setWorkTime({date: new Date(2021, 0, 1), hours: ["8:00-12:00"]});
Вы можете получить объекты календарей для дальнейшего использования. Вот доступные опции:
Чтобы получить глобальный календарь Gantt, используйте метод gantt.getCalendar()
:
var calendar = gantt.getCalendar(id);
По умолчанию глобальный календарь можно получить, используя предопределенный ID "global"
:
var globalSettings = gantt.getCalendar("global");
Этот календарь является стандартным для задач, если не указан другой календарь.
Чтобы получить календарь, назначенный конкретной задаче, используйте метод gantt.getTaskCalendar()
, передав объект задачи:
var task = gantt.getTask(taskId);
var calendar = gantt.getTaskCalendar(task);
if (calendar.isWorkTime(date)) {
alert("TaskWorkTime");
}
Related sample: Task level calendars
Если рабочее время отключено в конфигурации Gantt, метод вернет календарь рабочего времени 24/7.
Gantt предоставляет глобальные методы для расчета продолжительности задач или проверки дат без прямого доступа к календарю задачи:
gantt.isWorkTime
:if (gantt.isWorkTime({date: date, task: task})) {
alert("work time of a task" + task.text);
}
Эквивалентно:
var calendar = gantt.getTaskCalendar(task);
if (calendar.isWorkTime({date: date})) {
alert("work time of a task" + task.text);
}
gantt.calculateEndDate
:var end_date = gantt.calculateEndDate({start_date: date, duration: duration, task: task});
// или
var end_date = gantt.calculateEndDate(task);
gantt.calculateDuration
:var duration = gantt.calculateDuration({start_date: start, end_date: end, task: task});
// или
var duration = gantt.calculateDuration(task);
gantt.getClosestWorkTime
:var closestTime = gantt.getClosestWorkTime({date: date, task: task});
Чтобы получить все календари, добавленные в Gantt (глобальные и специфичные для задач), используйте метод gantt.getCalendars()
:
var calendars = gantt.getCalendars();
Этот метод возвращает массив объектов календарей.
Если календарь больше не нужен, вы можете удалить его, используя метод gantt.deleteCalendar()
. Просто передайте ID календаря:
// Добавление календаря
gantt.addCalendar({
id: "custom",
worktime: {
hours: ["8:00-17:00"],
days: [1, 1, 1, 1, 1, 1, 1]
}
});
// Удаление календаря
gantt.deleteCalendar("custom");
Чтобы назначить календарь задаче, сначала добавьте календарь с его ID и настройками рабочего времени:
gantt.addCalendar({
id: "custom", // не обязательно
worktime: {
hours: ["8:00-17:00"],
days: [1, 1, 1, 1, 1, 1, 1]
}
});
Затем установите ID календаря в атрибуте "calendar_id"
объекта задачи:
{
"id": 2, "calendar_id": "custom", "text": "Task #1", "start_date": "02-04-2019",
"duration": "8", "parent": "1", "progress": 0.5, "open": true
}
При необходимости вы можете изменить имя свойства задачи, которое связывает календарь, используя опцию gantt.config.calendar_property
:
gantt.config.calendar_property = "property_name";
Related sample: Task level calendars
Эта функциональность доступна только в PRO издании.
Вы можете назначить определенные рабочие календари задачам, которым необходимы определенные ресурсы, такие как люди или оборудование. Например, вы можете захотеть, чтобы задачи следовали индивидуальным календарям в зависимости от пользователя, которому они назначены. Вот как это сделать:
gantt.config.resource_property = "user";
gantt.config.resource_calendars = {
1 : gantt.addCalendar({
worktime: {
days: [0, 1, 1, 1, 1, 1, 0]
}
}),
2 : gantt.addCalendar({
worktime: {
days: [1, 0, 0, 0, 0, 0, 1]
}
}),
3 : gantt.addCalendar({
worktime: {
days: [0, 1, 1, 1, 0, 1, 1]
}
})
};
Этот объект содержит пары ключ-значение, где ключ - это ID ресурса, а значение - ID календаря, возвращаемое методом addCalendar.
{ "id":1, "user":"1", "text":"Project #2", "start_date":"01-04-2019", "duration":"5" },
{ "id":2, "user":"0", "text":"Task #1", "start_date":"02-04-2019", "duration":"2" },
{ "id":3, "user":"2", "text":"Task #2", "start_date":"11-04-2019", "duration":"4" },
{ "id":4, "user":"3", "text":"Task #3", "start_date":"13-04-2019", "duration":"3" },
{ "id":5, "user":"0", "text":"Task #1.1", "start_date":"02-04-2019", "duration":"7" },
{ "id":6, "user":"1", "text":"Task #1.2", "start_date":"03-04-2019", "duration":"7" }
Related sample: Resource level calendars
Если у задачи назначены как пользовательский календарь, так и календарь ресурса, приоритет отдается пользовательскому календарю, и он переопределяет календарь ресурса.
Начиная с версии 7.0, вы можете объединять несколько календарей в один. Например, если два ресурса с разными рабочими часами назначены одной задаче, их рабочие часы могут быть объединены в один календарь. Например, если один ресурс работает с 9:00 до 15:00, а другой с 12:00 до 17:00, объединенный календарь будет охватывать с 12:00 до 15:00.
Чтобы включить эту функцию автоматически, установите конфигурацию dynamic_resource_calendars в true:
gantt.config.dynamic_resource_calendars = true;
Related sample: Merge work Calendars of different resources
Кроме того, вы можете объединить календари вручную, используя метод mergeCalendars:
const johnCalendarId = gantt.addCalendar({
worktime: {
hours: ["0:00-24:00"],
days: [0, 1, 1, 1, 1, 1, 0]
}
});
const mikeCalendarId = gantt.addCalendar({
worktime: {
hours: ["8:00-12:00", "13:00-17:00"],
days: [0, 1, 1, 1, 1, 1, 0]
}
});
const joinedCalendar = gantt.mergeCalendars(
gantt.getCalendar(mikeCalendarId),
gantt.getCalendar(johnCalendarId)
);
Проверьте статью mergeCalendars() для получения деталей о том, как объединяются рабочие часы.
Эта функциональность доступна только в PRO издании.
Вы также можете назначить рабочий календарь проекту, позволяя задачам наследовать календарь их родительского проекта. Вот как это работает:
Чтобы включить эту функцию, установите конфигурационную опцию inherit_calendar в true. По умолчанию эта опция отключена.
gantt.config.inherit_calendar = true;
В примере ниже задачи по умолчанию наследуют календари от своих родительских проектов. Однако, если у задачи назначен собственный календарь, она будет использовать его вместо. Например, задачи #2.2 и #3 используют календари "Полная неделя" вместо календаря их родительского проекта:
Related sample: Project level calendars
Начиная с версии 7.0, Gantt автоматически обнаруживает изменения в календаре задачи и пересчитывает расписание задачи.
Однако, при необходимости, вы можете вручную обновить расписание задачи, когда ее календарь изменяется. Например, вы можете захотеть обновить расписание, когда календарь изменяется через lightbox:
function updateTaskTiming(task) {
task.start_date = gantt.getClosestWorkTime({
dir: "future",
date: task.start_date,
unit: gantt.config.duration_unit,
task: task
});
task.end_date = gantt.calculateEndDate(task);
}
gantt.attachEvent("onLightboxSave", function(id, task, is_new){
updateTaskTiming(task);
return true;
});
Кроме того, вы можете определить пересчет для всех задач, когда это необходимо:
gantt.batchUpdate(function(){
gantt.eachTask(function(task){
task.start_date = gantt.getClosestWorkTime({
dir: "future",
date: task.start_date,
unit: gantt.config.duration_unit,
task: task
});
task.end_date = gantt.calculateEndDate(task);
gantt.updateTask(task.id);
});
});
К началу