Вы можете настроить масштабы, используя свойство scales. Чтобы включить несколько масштабов, просто добавьте объекты масштаба в массив scales в конфигурации:
// Пример масштаба одного дня
gantt.config.scales = [
{unit: "day", step: 1, format: "%j, %D"}
];
// Пример с несколькими масштабами
gantt.config.scales = [
{unit: "month", step: 1, format: "%F, %Y"},
{unit: "week", step: 1, format: weekScaleTemplate},
{unit: "day", step:1, format: "%D", css:daysStyle }
];
Временной масштаб (ось X) может быть настроен несколькими способами:
Также у вас есть возможность создать пользовательский масштаб.
Свойство unit в объекте масштаба определяет единицу времени для масштаба.
Доступные единицы: "minute", "hour", "day" (по умолчанию), "week", "quarter", "month", и "year".
gantt.config.scales = [
{unit: "month", step: 1, format: "%F, %Y"},
{unit: "day", step: 1, format: "%j, %D"}
];
gantt.init("gantt_here");
Если вы не задаете явно диапазон дат, Gantt автоматически рассчитывает его на основе загруженных дат задач. Он добавляет небольшую подкладку перед самой ранней задачей и после самой поздней, как определено настройками временного масштаба. Размер этого смещения зависит от значения scale_offset_minimal. Оно может совпадать с атрибутом unit в конфигурации масштаба или использовать наименьшую единицу временного масштаба.
Чтобы проверить отображаемый диапазон дат, вы можете использовать метод gantt.getState()
:
var state = gantt.getState();
console.log(state.min_date);
// -> Mon Jan 01 2018 00:00:00
console.log(state.max_date);
// -> Tue Jan 01 2019 00:00:00
Диапазон масштаба автоматически обновляется каждый раз, когда Gantt рендерится. Однако, если пользователь перемещает задачу за пределы видимого диапазона, её строка все равно будет отображаться, но полоса задачи не появится до полной перерисовки диаграммы.
Чтобы масштаб автоматически подстраивался, вы можете включить конфигурацию fit_tasks
:
gantt.config.fit_tasks = true;
gantt.init("gantt_here");
Related sample: Auto resize scale
При необходимости вы можете вручную задать диапазон дат, используя параметры конфигурации start_date
и end_date
:
gantt.config.start_date = new Date(2018, 02, 31);
gantt.config.end_date = new Date(2018, 03, 09);
gantt.init("gantt_here");
Кроме того, вы можете указать эти даты непосредственно при инициализации:
gantt.init("gantt_here", new Date(2018, 02, 31), new Date(2018, 03, 09));
Related sample: Define displayed date range
Задачи, которые выходят за пределы заданного диапазона, не будут отображаться на диаграмме Gantt, если они не являются незапланированными задачами.
Related sample: Show Unscheduled Tasks
Если заданы оба параметра start_date
и end_date
, задачи, созданные за пределами этого диапазона, не будут отображаться на диаграмме. Чтобы включить такие задачи, включите конфигурацию show_tasks_outside_timescale
:
gantt.config.start_date = new Date(2019, 02, 31);
gantt.config.end_date = new Date(2019, 03, 09);
gantt.config.show_tasks_outside_timescale = true;
gantt.init("gantt_here");
Кроме того, вы можете динамически расширять диапазон:
gantt.attachEvent("onLightboxSave", function(id, task, is_new){
var taskStart = task.start_date;
var taskEnd = task.end_date;
var scaleStart = gantt.config.start_date;
var scaleEnd = gantt.config.end_date;
if(scaleStart > taskEnd || scaleEnd < taskStart ){
gantt.config.end_date = new Date(Math.max(taskEnd.valueOf(), scaleEnd.valueOf()));
gantt.config.start_date = new Date(Math.min(taskStart.valueOf(), scaleStart.valueOf()));
gantt.render();
}
return true;
});
Или вы можете добавить валидацию, чтобы предотвратить сохранение задач за пределами диапазона:
gantt.attachEvent("onLightboxSave", function(id, task, is_new){
var taskStart = task.start_date;
var taskEnd = task.end_date;
var scaleStart = gantt.config.start_date;
var scaleEnd = gantt.config.end_date;
if(scaleStart > taskEnd || scaleEnd < taskStart ){
gantt.message({
type: "warning",
text: "Warning! The task is outside the date range!",
expire: 5000
});
return false;
}
return true;
});
Существует несколько способов изменить отображаемый диапазон на лету:
start_date
и end_date
, обновляя их динамически, чтобы включить загруженные задачи. Например, вы можете пересчитать диапазон масштаба во время перерисовки:gantt.attachEvent("onBeforeGanttRender", function(){
var range = gantt.getSubtaskDates();
var scaleUnit = gantt.getState().scale_unit;
if(range.start_date && range.end_date){
gantt.config.start_date = gantt.calculateEndDate(range.start_date, -4, scaleUnit);
gantt.config.end_date = gantt.calculateEndDate(range.end_date, 5, scaleUnit);
}
});
gantt.init("gantt_here");
fit_tasks
, чтобы автоматически подстраивать масштаб всякий раз, когда задачи выходят за пределы видимого диапазона:gantt.config.fit_tasks = true;
gantt.init("gantt_here");
Если заданы оба параметра start_date
и end_date
, вам потребуется комбинировать это с другими методами, чтобы fit_tasks
работал корректно.
onTaskDrag
:gantt.attachEvent("onTaskDrag", function(id, mode, task, original){
var state = gantt.getState();
var minDate = state.min_date,
maxDate = state.max_date;
var scaleStep = gantt.date.add(new Date(), state.scale_step, state.scale_unit) - new Date();
var showDate,
repaint = false;
if(mode == "resize" || mode == "move"){
if(Math.abs(task.start_date - minDate) < scaleStep){
showDate = task.start_date;
repaint = true;
} else if(Math.abs(task.end_date - maxDate) < scaleStep){
showDate = task.end_date;
repaint = true;
}
if(repaint){
gantt.render();
gantt.showDate(showDate);
}
}
});
Задачи за пределами заданного диапазона дат все же могут быть отображены, если включить конфигурацию show_tasks_outside_timescale
:
var data = {
"tasks": [
{"id": 1, "text": "Project #1", "start_date": "01-09-2018", "end_date": "02-09-2018"},
{"id": 2, "text": "Project #2", "start_date": "01-09-2021", "end_date": "02-09-2021"},
{"id": 3, "text": "Task #1", "start_date": "03-02-2020", "end_date": "05-02-2020"},
],
"links": []
};
gantt.config.show_tasks_outside_timescale = true;
gantt.init("gantt_here", new Date(2020, 1, 1), new Date(2020, 2, 1));
Related sample: Tasks outside timescale
Задачи, которые выходят за пределы диапазона, будут отображаться пустыми строками в шкале времени и все же показывать свои детали в гриде.
[Продолжайте с следующими разделами, чтобы узнать больше о временном шаге, высоте, формате даты, стиле и пользовательских единицах времени.]
Вот как можно определить единицу "fiscal_year", если финансовый год заканчивается 31 января. Этот фрагмент демонстрирует настройку:
var firstMonth = 1,
firstDay = 1;
gantt.date.fiscal_year_start = function(date){ var next = new Date(date);
if(next.getMonth() < firstMonth ||
(next.getMonth() === firstMonth && next.getDate() < firstDay)){
next = gantt.date.add(next, -1, "year");
}
next = gantt.date.year_start(next);
next.setMonth(firstMonth);
next.setDate(firstDay);
return next;
};
gantt.date.add_fiscal_year = function(date, inc){ return gantt.date.add(date, inc, "year");
};
Как только это определено, вы можете интегрировать это в вашу конфигурацию следующим образом:
var dateToStr = gantt.date.date_to_str("%Y");
function fiscalYearLabel(date){
return dateToStr(gantt.date.fiscal_year_start(date));
};
gantt.config.scales = [
{unit:"year", step:1, format:"Calendar year %Y"},
{unit:"fiscal_year", step:1, format:fiscalYearLabel},
{unit:"month", step: 1, format: "%M %Y"},
{unit:"day", step: 1, format:"%d %M"}
];
Вы можете разделить каждую ячейку "day" на три ячейки "hour", обозначенные как 00, 08 и 16. Вот как можно реализовать эту логику:
gantt.date.hour_custom_start = function (date) {
return date;
};
gantt.date.add_hour_custom = function (date, inc) { // inc зависит от "step"
const nextDate = new Date(date);
if (nextDate.getHours() % 8 != 0) { // значение часа не 0, 8 или 16 const diff = Math.abs(8 - nextDate.getHours()); return gantt.date.add(nextDate, diff * inc, "hour"); } return gantt.date.add(date, 8 * inc, "hour"); };
gantt.config.scales = [
{ unit: "day", step: 1, date: "%d %F" },
{ unit: "hour_custom", step: 1, date: "%H" },
];
gantt.config.date_grid = "%Y-%m-%d %H:%i"
Related sample: Custom hours on the scale
Чтобы сгенерировать первую ячейку "hour", Gantt корректирует время на основе времени начала задачи. Например, если самая ранняя задача начинается в 07:00, что не является кратным восьми, Gantt применяет это правило:
if (nextDate.getHours() % 8 != 0) {
const diff = Math.abs(8 - nextDate.getHours()); // 8 - 7 = 1
return gantt.date.add(nextDate, diff * inc, "hour"); // 7 - 1 = 6
}
Он вычисляет разницу между 08:00 и 07:00:
diff = 08:00 - 07:00 = 1 час
Затем он умножает интервал на приращение:
diff * inc = 1 час * (-1) = -1 час
Значение приращения (inc) здесь отрицательное (-1).
Наконец, он корректирует время самой ранней задачи:
07:00 + (- 1 час) = 06:00
Значение первой ячейки становится 06.
Вторая ячейка "hour" вычисляется аналогично, но с положительным приращением:
diff = 08:00 - 06:00 = 2 часа
diff * inc = 2 часа * 1 = 2 часа
06:00 + 2 часа = 08:00
Значение второй ячейки 08.
Как только достигнуто 08:00, что является кратным восьми, последующие ячейки следуют шаблону: 08:00 + 8 часов = 16:00 и так далее.
Этот подход работает, потому что диапазон дат не определен явно.
Для получения дополнительных примеров обратитесь к руководству Как добавить пользовательский масштаб.
Этот раздел предоставляет примеры настройки временного масштаба для включения или исключения нерабочих часов. Также рассматривается скрытие ячеек с нерабочими часами в начале шкалы даже при активном режиме skip_off_time.
Вот типичная настройка, где рабочие часы с 08:00 до 12:00 и с 13:00 до 17:00:
gantt.date.day_custom_start = function (date) {
return date;
};
gantt.date.add_day_custom = function (date, inc) { const nextDate = new Date(date); if (nextDate.getHours() < 8) { // Условие 1 const diff = 8 - nextDate.getHours(); return gantt.date.add(nextDate, diff * inc, "hour"); } if (nextDate.getHours() == 8) { // Условие 2 return gantt.date.add(nextDate, 9 * inc, "hour"); } if (nextDate.getHours() == 17) { // Условие 3 return gantt.date.add(nextDate, 15 * inc, "hour"); }
return gantt.date.add(date, 8 * inc, "hour"); };
gantt.config.scales = [
{ unit: "day_custom", step: 1, date: "%d %H:00" },
];
// gantt.config.skip_off_time = true;
gantt.config.work_time = true;
gantt.config.correct_work_time = true;
gantt.plugins({
auto_scheduling: true,
});
gantt.setWorkTime({ hours: ["8:00-12:00", "13:00-17:00"] });
gantt.config.duration_unit = "minute";
gantt.config.duration_step = 1;
gantt.config.time_step = 1;
gantt.config.round_dnd_dates = false;
Related sample: Custom time spans
Предположим, что самая ранняя задача начинается в 08:00 1 апреля 2025 года. В зависимости от настройки gantt.config.skip_off_time Gantt корректирует временной масштаб по-разному.
Когда нерабочие часы скрыты:
gantt.config.skip_off_time = true;
Gantt вычисляет первую ячейку "hour", уменьшая время самой ранней задачи до тех пор, пока оно не совпадет с рабочими часами предыдущего дня:
Таким образом, значение первой ячейки становится 31 15:00.
Когда нерабочие часы отображаются:
gantt.config.skip_off_time = false;
Первая ячейка все равно начинается с 31 15:00, но перед самой ранней задачей появляются дополнительные пустые ячейки. Эти ячейки представляют собой нерабочие часы.
Например:
Остальные ячейки рассчитываются аналогично.
Если вы хотите иметь устойчивое смещение одной ячейки независимо от настройки skip_off_time, вы можете использовать эту логику:
gantt.date.add_day_custom = function (date, inc) {
// Для загруженных задач вычислите дату первой ячейки
if (inc < 0 && gantt.getTaskByTime().length) {
return gantt.calculateEndDate({
start_date: date, duration: -1, unit: gantt.config._duration_unit
})
}
// Вычислите время начала и конца рабочего дня
if (date.getHours() == 8) {
return gantt.calculateEndDate(date, 8);
}
if (date.getHours() == 17) {
return gantt.date.add(date, 15 * inc, "hour");
}
// Для задач или полного масштаба вычислите даты соответственно
date = gantt.date.add(date, 1 * inc, "day");
gantt.date.day_start(date);
date = gantt.getClosestWorkTime({ date, dir: "future" })
return date
};
gantt.config.scales = [
{ unit: "day_custom", step: 1, date: "%d %H:%i" },
];
gantt.config.work_time = true;
gantt.config.skip_off_time = false;
Related sample: Equal offset for custom scales
Вот как это выглядит, когда нерабочие часы скрыты:
И когда они показаны (отключен skip_off_time):
Для получения подробных примеров реализации бесконечной прокрутки в шкале времени обратитесь к соответствующей статье.
Начиная с версии 9.0, метки временного масштаба по умолчанию являются липкими. Это обеспечивает видимость меток при прокрутке по шкале времени, улучшая читаемость, особенно при увеличении или уменьшении масштаба.
Чтобы отключить эту функцию и вернуть центрированные метки, установите sticky
в false
:
gantt.config.scales = [
{unit: "year", step: 1, format: "%Y", sticky: false},
{unit: "month", step: 1, format: "%F", sticky: false},
{unit: "day", step: 1, format: "%j", sticky: false}
];
gantt.init("gantt_here");
Чтобы заставить метки оставаться липкими независимо от ширины ячейки, установите sticky
в true
:
gantt.config.scales = [
{unit: "year", step: 1, format: "%Y", sticky: true},
{unit: "month", step: 1, format: "%F", sticky: true},
{unit: "day", step: 1, format: "%j", sticky: true}
];
gantt.init("gantt_here");
К началу