Загрузка данных

dhtmlxGantt поддерживает два формата данных для загрузки информации:

Для заполнения диаграммы Gantt данными вы можете использовать методы parse или load.

gantt.init("gantt_here");
gantt.load("tasks.json");

Related sample:  Basic initialization

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

Загрузка из объекта

Если вы хотите загрузить данные напрямую из объекта, используйте метод parse:

Loading from an inline data source

var data = {
  tasks:[
     {id:1, text:"Project #1", start_date:"01-04-2020", duration:18},
     {id:2, text:"Task #1", start_date:"02-04-2020", duration:8, parent:1},
     {id:3, text:"Task #2", start_date:"11-04-2020", duration:8, parent:1}
   ]
};
gantt.init("gantt_here");
gantt.parse(data);

Related sample:  Basic initialization

Если ваши объекты данных содержат одновременно "start_date" и "end_date", но значения дат включают только дату (например, 01-12-2021, без времени), может потребоваться дополнительная настройка. Подробнее смотрите в разделе Отображение даты окончания задачи и включительно конец периода.

Загрузка с сервера

На стороне клиента

Для получения данных с сервера используйте метод load:

gantt.html

gantt.init("gantt_here");
gantt.load("data.json");

Метод load отправляет AJAX-запрос по указанному URL и ожидает ответ с данными в одном из поддерживаемых форматов. Например:

data.json

{
  "tasks":[
     {"id":1, "text":"Project #1", "start_date":"01-04-2020", "duration":18},
     {"id":2, "text":"Task #1", "start_date":"02-04-2020","duration":8, "parent":1},
     {"id":3, "text":"Task #2", "start_date":"11-04-2020","duration":8, "parent":1}
  ],
  "links":[
     {"id":1, "source":1, "target":2, "type":"1"},
     {"id":2, "source":2, "target":3, "type":"0"}
  ]
}

Вы можете указать формат во втором аргументе метода: "json", "xml" или "oldxml".

gantt.load("data.xml", "xml");

На стороне сервера

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

Подробные инструкции и примеры кода для различных платформ смотрите в Интеграция с серверной стороной.

Например, в Node.js вы настраиваете маршрут сервера, который обрабатывает URL, по которому Gantt отправляет AJAX-запрос за данными.

gantt.load("/data");

Этот маршрут должен возвращать JSON примерно такого вида:

app.get("/data", function(req, res){
    db.query("SELECT * FROM gantt_tasks", function(err, rows){
        if (err) console.log(err);
        db.query("SELECT * FROM gantt_links", function(err, links){
            if (err) console.log(err);
            for (var i = 0; i < rows.length; i++){
                rows[i].start_date = rows[i].start_date.format("YYYY-MM-DD");
                rows[i].open = true;
            }
 
            res.send({ tasks:rows, links : links });
        });
    });
});

Все поддерживаемые форматы данных перечислены в Поддерживаемые форматы данных.

Загрузка дат задач

Определение расписания задачи

Есть три способа задать расписание задачи в данных:

  • start_date + duration
  • start_date + end_date
  • duration + end_date

Свойство, которое не указано, будет вычислено на основе двух других.

Related sample:  Backward planning

Свойство end_date имеет приоритет над duration. Если указаны все три параметра, Gantt проигнорирует duration и вычислит его на основе дат начала и окончания. Например:

{
    "id":"20", "text":"Project #2", 
    "start_date":"01-04-2025", 
    "duration":3, 
    "end_date":"05-04-2025", 
    "order":10,"progress":0.4, 
    "type": "project", "open": true
}
 
// На самом деле задача будет загружена с duration, вычисленным по датам начала и окончания:
{
    "id":"20", "text":"Project #2", 
    "start_date":"01-04-2025", 
    "duration":4, 
    "end_date":"05-04-2025", 
    "order":10,"progress":0.4, 
    "type": "project", "open": true
}

Использование ISO-формата даты

Gantt поддерживает ISO-формат даты. Для его использования необходимо переопределить функции парсинга и форматирования дат:

gantt.templates.parse_date = function(date) { 
    return new Date(date);
};
gantt.templates.format_date = function(date) { 
    return date.toISOString();
};

Динамическое изменение формата даты

Если вы хотите изменить формат даты на лету, обновите шаблон parse_date следующим образом:

var cfg = gantt.config;
var strToDate = gantt.date.str_to_date(cfg.date_format, cfg.server_utc);
 
gantt.templates.parse_date = function(date){
    return strToDate (date);
};

Отображение даты окончания задачи и включительно конец периода

В этом разделе объясняется, как правильно сохранять и отображать дату окончания задачи.

Сначала рассмотрим два распространённых сценария при работе с датами задач:

Сценарий 1

  • Длительность задачи измеряется в целых днях (duration_unit="day")
  • Данные задачи содержат даты начала и окончания в формате "%Y-%m-%d" или "%d-%m-%Y" (без времени)

Из-за того, как dhtmlxGantt интерпретирует и хранит даты окончания задач, результат может отличаться от ожидаемого.

Пример:

