본문으로 건너뛰기

실습 방법

그리드/차트 전환 방법​

기본 레이아웃 구성(default layout configuration)을 사용하는 경우, show_grid 또는 show_chart 매개변수를 변경하고 render() 메서드를 사용하여 변경 사항을 다시 렌더링할 수 있습니다.

function toggleGrid(){
gantt.config.show_grid = !gantt.config.show_grid;
gantt.render();
}

관련 샘플 Gantt. Toggle grid (default layout)

function toggleChart(){
gantt.config.show_chart = !gantt.config.show_chart;
gantt.render();
}

관련 샘플 Gantt. Toggle timeline (default layout)

사용자 정의 레이아웃 구성(custom layout configuration)을 사용하는 경우, 그리드/타임라인이 있는 구성과 없는 구성을 각각 만들어야 합니다. 이들 사이를 전환하려면 gantt.config.layout 매개변수를 수정하고 변경 사항을 확인하기 위해 init() 메서드를 적용해야 합니다:

let showGrid = true;

function toggleGrid() {
showGrid = !showGrid;
if (showGrid) {
gantt.config.layout = gridAndChart; // 그리드와 타임라인이 포함된 레이아웃
}
else {
gantt.config.layout = onlyChart; // 타임라인만 있는 레이아웃
}
gantt.init("gantt_here");
}

관련 샘플 Gantt. Toggle grid (custom layout)

let showChart = true;

function toggleChart() {
showChart = !showChart;
if (showChart) {
gantt.config.layout = gridAndChart; // 그리드와 타임라인이 포함된 레이아웃
}
else {
gantt.config.layout = onlyGrid; // 그리드만 있는 레이아웃
}
gantt.init("gantt_here");
}

관련 샘플 Gantt. Toggle timeline (custom layout)

리소스 뷰를 토글하는 방법​

앞선 사용 사례와 마찬가지로, 리소스 뷰가 있는 구성과 없는 구성을 여러 개 만들어야 합니다. 이를 전환하려면 gantt.config.layout 매개변수를 수정하고 변경 사항을 확인하기 위해 init() 메서드를 적용해야 합니다:

let resourceChart = true;

function layoutChange() {
resourceChart = !resourceChart;
if (resourceChart) {
gantt.config.layout = resourceLayout;
}
else {
gantt.config.layout = noresourceLayout;
}
gantt.init("gantt_here");
};

관련 샘플 Gantt. Toggle resource load diagram

let histogramView = true;

function layoutChange() {
histogramView = !histogramView;
if (histogramView) {
gantt.config.layout = histogramLayout;
}
else {
gantt.config.layout = simpleLayout;
}
gantt.init("gantt_here");
};

관련 샘플 Gantt. Toggle resource histogram

또는 레이아웃 뷰(layout views)를 사용하고 Gantt를 다시 초기화하여 변경 사항을 확인하도록 레이아웃을 생성할 수도 있습니다:

관련 샘플 Gantt. Generate layout

타임라인에서 무한 스크롤을 구현하는 방법​

무한 스크롤을 구현하는 방법은 여러 가지가 있습니다. 그러나 대부분의 경우 표시되는 날짜 범위를 수정해야 합니다(gantt.config.start_date와 gantt.config.end_date 매개변수).

스크롤바를 사용할 때​

현재 스크롤 위치를 얻고 날짜 범위를 늘려야 합니다. 다만, Gantt의 재페인팅(repainting)을 너무 자주 수행하면 성능에 영향을 미치므로 타임아웃 후에 이를 수행해야 합니다:

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)
}
});

관련 샘플 Gantt. Infinite scroll while using scrollbar

타임라인을 끌 때​

현재 스크롤 위치를 확인하고 타임라인 시작이나 끝에 가까워지면 표시되는 날짜 범위를 늘려야 합니다:

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();
}
}
});

관련 샘플 Gantt. Infinite scroll while dragging the timeline

작업을 끌 때​

날짜 범위가 설정되어 있지 않으면 작업이 타임라인의 시작이나 끝 근처로 드래그될 때마다 [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. Infinite scroll while dragging a task (default range settings)

만약 date range이 설정되어 있다면 이를 수정해야 합니다:

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()
}
});

관련 샘플 Gantt. Infinite scroll while dragging a task (explicit range settings)

작업을 동적으로 로드하는 방법​

스크롤하여 마지막으로 보이는 작업에 도달했는지 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);
}
});

관련 샘플 Gantt. Load data dynamically

버튼으로 모든 작업 확장/축소하는 방법​

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)
})
})
}

관련 샘플 Gantt. Add collapse/expand buttons into Gantt header

관련 샘플 Gantt. Collapse/expand all tasks

그리드 셀/헤더에 여러 줄 표시 방법​

스타일 규칙을 조금 추가하면 이를 달성할 수 있습니다.

그리드 헤더의 경우:

.gantt_grid_head_text{
line-height: 12px;
white-space:normal;
}

관련 샘플 Gantt. Multiline text in the grid header

그리드 셀의 경우:

.gantt_tree_content, .gantt_task_content{
line-height: 12px;
white-space:normal;
overflow-wrap: break-word;
}

