TsGantt
Simple library for creating gantt chart combined with task grid.
Current features
- highly customizable
- contains two resizable parts: task grid and Gantt chart
- resizable grid columns
- tree-like structure with expandable and selectable rows
- support for tasks with two date pairs (planned and actual)
- single or multiple row selection mode
- localization support
- three out-of-box supported languages: English, Ukrainian, Russian
- custom locales support
- instant locale switching
- configurable chart
- four available chart scales: day, week, month, year
- three available chart display modes: planned dates, actual dates, both
- instant chart scale and display mode switching
- written completely in Typescript
- light codebase: only one dependency (lightweight Day.js is used to work with dates)
Getting started
Install and initialize
With npm
npm install ts-gantt
import { TsGantt } from "ts-gantt";
const chart = new TsGantt("#container-selector");
include stylesheet ('ts-gantt/dist/styles.min.css') in any suitable way
Or using CDN
<link rel="stylesheet" href="https://unpkg.com/ts-gantt/dist/styles.min.css">
<script src="https://unpkg.com/ts-gantt/dist/ts-gantt.umd.min.js"></script>
const chart = new tsGantt.TsGantt("#container-selector");
⚠️ for chart to function properly its container element must have relative, absolute or fixed position!
Set your task list
your tasks must implement following interface
interface TsGanttTaskModel {
id: string; // to avoid incorrect behaviour please use unique ids within array
parentId: string | null | undefined; // use if you need tree-like structure
name: string;
progress: number; // percentage from 0 to 100. higher or lower values will be truncated
datePlannedStart: Date | null | undefined;
datePlannedEnd: Date | null | undefined;
dateActualStart: Date | null | undefined;
dateActualEnd: Date | null | undefined;
localizedNames: {[key: string]: string} | null | undefined; // eg {"en": "Name", "uk": "Ім'я", "ru": "Имя"}
}
to pass your task array to chart use 'tasks' property setter
chart.tasks = yourTaskArray;
task are updated in the same way. you should just pass actual task array when any change happens. change detection will find tasks that have been changed/added/removed and will replace/add/remove them in chart.
Switch modes
Language
you can instantly switch chart language
chart.locale = locale; // "en" | "uk" | "ru" or any custom locale you provided in chart options
Timeline scale
you can instantly switch chart timeline scale
chart.chartScale = scale; // "day" | "week" | "month" | "year"
Display mode (chart bars)
you can instantly switch chart bar display mode
chart.chartDisplayMode = mode; // "planned" | "actual" | "both"
"planned" - show only planned dates bar on timeline
"actual" - show only actual dates bar on timeline
Select tasks
select task rows programmatically
chart.selectedTasks = [{id: "taskIdString"}];
get selected tasks
const selectedTasks = chart.selectedTasks;
Customize chart
you can customize chart in two ways:
- edit or override styles in styles.css file
- provide custom options to 'TsGantt' class constructor
Css
preffered way to customize styling is to change css variable values
:root {
--tsg-table-min-width: 100px;
--tsg-chart-min-width: 100px;
--tsg-nesting-indent: 20px; /* indent width per nesting level */
--tsg-background-color: white;
--tsg-foreground-color: black;
--tsg-separator-color: rgb(80, 80, 80); /* color of movable vertical line between parts */
--tsg-header-color: rgb(210, 210, 210); /* header background color */
--tsg-border-color: rgb(190, 190, 190);
--tsg-symbol-color: rgb(80, 80, 80); /* color of row special symbols */
--tsg-selection-color: rgb(230, 230, 230); /* background color of selected row */
--tsg-not-started-fg-color: dimgray; /* color of task row text depending on task state */
--tsg-in-progress-fg-color: black;
--tsg-overdue-fg-color: darkred;
--tsg-completed-fg-color: darkgreen;
--tsg-completed-late-fg-color: sienna;
--tsg-today-line-color: orangered; /* color of vertical line on chart that represents today */
--tsg-chart-bar-color-1: skyblue; /* chart bars colors */
--tsg-chart-bar-color-2: lightcoral;
--tsg-chart-bar-accent-1: darkcyan;
--tsg-chart-bar-accent-2: darkred;
--tsg-font-family: 'Calibri', sans-serif;
--tsg-font-size: 14px;
--tsg-line-height: 16px;
--tsg-max-cell-text-lines: 2; /* max lines of multiline text */
}
Options
you can apply your custom options by passing options object as second parameter to 'TsGantt' constructor
const options = new TsGanttOptions({
multilineSelection: false,
// other options you want to change
});
// or you can use assignment expressions (come in handy for getters and formatters that refence options object itself)
options.columnValueGetters[0] = task =>
task.localizedNames && task.localizedNames[options.locale] || task.name; // value getter implementation for first column
// esm chart init with options
const chart = new TsGantt("#container-selector", options);
// umd chart init with options
const chart = new tsGantt.TsGantt("#container-selector", options);
// ⚠️chart class in not designed to allow changes in options instance after the chart initialization.
// such changes can lead to unpredictable behavior.
// to change locale, scale and display mode use appropriate TsGantt instance methods.
// if it's very necessary to change other options after chart init then you should destroy old chart instance and create new one.
this.chart.destroy();
this.chart = new TsGantt("#container-selector", options);
ℹ️ complete list of 'TsGanttOptions' class properties you can use
// some default values ommited for brevity. you can always see them in 'TsGanttOptions' source code
multilineSelection = true; // allow multiple rows to be selected at the same time
useCtrlKeyForMultilineSelection = false; // enable using ctrl key to select multiple rows
drawTodayLine = true; // draw a vertical line on chart that represents today
highlightRowsDependingOnTaskState = true; // change row text color depending on task state
// columns order: "Name", "Progress", "Start date planned", "End date planned",
// "Start date actual", "End date actual", "Duration planned", "Duration actual"
columnsMinWidthPx: number[]; // array of 8 values, one for each of 8 columns. 0 to disable column
columnsContentAlign: ("start" | "center" | "end")[]; // array of 8 values, one for each of 8 columns.
separatorWidthPx = 5; // vertical central line width
headerHeightPx = 90; // lower values are not recommended, but you can still try
rowHeightPx = 40; // lower values are not recommended, but you can still try
borderWidthPx = 1;
barStrokeWidthPx = 2;
barMarginPx = 2;
barCornerRadiusPx = 6;
// special row symbols. you can also use some HTML code
rowSymbols: TsGanttRowSymbols = {childless: "◆", collapsed: "⬘", expanded: "⬙"};
chartShowProgress = true; // indicating progress percentage on chart bar using different color
chartDisplayMode: "planned" | "actual" | "both";
chartScale: "day" | "week" | "month" | "year";
// optimal spare space on timeline edges in days
chartDateOffsetDays: {[key: string]: number} = {"day": 14, "week": 60, "month": 240, "year": 730};
// minimal spare space on timeline edges in days
// chart timeline is redrawn only when trespassing minimal distance to chart edge to nearest bar
chartDateOffsetDaysMin: {[key: string]: number} = {"day": 7, "week": 30, "month": 120, "year": 365};
// width of 1 day on timeline. not recommended to use lower values than default
chartDayWidthPx: {[key: string]: number} = {"day": 60, "week": 20, "month": 3, "year": 1};
locale = "en"; // default locale
localeDecimalSeparator: {[key: string]: string} = {en: ".", uk: ",", ru: ","};
// you can provide any format strings that supported by dayjs
localeDateFormat: {[key: string]: string} = {en: "MM/DD/YYYY", uk: "DD.MM.YYYY", ru: "DD.MM.YYYY"};
localeFirstWeekDay: {[key: string]: number} = {en: 0, uk: 1, ru: 1}; // Sunday is 0
localeDateMonths: {[key: string]: string[]}; // array of 12 string values for each locale. eg ["January", "February", ...etc]
localeDateDays: {[key: string]: string[]}; // array of 7 string values for each locale. eg ["Sunday", "Monday", ...etc]
localeDateDaysShort: {[key: string]: string[]}; // array of 7 string values for each locale. eg ["Su", "Mo", ...etc]
localeDateScale: {[key: string]: string[]}; // array of 3 string values for each locale. eg ["Weeks", "Months", "Years"]
localeHeaders: {[key: string]: string[]}; // array of 8 string values for each locale
localeDurationFormatters: {[key: string]: (duration: number) => string}; // duration formatter function for each locale
// default column value getters return localized values by taking into account all the properties assigned above
// but you can provide your own ones if you need more complex output
// returned value is assigned to cell's innerHTML property. so you can use html tags
columnValueGetters: ((a: TsGanttTask) => string)[]; // array of 8 string value getters for each locale
taskComparer: (taskA: TsGanttTask, taskB: TsGanttTask) => number; // you can provide here your custom task comparer
Event callbacks
you can pass callbacks for chart row events using TsGantt properties shown below
onRowClickCb: (model: TsGanttTaskModel, event: MouseEvent) => void;
onRowDoubleClickCb: (model: TsGanttTaskModel, event: MouseEvent) => void;
onRowContextMenuCb: (model: TsGanttTaskModel, event: MouseEvent) => void;
onSelectionChangeCb: (models: TsGanttTaskModel[]) => void;
context menu implementation is not provided, but you can implement your own using callback
TODO list
-
add optional multiple row selectionadded in 0.2.0 -
make grid columns resizableadded in 0.2.2 -
add callbacks on chart events (on row click/double click, selection change)added in 0.3.0 - allow grid column reorder
- add optional possibility to move/resize chart bars
- add tooltips on bar hover
- increase code coverage
- optimize task change detection
- add row virtualization (move grid to custom table implementation)