gantt.parse({ tasks: [
    { 
        id: 1,
        text: "Task 1",
        start_date: "22-12-2021",
        end_date: "22-12-2021"
    }
]}, links:[]);
 
console.log(gantt.getTask(1).end_date);
// 22 декабря 2021 00:00:00
 
console.log(gantt.getTask(1).duration);
// 0

В этом случае даты начала и окончания совпадают, поэтому длительность задачи равна нулю.

Сценарий 2

  • В гриде отображается End Date
  • Формат даты окончания не содержит времени
gantt.config.columns = [
    {name: "text", label: "Name", tree: true, width: 200, resize: true},
    {name: "duration", label: "Duration", width:80, align: "center", resize: true},
    {name: "start_date", label: "Start", width:80, align: "center", resize: true},
    {name: "end_date", label: "Finish", width:80, align: "center", resize: true}
];
 
gantt.init("gantt_here");
 
gantt.parse({ tasks: [
    { 
        id: 1,
        text: "Task 1",
        start_date: "02-04-2020",
        end_date: "02-04-2020"
    }
]}, links:[]);

Здесь в гриде дата окончания (end_date) отображается как 3 апреля, хотя задача фактически завершается в конце 2 апреля.

Далее объясняется, как Gantt хранит даты окончания.

Как Gantt хранит даты окончания

Даже если часть времени не указана (duration_unit = "day"), dhtmlxGantt всегда хранит даты как объекты JavaScript Date, которые содержат компоненты времени.

Формат хранения дат окончания:

  • Секунды и миллисекунды всегда равны нулю, так как Gantt не поддерживает единицы меньше одной минуты
  • Дата окончания указывает на начало дня (или часа), следующего за последним активным днём (или часом). Например:
    • Задача, начинающаяся 2 апреля и длящаяся 1 день, будет иметь даты начала и окончания: "02-04-2022 00:00:00 - 03-04-2022 00:00:00". Дата окончания указывает на начало 3 апреля.
    • Задача, начинающаяся 2 апреля в 13:00 и длящаяся 1 час, будет иметь даты: "02-04-2022 13:00:00 - 02-04-2022 14:00:00". Дата окончания указывает на начало следующего часа.

Если дата окончания отображается без времени, это может ввести в заблуждение. В примере из Сценария 2 даты выглядят как "02-04-2022 - 03-04-2022", что можно ошибочно интерпретировать как двухдневную задачу вместо однодневной.

Это стандартное поведение. Хотя оно может сбивать с толку, доступны настройки, позволяющие это изменить, о чём рассказывается в следующих разделах.

Как изменить поведение по умолчанию?

1) Первое, чего следует избегать — это изменение фактических дат задач, хранящихся в Gantt.

Возможно, вы захотите изменить даты задач при загрузке в Gantt, например, устанавливая дату окончания как 02-04-2022 23:59:59. Тем не менее, лучше не использовать этот подход, так как это может привести к конфликтам в расчетах длительности задач и авто-планировании.

Вместо этого рекомендуем использовать следующие методы:

2a) Чтобы изменить формат отображения дат окончания задач в Gantt (например, чтобы включить дату окончания в длительность задачи), вы можете переопределить шаблон task_end_date.

Рассмотрим задачу, начинающуюся 2 апреля 2020 года, с длительностью один день, и посмотрим, как шаблон влияет на дату окончания.

По умолчанию дата окончания задачи отображается как 3 апреля 2020 года (03-04-2020 00:00:00):

Но если использовать шаблон task_end_date, та же задача будет отображаться как завершающаяся 2 апреля 2020 года:

Пример кода:

// переопределяем конфигурацию колонок
gantt.config.columns = [
  {name: "wbs", label: "#", width: 60, align: "center", template: gantt.getWBSCode},
  {name: "text", label: "Name", tree: true, width: 200, resize: true},
  {name: "start_date", label: "Start", width:80, align: "center", resize: true},
  {name: "end_date", label: "Finish", width:80, align: "center", resize: true}, 
  {name:"add"}
];
 
// переопределяем шаблон
gantt.templates.task_end_date = function(date){
   return gantt.templates.task_date(new Date(date.valueOf() - 1)); 
};
 
var gridDateToStr = gantt.date.date_to_str("%Y-%m-%d");
gantt.templates.grid_date_format = function(date, column){
   if(column === "end_date"){
     return gridDateToStr(new Date(date.valueOf() - 1)); 
   }else{
     return gridDateToStr(date); 
   }
}
gantt.init("gantt_here");

Этот способ меняет отображение даты окончания задачи в гриде, заголовке lightbox и других местах, где отображается дата окончания.

Если вы используете формат включающей даты окончания и хотите, чтобы он корректно работал с inline editing в гриде, потребуется создать собственный редактор для редактирования включающих дат окончания, например:

// редактор для включающих дат окончания
// используем стандартный редактор, но переопределяем методы set_value/get_value
var dateEditor = gantt.config.editor_types.date;
gantt.config.editor_types.end_date = gantt.mixin({
    set_value: function(value, id, column, node){
        var correctedValue = gantt.date.add(value, -1, "day");
        return dateEditor.set_value.apply(this, [correctedValue, id, column, node]);
    },
    get_value: function(id, column, node) {
        var selectedValue = dateEditor.get_value.apply(this, [id, column, node]);
        return gantt.date.add(selectedValue, 1, "day");
    },
}, dateEditor);
 