관련 샘플 Gantt. Multiline text in Grid cells and Timeline

관련 샘플 Gantt. Multiline text in cells of a Grid column

그리드에 사용자 정의 열 추가 방법​

사용자 정의 열을 추가하려면 gantt.config.columns 매개변수를 수정해야 합니다. name 매개변수를 지정하면 Gantt는 동일한 이름의 작업 속성 값을 반환합니다. 또한 template() 함수를 사용해 임의의 날짜나 HTML 요소를 반환할 수 있습니다.

gantt.config.columns = [
/*
다른 열들
*/
{
name: "progress", label: "Progress", width: 50, resize: true, align: "center",
template: function (task) {
return Math.round(task.progress * 100) + "%"
}
},
/*
다른 열들
*/
];

관련 샘플 Gantt. Custom column with template for task progress

관련 샘플 Gantt. Custom column with template for action buttons

커스텀 add(+) 버튼 추가 방법​

[l gantt.config.columns] 매개변수를 통해 커스텀 열을 만들어야 합니다. 해당 열에 원하는 이름을 아무렇게나 설정할 수 있지만, add 이름은 예외적으로 사용할 수 없습니다. 그렇지 않으면 Gantt가 기본적인 add 열을 추가합니다. 그리드 열에서 HTML 요소를 반환하기 위해 [template] 함수를 사용할 수 있습니다. 즉, 버튼을 반환하고 작업 추가를 위한 커스텀 함수에 클릭 이벤트를 연결할 수 있습니다.

gantt.config.columns = [
/*
다른 열들
*/
{
name: "add_tasks", label: "+", width: 50, resize: true, align: "center",
template: function (task) {
return `<button onclick='addTask(${task.id})';>`
}
},
];

관련 샘플 Gantt. Custom columns with templates for add (+) buttons

커스텀 눈금 추가 방법​

custom scale unit를 만들고 날짜를 계산하는 로직을 추가해야 합니다.

작업 교대 시간(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" },
];

관련 샘플 Gantt. Custom work shift hours on the scale

일수가 아닌 숫자로 된 커스텀 눈금 예시:

gantt.config.scales = [
{
unit: "day", step: 1, format: function (date) {
return gantt.getScale().trace_indexes[+date] + 1
}
}
]

관련 샘플 Gantt. Numbers of days on the scale

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;
};

관련 샘플 5-day work weeks on the scale

연도 주 단위 눈금의 예시(해당 주의 번호는 연초부터 시작):

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" },
];

관련 샘플 Gantt. Weeks of the year on the scale

작업 복사 및 붙여넣기 방법​

작업 객체의 깊은 복사본을 만들기 위해 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: "clone", width: 44, template: function (task) {
return "<input type="button" value='V' onclick="clone_task("" + task.id + ")/>"
}
}
];

관련 샘플 Gantt. Clone a task

다음 예제는 모든 하위 작업과 링크를 포함해 작업을 복제하는 방법을 보여줍니다:

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: "clone", width: 44, template: function (task) {
return "<input type="button" value='V' onclick="clone_task("" + task.id + ")/>"
}
}
];

관련 샘플 Gantt. Clone a task with all its subtasks and links

다음 예시는 키 네비게이션으로 복사를 구현하는 방법을 보여줍니다(작업을 선택하고, 단축키 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");

관련 샘플 Gantt. Copy and paste tasks via Ctrl+C, Ctrl+V

내보낸 PDF 파일에 리소스 차트나 커스텀 스타일 추가 방법​

데이터를 [raw] 모드로 내보내고 export 함수의 header 또는 footer 매개변수에 스타일을 포함해야 합니다.

예를 들어, 커스텀 스타일을 변수에 저장한 후 [header] 매개변수에 해당 변수를 추가할 수 있습니다:

const header = `
.gantt_bar_task {
background: orange;
}

.gantt_task_progress {
background-color: rgba(33, 33, 33, 0.17);
}
`

gantt.exportToPDF({
header: "<style>" + header + "</style>"
});

관련 샘플 Gantt. Export Gantt to PDF (styles from a variable)

또는 페이지에서 <style> 요소를 찾아 그 내용을 아래와 같이 header에 삽입할 수 있습니다:

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>

관련 샘플 Gantt. Export Gantt to PDF (styles from <style> element)

관련 샘플 Gantt. Export Gantt with custom icons to PDF

작업에 대한 범례를 내보내는 예시:

관련 샘플 Gantt. Export Gantt with legend to PDF

리소스 로드 다이어그램과 히스토그램을 내보내는 예시들:

관련 샘플 Gantt. Export Gantt with resource load diagram to PDF

관련 샘플 Gantt. Export Gantt with resource histogram to 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();
}

관련 샘플 Gantt. Calculate progress of a parent task dynamically

다음 예제에서는 부모 작업의 진행률이 자식 작업의 진행률과 지속 시간에 따라 달라집니다:

function calculateSummaryProgress(task) {
if (task.type !== gantt.config.types.project) return task.progress;

let totalToDo = 0;
let totalDone = 0;

gantt.eachTask(child => {
if (child.type !== gantt.config.types.project) {
totalToDo += child.duration;
totalDone += (child.progress || 0) * child.duration;
}
}, task.id);

return totalToDo ? totalDone / totalToDo : 0;
}

