Привет, меня зовут Женя, и я просто еще один из обитателей JavaScript вселенной, который хочет поделиться с вами интересным опытом в frontend-разработке, а именно как кастомизировать диаграмму Ганта. Не так давно я присоединился к команде энтузиастов, которая работает над проектом по производству оборудования для ремонта автомобилей. Как и для любого проектного менеджмента, нам нужен был инструмент для планирования задач с следующим функционалом: Во многих современных приложениях для управления проектами для решения таких задач используются диаграммы Ганта. И я взялся за реализацию ее функциональности в нашем приложении. Хотя можно было бы использовать готовый софт, в нашем случае нужно было сильно кастомизировать Гант под нужды проекта. Альтернатива разработки диаграммы с нуля — это слишком накладное и времязатратное мероприятие. Посовещавшись с коллегами, мы решили, что лучше всего найти готовый компонент среди библиотек JavaScript и настроить его под наш проект. Основная проблема диаграмм Ганта заключается в том, что с большим количеством данных они становятся громоздкими и трудными для восприятия и управления. При поиске подходящей библиотеки мы выделили три основных критерия: Один из иностранных коллег уберег меня от долгих скитаний по просторам интернета в поисках необходимого виджета и подсказал JavaScript библиотеку DHTMLX Gantt. Ознакомившись с функциональными возможностями продукта, я решил, что стоит попробовать — библиотека удовлетворила наши требованиям по настройке диаграммы и оказалась простой в использовании. Сама библиотека доступна в двух версиях — бесплатной и платной: Для нашего проекта хватает фич бесплатной версии — ее мы и решили использовать. Насколько я понял, загвоздка с GPL лицензиями и GPLv2 конкретно в том, что они требуют раскрывать исходный код (TLDRlegal). При этом не очень понятно, какой именно код веб приложения надо открывать — все приложение/только front-end/только код, который взаимодействует с библиотекой. Но так как наш проект мы делаем для внутренних нужд и не планируем никому распространять, как я понимаю, нас требование раскрытия кода не коснется. Если мы когда-нибудь решим продавать наше приложение другим предприятиям, тогда придется купить платную лицензию. В этой статье я хочу поделиться с вами несколькими приемами работы с DHTMLX JavaScript Гантом. Я не стану расписывать все детали по настройке Ганта, но расскажу о наиболее интересных фишках, которые пригодились мне в работе.  Для проекта мне нужно было предоставить возможность пользователям обозначать задачи на диаграмме Ганта разными цветами прямо из интерфейса.   В DHTMLX Gantt контент можно редактировать двумя способами: Второй вариант редактирования задач как раз оказался тем, что мне нужно. Используя DHTMLX Gantt, я без труда смог реализовать свой тип редактора для выбора цвета — color picker, позволяющий присваивать цвет задачам проекта. Далее я подробно расскажу о реализации этой функциональности. Пример я покажу на простом HTML5 и JavaScript, чтобы не требовалась сборка и было максимально понятно и без лишних сложностей. Для начала нужно инициализировать Гант на странице. Для этого нужно подключить JS и CSS файлы библиотеки из коробки, а затем создать контейнер, в котором инициализировать Гант (подробная инструкция тут): Прямо в HTML файле или же отдельно в js файле, после инициализации Ганта, нужно добавить данные, на основании которых Гант построит диаграмму. Для примера я добавлю тут 1 проект (Открытие производства оборудования) и 2 вложенные в него задачи (Определение рынка сбыта и Определение маркетинговой стратегии). Тут также задаются даты начала задач, их длительность, порядок выполнения и прогресс (степень выполнения задач):  Это самая простая часть. Опция встроенного редактирования позволяет вносить любые изменения прямо в таблице с помощью клавиатуры и мышки: создавать и обновлять задачи, устанавливать связи между ними, определять даты начала и окончания выполнения задачи или изменять общее отведенное на задачу время. Колонку можно сделать редактируемой, добавив к ней свойство editor: Объект редактора должен иметь свойство type, которое соответствует нужному типу редактора, и свойство map_to, которое определяет свойство объекта задачи, в которое редактор будет сохранять значения. Например, так настраивается редактор для полей с текстом, датами и длительностями задач: Остальные настройки относятся к определенным типам редакторов. Чтобы дать возможность пользователям присваивать цвета задачам, нужно добавить в таблицу соответствующий столбец и прикрутить в него подходящий редактор. Встроенного редактора для выбора цвета в библиотеке нет, поэтому вариантов у нас немного: использовать выпадающий список (select) или сделать новый редактор с селектором цвета (color picker). Я решил пойти по второму пути, то есть создать редактор-colorpicker. Сначала я покажу на примере, как встроить простой HTML5 элемент формы input с типом color, чтобы выбирать цвет задачи. Для создания собственного редактора нужно добавить новый объект редактора в конфигурацию Ганта. Я сделал это по шаблону из документации: Чтобы создать свой редактор, я внес следующие изменения в код шаблона: Первым делом я изменил название моего редактора и поменял функцию show, чтобы изменить тип вводимых данных на color:  Метод hide мне не понадобился, поскольку элементу выбора цвета не требуется никаких деструкторов или постобработки после того, как он становится скрытым, поэтому я оставил его пустым: Далее — методы set_value и get_value: Первый метод вызывается при открытии редактора, чтобы установить значение из объекта task. Второй метод вызывается, когда пользователь сохраняет редактор, а возвращаемое значение применяется к объекту задачи. Следующая на очереди функция is_changed. Поскольку редакторы можно легко открывать и закрывать, я задал инициирование изменения данных только тогда, когда пользователь фактически меняет значение редактора: Внутри этого метода сравнивается исходное значение, определенное для редактора, с текущим значением и возвращается логическое значение true, если показатели различаются. Значение true обновит задачу новым значением, а false просто закроет редактор. Принцип работы метода is_valid полностью соответствует своему названию и, возвращая false, сообщает Ганту, что введенное значение недопустимо и его необходимо сбросить: Метод save мне не понадобился, так как он необходим для сложных редакторов, которые выполняют несколько изменений сразу, а не изменяют одно свойство задачи. Использование метода focus помогло поместить фокус окна браузера в редактор: В итоге я получил свой собственный редактор для выбора цвета задачи в Ганте. Далее мне нужно было добавить этот редактор в мой Гантт.
Для этого я добавил новый столбец к конфигу таблицы и привязал к нему конфиг редактора. Свойство type редактора цвета должно соответствовать значению для редактора, которое я использовал выше (в моем случае type: “color”). Я использовал свойство color, поскольку Гант автоматически применит цвета из этого свойства. Теперь можно посмотреть, как все работает, если добавить к задачам значение цвета — например, color:"#FF0000":  В качестве последнего штриха, я сделал так, чтобы цвета внутри столбца “color” отображались красиво. Для этого я использовал шаблон: Я задал шаблон, который будет возвращать элемент контейнера div с указанным в стилях цветом фона. В файле css я добавил стили, чтобы красиво отображать цвет в контейнере:  Реализованный пример с кодом можно посмотреть по ссылке: https://plnkr.co/edit/yGWtLzoELPrhJV2K?preview Поскольку в DHTMLX Gantt изменять цвета можно только через селект, то я решил использовать более гибкий способ для обозначения задач цветом, а именно интегрировать в Гант плагин jquery под названием Spectrum.  Первым шагом я добавил файлы библиотеки в Гант: После этого обновил контрол Ганта. Я задал переменную let editor, где будет храниться ссылка на наш редактор. Это необходимо, чтобы вызвать деструктор, когда элемент input будет скрыт.
Сначала я внес изменения в метод show. Когда он вызывается, необходимо инициализировать и отобразить виджет селектора цвета. На этом месте возникла неожиданная сложность: если вызывать editor.spectrum("show") внутри метода show, редактор не появляется. Видимо, в момент вызова show placeholder-элемент еще не добавлен в документ и у него нет размеров и позиции. В итоге я просто добавил минимальный тайм-аут, чтобы запускать color picker уже после того, как метод завершился и placeholder висит над нужным местом в таблице.  Далее я определил метод “hide” — деструктор будет вызван, когда редактор будет закрыт: Остальные методы не слишком отличаются от первоначальной реализации. Просто нужно изменить способ получения значений из контрола:  После этого все должно работать как положено! А это ссылка на мой пример со встроенным Color Picker. Надеюсь, что эта статья поможет вам в настройке цвета задач в диаграмме Ганта. Веб-разработчик