var textEditor = {type: "text", map_to: "text"};
var startDateEditor = {type: "date", map_to: "start_date"};
var endDateEditor = {type: "end_date", map_to: "end_date"};
var durationEditor = {type: "number", map_to: "duration", min:0, max: 100};
 
gantt.config.columns = [
    {name: "text", label: "Name", tree: true, width: 200, editor: textEditor, 
        resize: true},
    {name: "duration", label: "Duration", width:80, align: "center", 
        editor: durationEditor, resize: true},
    {name: "start_date", label: "Start", width:140, align: "center", 
        editor: startDateEditor, resize: true},
    {name: "end_date", label: "Finish", width:140, align: "center", 
        editor: endDateEditor, resize: true}
];
 
// изменяем шаблоны lightbox и грида для отображения дат задач во включающем формате
gantt.templates.task_end_date = function(date){
    return gantt.templates.task_date(new Date(date.valueOf() - 1)); 
};
 
var gridDateToStr = gantt.date.date_to_str("%Y-%m-%d");
gantt.templates.grid_date_format = function(date, column){
    if(column === "end_date"){
        return gridDateToStr(new Date(date.valueOf() - 1)); 
    }else{
        return gridDateToStr(date); 
    }
}

Related sample:  Редактор включающей даты окончания

2b) Если другим частям вашего приложения нужны даты окончания, сохранённые во "включающем" формате (т.е. задача, начинающаяся 2 апреля 2020 года и длящаяся один день, хранится с start_date: "02-04-2022", end_date: "02-04-2022"), потребуется дополнительная обработка дат окончания:

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

Свойства данных

Источник данных для диаграммы Gantt — это объект, содержащий два основных типа информации:

  • tasks — элементы задач.
  • links — связи-зависимости.

Свойства объекта задачи

Полный список свойств объекта задачи приведён в статье Task properties.

Формат дат по умолчанию для JSON и XML данных — "%d-%m-%Y %H:%i" (см. спецификацию формата даты).
Чтобы изменить его, используйте опцию конфигурации date_format.

gantt.config.date_format="%Y-%m-%d";
gantt.init("gantt_here");

После загрузки в Gantt свойства start_date и end_date преобразуются в объекты Date.

Если ваши форматы дат не поддерживаются конфигом date_format, вы можете выполнить парсинг вручную с помощью шаблона parse_date.

Полный список свойств объекта связи доступен в статье Link properties.

Пользовательские свойства

Вы не ограничены обязательными свойствами и можете добавлять любые пользовательские свойства в ваши элементы данных. Дополнительные свойства будут распознаны как строки и отправлены на клиентскую сторону, где вы сможете использовать их по своему усмотрению.

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

Структура базы данных

Для работы с базой данных рекомендуется использовать две отдельные таблицы: одну для задач, другую — для связей.

Типичная структура базы данных для загрузки задач и связей в диаграмму Gantt выглядит так:

  • gantt_tasks — таблица для хранения задач Gantt
    • id — (string,number) идентификатор задачи.
    • start_date — (Date) дата начала задачи.
    • text — (string) описание задачи.
    • progress — (number) от 0 до 1, процент выполнения задачи.
    • duration — (number) длительность задачи в текущих единицах времени.
    • parent — (number) идентификатор родительской задачи.
    • type — (string) необязательное, тип задачи.
    • readonly — (boolean) необязательное, помечает задачу как только для чтения.
    • editable — (boolean) необязательное, помечает задачу как доступную для редактирования.
  • gantt_links — таблица для хранения связей Gantt
    • id — (string,number) идентификатор связи.
    • source — (number) идентификатор исходной задачи.
    • target — (number) идентификатор целевой задачи.
    • type — (string) тип зависимости:
      • 0 — 'finish_to_start'
      • 1 — 'start_to_start'
      • 2 — 'finish_to_finish'
      • 3 — 'start_to_finish'
    • lag — (number) необязательное, лаг задачи.
    • readonly — (boolean) необязательное, помечает связь как только для чтения.
    • editable — (boolean) необязательное, помечает связь как доступную для редактирования.

Для создания этих двух таблиц используйте следующий SQL:

CREATE TABLE `gantt_links` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `source` int(11) NOT NULL,
  `target` int(11) NOT NULL,
  `type` varchar(1) NOT NULL,
  PRIMARY KEY (`id`)
)
CREATE TABLE `gantt_tasks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `text` varchar(255) NOT NULL,
  `start_date` datetime NOT NULL,
  `duration` int(11) NOT NULL,
  `progress` float NOT NULL,
  `sortorder` int(11) NOT NULL,
  `parent` int(11) NOT NULL,
  PRIMARY KEY (`id`)
)

Поток событий

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

gantt.parse():

gantt.load()

gantt.refreshData():

gantt.render():

К началу