function refreshSummaryProgress(id, submit) {
if (!gantt.isTaskExists(id)) return;

const task = gantt.getTask(id);
const 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", () => {
gantt.eachTask(task => {
task.progress = calculateSummaryProgress(task);
});
});

gantt.attachEvent("onAfterTaskUpdate", id => {
refreshSummaryProgress(gantt.getParent(id), true);
});

gantt.attachEvent("onTaskDrag", id => {
refreshSummaryProgress(gantt.getParent(id), false);
});

gantt.attachEvent("onAfterTaskAdd", id => {
refreshSummaryProgress(gantt.getParent(id), true);
});

(() => {
let idParentBeforeDeleteTask = 0;

gantt.attachEvent("onBeforeTaskDelete", id => {
idParentBeforeDeleteTask = gantt.getParent(id);
});

gantt.attachEvent("onAfterTaskDelete", () => {
refreshSummaryProgress(idParentBeforeDeleteTask, true);
});
})();

gantt.config.auto_types = true;

gantt.templates.progress_text = (start, end, task) =>
`<span style='text-align:left;'>${Math.round(task.progress * 100)}% </span>`;

gantt.templates.task_class = (start, end, task) =>
task.type === gantt.config.types.project ? "hide_project_progress_drag" : "";

Calculate Progress of Summary Tasks

타임라인에서 작업을 수직으로 재배열하는 방법​

타임라인에 커스텀 HTML 요소를 표시하고 이를 수직 및 수평으로 드래그할 수 있게 하려면 addTaskLayer() 메서드를 사용할 수 있습니다.

다음 예제에서는 그리드에서의 일반적인 작업 재배열처럼 작동합니다:

관련 샘플 Gantt. Reorder tasks vertically in timeline

다음 예제에서는 분할 작업을 재배열하고 같은 행에 작업을 배치할 수 있습니다:

관련 샘플 Gantt. Reorder split tasks vertically in timeline

그리드의 열을 고정하는 방법​

CSS를 사용하여 고정해야 하는 열에 대해 'relative' 위치를 설정하면 됩니다. 'left' 매개변수는 스크롤바 위치와 동일한 값을 가지도록 설정해야 하므로 스크롤바 이벤트 핸들러를 추가하고 CSS 변수를 업데이트해야 합니다:

gantt.attachEvent("onGanttReady", () => {
const el = document.querySelector(".gantt_hor_scroll");
if (el) {
el.addEventListener("scroll", () => {
document.documentElement.style.setProperty(
"--gantt-frozen-column-scroll-left",
`${el.scrollLeft}px`
);
});
}
});

const textEditor = { type: "text", map_to: "text" };
const startDateEditor = { type: "date", map_to: "start_date" };
const endDateEditor = { 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: startDateEditor },
{ name: "end_date", label: "End Time", align: "center", width: 120, resize: true,
editor: endDateEditor },
{ name: "duration", align: "center", width: 80, resize: true,
editor: durationEditor },
{ name: "progress", label: "Progress", width: 80, align: "center", resize: true },
{ name: "custom", label: "Custom", width: 180, align: "center", resize: true,
template: task => 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", croll: "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;
}

관련 샘플 Gantt. Frozen column in Grid (via CSS)

다른 방법으로는 several grid views를 추가하는 것이지만, 인라인 편집기와는 잘 맞지 않습니다:

gantt.config.columns = [
{ name: "start_date", align: "center", width: 80, resize: true },
{ name: "end_date", label: "End Date", align: "center", width: 80, resize: true },
{ name: "duration", width: 60, align: "center", resize: true },
{ name: "progress", label: "Progress", 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,
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" }
]
}
]
}
]
};

관련 샘플 Gantt. Fixed column in Grid (several grid views)

Gantt에 범례를 추가하는 방법​

Gantt에 범례를 표시하는 내장 메서드는 없으며, 가장 가까운 것은 Overlay 확장 기능이지만 완전히 동일하지는 않으며 쉽게 커스터마이즈하기 어렵습니다.

다만 범례는 비교적 간단하게 구현할 수 있습니다. HTML로 범례 요소를 코드로 작성한 뒤 이를 Gantt 노드에 주입하면 됩니다:

gantt.$root.appendChild(legend);

다음은 범례를 표시하는 라이브 예시로, 상단의 "Toggle legend" 버튼을 누르면 범례가 표시됩니다:

관련 샘플 Gantt. Add information legend

인터랙티비티를 추가하려면 DOM 이벤트 리스너를 직접 범례 요소에 추가하거나, 루트 레벨에서 DOM 이벤트를 수신하는 방식(event delegation)을 사용할 수 있습니다:

gantt.event(gantt.$root, "click", function(e){
const closest = gantt.utils.dom.closest;
if(closest(e.target, ".gantt-legend")) {
gantt.message("Mouse click inside the legend element");
}
});
Need help?
Got a question about the documentation? Reach out to our technical support team for help and guidance. For custom component solutions, visit the Services page.