В стандартной настройке интерфейса легко переключаться между видами грида и диаграммы. Нужно просто изменить параметры show_grid или show_chart и затем вызвать метод render(), чтобы применить изменения.
function toggleGrid(){
gantt.config.show_grid = !gantt.config.show_grid;
gantt.render();
}
Related sample: Gantt. Переключение грида (стандартный макет)
function toggleChart(){
gantt.config.show_chart = !gantt.config.show_chart;
gantt.render();
}
Related sample: Gantt. Переключение шкалы времени (стандартный макет)
Если вы используете кастомный макет, вам понадобятся отдельные настройки для макетов с гридом и без него, или с временной шкалой и без неё. Для переключения между ними обновите свойство gantt.config.layout и переинициализируйте Gantt с помощью метода init().
let showGrid = true;
function toggleGrid() {
showGrid = !showGrid;
if (showGrid) {
gantt.config.layout = gridAndChart; // макет с гридом и временной шкалой
} else {
gantt.config.layout = onlyChart; // макет только с временной шкалой
}
gantt.init("gantt_here");
}
Related sample: Gantt. Переключение грида (кастомный макет)
let showChart = true;
function toggleChart() {
showChart = !showChart;
if (showChart) {
gantt.config.layout = gridAndChart; // макет с гридом и временной шкалой
} else {
gantt.config.layout = onlyGrid; // макет только с гридом
}
gantt.init("gantt_here");
}
Related sample: Gantt. Переключение временной шкалы (кастомный макет)
Подобно переключению видов грида и диаграммы, вы можете управлять видами ресурсов, настраивая различные конфигурации макетов. Вы изменяете свойство gantt.config.layout и обновляете Gantt с помощью метода init().
let resourceChart = true;
function layoutChange() {
resourceChart = !resourceChart;
gantt.config.layout = resourceChart ? resourceLayout : noresourceLayout;
gantt.init("gantt_here");
};
Related sample: Gantt. Переключение диаграммы загрузки ресурсов
let histogramView = true;
function layoutChange() {
histogramView = !histogramView;
gantt.config.layout = histogramView ? histogramLayout : simpleLayout;
gantt.init("gantt_here");
};
Related sample: Gantt. Переключение гистограммы ресурсов
В качестве альтернативы вы можете динамически генерировать макет, используя виды макета, и переинициализировать Gantt для отражения изменений.
Related sample: Gantt. Генерация макета
Чтобы реализовать бесконечную прокрутку, вам, вероятно, потребуется настроить отображаемый диапазон дат, используя свойства gantt.config.start_date и gantt.config.end_date.
Отслеживайте позицию прокрутки и расширяйте диапазон дат по мере необходимости. Имейте в виду, что частая перерисовка с помощью render() может повлиять на производительность, поэтому лучше делать это с задержкой.
gantt.init("gantt_here");
gantt.parse(tasks);
gantt.attachEvent("onGanttScroll", function (left, top) {
const left_date = gantt.dateFromPos(left);
const right_date = gantt.dateFromPos(left + gantt.$task.offsetWidth);
gantt.config.start_date = gantt.config.start_date || gantt.getState().min_date;
gantt.config.end_date = gantt.config.end_date || gantt.getState().max_date;
const min_allowed_date = gantt.date.add(gantt.config.start_date, 1, "day");
const max_allowed_date = gantt.date.add(gantt.config.end_date, -2, "day");
let repaint = false;
if (+left_date <= +min_allowed_date) {
gantt.config.start_date = gantt.date.add(gantt.config.start_date, -2, "day");
repaint = true;
}
if (+right_date >= +max_allowed_date) {
gantt.config.end_date = gantt.date.add(gantt.config.end_date, 2, "day");
repaint = true;
}
if (repaint) {
setTimeout(function () {
gantt.render();
gantt.showDate(left_date);
}, 20);
}
});
Related sample: Gantt. Бесконечная прокрутка при использовании полосы прокрутки
Проверяйте позицию прокрутки во время перемещения, и если она близка к краям временной шкалы, расширяйте диапазон дат.
gantt.attachEvent("onMouseMove", function (id, e) {
if (!gantt.getState().drag_id && e.buttons == 1) {
const left_date = gantt.dateFromPos(gantt.getScrollState().x);
const right_date = gantt.dateFromPos(
gantt.getScrollState().x + gantt.$task.offsetWidth - 1
);
if (left_date && +left_date <= +gantt.config.start_date) {
gantt.config.start_date = gantt.date.add(gantt.config.start_date, -1, 'day');
gantt.render();
}
if (right_date && +gantt.config.end_date < +gantt.date.add(right_date, 1, 'day')) {
gantt.config.end_date = gantt.date.add(gantt.config.end_date, 1, 'day');
gantt.render();
}
}
});
Related sample: Gantt. Бесконечная прокрутка при перемещении временной шкалы
Если диапазон дат не установлен, просто вызовите render(), когда задача перемещается вблизи краев временной шкалы.
gantt.init("gantt_here");
gantt.parse(tasks);
gantt.attachEvent("onTaskDrag", function (id, mode, task, original) {
if (task.start_date <= gantt.getState().min_date ||
task.end_date >= gantt.getState().max_date) {
gantt.render();
}
});
Если у вас установлен диапазон дат, настройте его по мере необходимости.
gantt.init("gantt_here");
gantt.parse(tasks);
gantt.config.start_date = new Date(2025, 02, 28);
gantt.config.end_date = new Date(2025, 03, 10);
gantt.render();
gantt.attachEvent("onTaskDrag", function (id, mode, task, original) {
if (+task.start_date <= +gantt.config.start_date) {
gantt.config.start_date = gantt.date.add(
gantt.config.start_date, -1, gantt.config.duration_unit
);
gantt.render();
}
if (+task.end_date >= +gantt.config.end_date) {
gantt.config.end_date = gantt.date.add(
gantt.config.end_date, 1, gantt.config.duration_unit
);
gantt.render();
}
});
Related sample: Gantt. Бесконечная прокрутка при перемещении задачи (явные настройки диапазона)
Вы можете использовать событие onGanttScroll для обнаружения момента, когда вы достигли последней видимой задачи, и загрузки дополнительных задач с помощью метода parse().
gantt.attachEvent("onGanttScroll", function (left, top) {
const visibleTasks = gantt.getVisibleTaskCount();
const lastVisibleTask = gantt.getTaskByIndex(visibleTasks - 1);
if (gantt.getTaskRowNode(lastVisibleTask.id)) {
const tasks = load_tasks();
gantt.parse(tasks);
}
});
Related sample: Gantt. Динамическая загрузка данных
Чтобы открыть или закрыть все задачи, используйте методы open() и close() в функции eachTask(). Обертывание этого в batchUpdate() гарантирует, что диаграмма обновится только один раз.
function collapseAll() {
gantt.batchUpdate(function () {
gantt.eachTask(function (task) {
gantt.close(task.id);
});
});
}
function expandAll() {
gantt.batchUpdate(function () {
gantt.eachTask(function (task) {
gantt.open(task.id);
});
});
}
Related sample: Gantt. Добавление кнопок сворачивания/разворачивания в заголовок Gantt
Related sample: Gantt. Сворачивание/разворачивание всех задач
Чтобы включить многострочный текст в заголовке грида, можно добавить следующий CSS:
.gantt_grid_head_text {
line-height: 12px;
white-space: normal;
}
Related sample: Gantt. Многострочный текст в заголовке грида
Для ячеек грида используйте этот CSS:
.gantt_tree_content, .gantt_task_content {
line-height: 12px;
white-space: normal;
overflow-wrap: break-word;
}
Related sample: Gantt. Многострочный текст в ячейках грида и временной шкале
Related sample: Gantt. Многострочный текст в ячейках столбца грида
Чтобы включить пользовательский столбец, измените параметр gantt.config.columns. Свойство name должно соответствовать свойству задачи, которое вы хотите отобразить, или вы можете использовать функцию template() для пользовательского контента.
gantt.config.columns = [
/*
другие столбцы
*/
{
name: "progress", label: "Прогресс", width: 50, resize: true, align: "center",
template: function (task) {
return Math.round(task.progress * 100) + "%";
}
},
/*
другие столбцы
*/
];
Related sample: Gantt. Пользовательский столбец с шаблоном для прогресса задачи
Related sample: Gantt. Пользовательский столбец с шаблоном для кнопок действий
Чтобы создать пользовательскую кнопку добавления, определите столбец в параметре gantt.config.columns. Избегайте названия add, чтобы предотвратить поведение по умолчанию. Используйте функцию template, чтобы вернуть HTML-кнопку с пользовательским обработчиком кликов.
gantt.config.columns = [
/*
другие столбцы
*/
{
name: "add_tasks", label: "+", width: 50, resize: true, align: "center",
template: function (task) {
return `<button onclick='addTask(${task.id})';>`;
}
},
];
Related sample: Gantt. Пользовательские столбцы с шаблонами для кнопок добавления (+)
Чтобы создать пользовательскую шкалу, необходимо определить пользовательскую единицу шкалы времени и реализовать логику расчета дат.
Вот пример создания пользовательской шкалы для рабочих смен (06:30, 18:30):
gantt.date.custom_scale_start = function (date) {
return date;
};
gantt.date.add_custom_scale = function (date, inc) {
let next = new Date(date)
if (!next.getMinutes()) {
gantt.date.day_start(next)
next = gantt.date.add(next, 6, "hour");
next = gantt.date.add(next, 30, "minute");
}
else {
next = gantt.date.add(next, 12 * inc, "hour");
}
return next
};
gantt.config.scales = [
{ unit: "day", step: 1, date: "%d" },
{ unit: "custom_scale", step: 1, date: "%H:%i" },
];
Related sample: Gantt. Пользовательские часы рабочих смен на шкале
Вот еще один пример, где вместо дней используются числа:
gantt.config.scales = [
{
unit: "day", step: 1, format: function (date) {
return gantt.getScale().trace_indexes[+date] + 1
}
}
]
Related sample: Gantt. Номера дней на шкале
Чтобы создать пользовательскую шкалу для 5-дневных рабочих недель, вы можете использовать следующий пример:
const weekScaleTemplate = function (date) {
const dateToStr = gantt.date.date_to_str("%d");
const endDate = gantt.date.add(gantt.date.add(date, 5, "day"), -1, "day");
return dateToStr(date) + " - " + dateToStr(endDate);
};
gantt.date.five_days_start = function (date) {
return date;
};
gantt.date.add_five_days = function (date, inc) {
if (date.getDay() == 0 || date.getDay() == 6) {
return gantt.date.add(date, 1 * inc, "day");
}
gantt.date.week_start(date);
return gantt.date.add(date, 5 * inc, "day");
};
gantt.config.scales = [
{ unit: "month", step: 1, format: "%F, %Y" },
{ unit: "five_days", step: 1, format: weekScaleTemplate },
];
gantt.ignore_time = function (date) {
return date.getDay() == 0 || date.getDay() == 6;
};
Related sample: 5-дневные рабочие недели на шкале
Для пользовательской шкалы, отображающей недели года (начиная с первого дня года), этот пример будет полезен:
gantt.date.custom_week_start = function (date) {
return date;
};
gantt.date.add_custom_week = function (date, inc) {
const year_start = new Date(date);
gantt.date.year_start(year_start);
const week_number = Math.round(gantt.calculateDuration(year_start, date) / 7);
const next_week = gantt.date.add(year_start, week_number + 1, "week");
if (next_week.getYear() != date.getYear()) {
gantt.date.year_start(next_week)
}
return next_week;
};
const custom_week_template = function (date) {
const year_start = gantt.date.year_start(new Date(date));
const week_number = Math.round(gantt.calculateDuration(year_start, date) / 7) + 1;
return "Week:" + week_number
}
gantt.config.scales = [
{ unit: 'custom_week', step: 1, template: custom_week_template },
{ unit: 'day', step: 1, format: "%d, %M" },
];
Related sample: Gantt. Недели года на шкале
Чтобы дублировать задачи, метод copy() создает глубокую копию объекта задачи. Вы можете затем изменить ID скопированной задачи и добавить её, используя addTask() или createTask().
Вот как добавить кнопку для клонирования задачи:
function clone_task(id) {
const task = gantt.getTask(id);
const clone = gantt.copy(task);
clone.id = +(new Date());
gantt.addTask(clone, clone.parent, clone.$index)
}
gantt.config.columns = [
/*
другие столбцы
*/
{
name: "clone", label: "клонировать", width: 44, template: function (task) {
return "<input type=button value='V' onclick=clone_task(" + task.id + ")>"
}
}
];
Related sample: Gantt. Клонирование задачи
Вот пример клонирования задачи вместе со всеми её подзадачами и связями:
let child_links;
let clone_original_ids_table;
function obtain_link_ids(id) {
const task = gantt.getTask(id);
const source_links = task.$source;
for (let i = 0; i < source_links.length; i++) {
child_links.push(source_links[i]);
}
}
function create_clone_original_ids_table(original_id, clone_id) {
clone_original_ids_table[original_id] = clone_id;
}
function clone_child_links() {
for (let i = 0; i < child_links.length; i++) {
const link = gantt.getLink(child_links[i]);
if (clone_original_ids_table[link.source] && clone_original_ids_table[link.target]){
const clone_link = {};
clone_link.id = gantt.uid();
clone_link.target = clone_original_ids_table[link.target];
clone_link.source = clone_original_ids_table[link.source];
clone_link.type = link.type;
gantt.addLink(clone_link)
}
}
}
function clone_children(id, new_parent) {
const children = gantt.getChildren(id)
for (let i = 0; i < children.length; i++) {
const child_original = gantt.getTask(children[i]);
const child_clone = gantt.copy(child_original);
child_clone.id = gantt.uid();
child_clone.parent = new_parent;
gantt.addTask(child_clone, child_clone.parent, child_clone.$index);
obtain_link_ids(child_original.id);
create_clone_original_ids_table(child_original.id, child_clone.id);
if (gantt.hasChild(child_original.id)) clone_children(
child_original.id, child_clone.id
);
}
}
function clone_task(id) {
const task = gantt.getTask(id);
const clone = gantt.copy(task);
clone.id = gantt.uid();
gantt.addTask(clone, clone.parent, clone.$index);
child_links = [];
obtain_link_ids(id);
clone_original_ids_table = {};
create_clone_original_ids_table(task.id, clone.id);
if (gantt.hasChild(id)) {
clone_children(id, clone.id)
}
clone_child_links()
}
gantt.config.order_branch = true;
gantt.config.order_branch_free = true;
gantt.config.columns = [
/*
другие столбцы
*/
{
name: "clone", label: "клонировать", width: 44, template: function (task) {
return "<input type=button value='V' onclick=clone_task(" + task.id + ")>"
}
}
];
Related sample: Gantt. Клонирование задачи со всеми её подзадачами и связями
Вот как включить копирование с помощью сочетаний клавиш (Ctrl + C для копирования, Ctrl + V для вставки в качестве подзадач):
gantt.plugins({
keyboard_navigation: true,
multiselect: true,
})
let tasks_to_copy = [];
gantt.ext.keyboardNavigation.addShortcut("ctrl+c", function (e) {
tasks_to_copy = [];
gantt.eachSelectedTask(function (task_id) {
tasks_to_copy.push(task_id);
});
}, "taskRow");
gantt.ext.keyboardNavigation.addShortcut("ctrl+v", function (e) {
const new_parent = gantt.getSelectedId();
for (let i = 0; i < tasks_to_copy.length; i++) {
const task = gantt.copy(gantt.getTask(tasks_to_copy[i]));
task.id = +new Date() + '+' + Math.floor(Math.random() * 10);
gantt.addTask(task, new_parent)
}
gantt.getTask(new_parent).$open = true;
gantt.render()
}, "taskRow");
Related sample: Gantt. Копирование и вставка задач через Ctrl+C, Ctrl+V
Чтобы включить пользовательские стили или дополнительные элементы в экспортируемый PDF, используйте режим raw и включайте стили в параметры header или footer.
Например, вы можете сохранить стили в переменной и включить их в заголовок:
const header = `
.gantt_bar_task {
background: orange;
}
.gantt_task_progress {
background-color: rgba(33, 33, 33, 0.17);
}
`
gantt.exportToPDF({
header: "<style>" + header + "</style>"
});
Related sample: Gantt. Экспорт Gantt в PDF (стили из переменной)
В качестве альтернативы вы можете извлечь стили из элемента <style>
на странице:
gantt.exportToPDF({
raw: true,
header: "<style>" + document.getElementById("styles").innerHTML + "</style>"
});
<style id='styles'>
.gantt_bar_task {
background: orange;
}
.gantt_task_progress {
background-color: rgba(33, 33, 33, 0.17);
}
</style>
Related sample: Gantt. Экспорт Gantt в PDF (стили из элемента <style>)
Related sample: Gantt. Экспорт Gantt с пользовательскими значками в PDF
Чтобы включить легенду в экспортируемый PDF:
Related sample: Gantt. Экспорт Gantt с легендой в PDF
Для экспорта диаграмм загрузки ресурсов или гистограмм:
Related sample: Gantt. Экспорт Gantt с диаграммой загрузки ресурсов в PDF
Related sample: Gantt. Экспорт Gantt с гистограммой ресурсов в PDF
Простой способ вычислить прогресс родительской задачи — пересчитывать его каждый раз, когда обновляется подзадача. Метод eachParent() удобен для обхода родительских задач.
Вот пример, в котором прогресс родительских задач определяется исключительно прогрессом их подзадач:
gantt.config.auto_types = true;
gantt.templates.progress_text = function (start, end, task) {
return "<span style='text-align:left;'>" + Math.round(task.progress * 100)
+ "% </span>";
};
gantt.init("gantt_here");
gantt.parse({
"data": [
...
]
});
gantt.attachEvent("onAfterTaskUpdate", function (id, task) {
parentProgress(id)
});
gantt.attachEvent("onTaskDrag", function (id, mode, task, original) {
if (mode == "progress") {
parentProgress(id)
}
});
gantt.attachEvent("onAfterTaskAdd", function (id) {
parentProgress(id)
});
gantt.attachEvent("onAfterTaskDelete", function (id, task) {
if (task.parent) {
const siblings = gantt.getChildren(task.parent);
if (siblings.length) {
parentProgress(siblings[0])
}
}
});
function parentProgress(id) {
gantt.eachParent(function (task) {
const children = gantt.getChildren(task.id);
let childProgress = 0;
for (let i = 0; i < children.length; i++) {
const child = gantt.getTask(children[i])
childProgress += (child.progress * 100);
}
task.progress = childProgress / children.length / 100;
}, id)
gantt.render();
}
Related sample: Gantt. Динамический расчет прогресса родительской задачи
В другом сценарии прогресс родительских задач может зависеть как от прогресса, так и от длительности подзадач:
function calculateSummaryProgress(task) {
if (task.type != gantt.config.types.project)
return task.progress;
var totalToDo = 0;
var totalDone = 0;
gantt.eachTask(function (child) {
if (child.type != gantt.config.types.project) {
totalToDo += child.duration;
totalDone += (child.progress || 0) * child.duration;
}
}, task.id);
if (!totalToDo) return 0;
else return totalDone / totalToDo;
}
function refreshSummaryProgress(id, submit) {
if (!gantt.isTaskExists(id))
return;
var task = gantt.getTask(id);
var newProgress = calculateSummaryProgress(task);
if (newProgress !== task.progress) {
task.progress = newProgress;
if (!submit) {
gantt.refreshTask(id);
} else {
gantt.updateTask(id);
}
}
if (!submit && gantt.getParent(id) !== gantt.config.root_id) {
refreshSummaryProgress(gantt.getParent(id), submit);
}
}
gantt.attachEvent("onParse", function () {
gantt.eachTask(function (task) {
task.progress = calculateSummaryProgress(task);
});
});
gantt.attachEvent("onAfterTaskUpdate", function (id) {
refreshSummaryProgress(gantt.getParent(id), true);
});
gantt.attachEvent("onTaskDrag", function (id) {
refreshSummaryProgress(gantt.getParent(id), false);
});
gantt.attachEvent("onAfterTaskAdd", function (id) {
refreshSummaryProgress(gantt.getParent(id), true);
});
(function () {
var idParentBeforeDeleteTask = 0;
gantt.attachEvent("onBeforeTaskDelete", function (id) {
idParentBeforeDeleteTask = gantt.getParent(id);
});
gantt.attachEvent("onAfterTaskDelete", function () {
refreshSummaryProgress(idParentBeforeDeleteTask, true);
});
})();
...
gantt.config.auto_types = true;
gantt.templates.progress_text = function (start, end, task) {
return "<span style='text-align:left;'>" + Math.round(task.progress * 100)
+ "% </span>";
};
gantt.templates.task_class = function (start, end, task) {
if (task.type == gantt.config.types.project)
return "hide_project_progress_drag";
};
Related sample: Calculate Progress of Summary Tasks
Метод addTaskLayer() позволяет отображать пользовательские HTML-элементы на временной шкале, обеспечивая вертикальное и горизонтальное перемещение задач.
Вот как вы можете сделать стандартную задачу переставляемой в гриде:
Related sample: Gantt. Вертикальная перестановка задач на временной шкале
Для разделенных задач вы можете их переставлять и даже размещать несколько задач на одной строке:
Related sample: Gantt. Вертикальная перестановка разделенных задач на временной шкале
Фиксирование столбцов в гриде можно реализовать с помощью CSS. Столбец, который вы хотите заморозить, должен иметь позицию 'relative'. Его параметр 'left' должен соответствовать позиции полосы прокрутки, и это можно динамически обновлять через обработчик события полосы прокрутки:
gantt.attachEvent("onGanttReady", function () {
const el = document.querySelector(".gantt_hor_scroll");
if (el) {
el.addEventListener('scroll', function () {
document.documentElement.style.setProperty(
'--gantt-frozen-column-scroll-left', el.scrollLeft + "px"
);
});
}
});
const textEditor = { type: "text", map_to: "text" };
const start_dateEditor = { type: "date", map_to: "start_date" };
const end_dateEditor = { type: "date", map_to: "end_date" };
const durationEditor = { type: "number", map_to: "duration", min: 0, max: 100 };
gantt.config.columns = [
{ name: "text", tree: true, width: 150, resize: true, editor: textEditor },
{ name: "start_date", align: "center", width: 120, resize: true,
editor: start_dateEditor },
{ name: "end_date", label: "End Time", align: "center", width: 120,
resize: true, editor: end_dateEditor },
{ name: "duration", align: "center", width: 80, resize: true,
editor: durationEditor },
{ name: "progress", label: "Прогресс", width: 80, align: "center",
resize: true },
{
name: "custom", label: "Пользовательский", width: 180, align: "center",
resize: true, template: function (task) {
return Math.round(Math.random() * 100)
}
},
{ name: "add", width: 44 }
];
gantt.config.layout = {
css: "gantt_container",
cols: [
{
rows: [
{
view: "grid", scrollable: true,
scrollX: "scrollHor1", scrollY: "scrollVer"
},
{
view: "scrollbar", id: "scrollHor1",
scroll: 'x', group: 'hor'
},
]
},
{ resizer: true, width: 1 },
{
rows: [
{
view: "timeline", scrollX: "scrollHor", scrollY: "scrollVer"
},
{
view: "scrollbar", id: "scrollHor",
scroll: 'x', group: 'hor'
},
]
},
{ view: "scrollbar", id: "scrollVer" }
]
}
Настройки CSS для фиксированных столбцов:
:root {
--gantt-frozen-column-scroll-left: 0px;
}
.gantt_cell:nth-child(1),
.gantt_grid_head_cell:nth-child(1) {
background: Azure;
position: relative;
left: var(--gantt-frozen-column-scroll-left);
}
.gantt_grid_editor_placeholder[data-column-name="text"] {
left: var(--gantt-frozen-column-scroll-left) !important;
}
.gantt_grid_head_cell:nth-child(1) {
z-index: 1;
}
Related sample: Gantt. Замороженный столбец в гриде (через CSS)
В качестве альтернативы вы можете использовать несколько видов грида, хотя это может не работать безупречно с встроенными редакторами:
gantt.config.columns = [
{ name: "start_date", align: "center", width: 80, resize: true },
{ name: "end_date", label: "Дата окончания", align: "center", width: 80, resize: true },
{ name: "duration", width: 60, align: "center", resize: true },
{ name: "progress", label: "Прогресс", width: 60, align: "center", resize: true },
{ name: "add", width: 44 }
];
const fixedColumn = {
columns: [
{ name: "text", tree: true, width: 200, resize: true },
]
};
gantt.config.layout = {
css: "gantt_container",
cols: [
{
width: 400,
//min_width: 100,
rows: [
{
group: "gantt",
cols: [
{
rows: [
{ view: 'grid', config: fixedColumn, bind: "task",
scrollY: 'gridScrollY' }
]
},
{
rows: [
{ view: 'grid', bind: "task", scrollX: 'gridScrollX',
scrollable: true, scrollY: 'gridScrollY' },
{ view: 'scrollbar', id: 'gridScrollX' }
]
},
{ view: 'scrollbar', id: 'gridScrollY' }
]
}
]
},
{ resizer: true, width: 1 },
{
rows: [
{
group: "gantt",
cols: [
{
rows: [
{ view: "timeline", scrollX: "scrollHor", scrollY: "scrollVer" },
{ view: "scrollbar", id: "scrollHor" }
]
},
{ view: 'scrollbar', id: 'scrollVer' }
]
}
]
}
]
}
Related sample: Gantt. Фиксированный столбец в гриде (несколько видов грида)
Хотя в Gantt нет прямой функции для добавления легенды, вы можете создать её вручную. Расширение Overlay может быть чем-то похожим, но не предоставляет большой гибкости.
Чтобы добавить легенду, вы можете создать HTML-элемент для неё и вставить его в контейнер Gantt:
gantt.$root.appendChild(legend);
Вот рабочий пример, где вы можете переключать легенду, нажимая кнопку "Переключить легенду":
Related sample: Gantt. Добавление информационной легенды
Для интерактивных легенд вы можете прикрепить слушатели событий непосредственно к элементу легенды или использовать делегирование событий на уровне корня Gantt:
gantt.event(gantt.$root, "click", function(e){
var closest = gantt.utils.dom.closest;
if(closest(e.target, ".gantt-legend")) {
gantt.message("Щелчок мыши внутри элемента легенды");
}
});
К началу