README
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" | "ja" 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: ",", ja: "."};
// 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", ja: "YYYY/MM/DD"};
localeFirstWeekDay: {[key: string]: number} = {en: 0, uk: 1, ru: 1, ja: 0}; // 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.0make grid columns resizableadded in 0.2.2add 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)