apexgantt 3.12.0 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +392 -13
- package/apexgantt.d.ts +170 -71
- package/apexgantt.es.min.js +1 -1
- package/apexgantt.min.js +1 -1
- package/demo/extended-columns.html +150 -0
- package/demo/grouping.html +187 -0
- package/demo/localization-rtl.html +341 -0
- package/demo/sort-filter.html +201 -0
- package/demo/split-tasks.html +168 -0
- package/demo/state-persistence.html +241 -0
- package/demo/task-list-columns-demo.html +21 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,32 +74,44 @@ The layout can be configured by passing a second argument to `ApexGantt` with th
|
|
|
74
74
|
| `snapUnit` | `'day' \| 'hour' \| 'minute'` | `'day'` | Granularity at which task drag, resize, and inline edits snap. Independent of timeline header tier. |
|
|
75
75
|
| `snapValue` | `number` | `1` | Multiplier applied to `snapUnit`, e.g. `snapUnit: 'minute', snapValue: 15` → 15-min steps. |
|
|
76
76
|
| `inputDateFormat` | `string` | `'MM-DD-YYYY'` | dayjs-compatible format used to parse `startTime` / `endTime` values. Include time tokens (e.g. `'YYYY-MM-DD HH:mm'`) to enable sub-day editing — inline-edit inputs switch to `datetime-local` automatically. |
|
|
77
|
+
| `locale` | `{ direction?: 'ltr' \| 'rtl' \| 'auto', dateLocale?: GanttDateLocale, messages?: Partial<GanttMessages> }` | `{ direction: 'ltr' }` | Localization, date-locale, and text-direction. See [Localization & RTL](#localization--rtl). |
|
|
77
78
|
| `canvasStyle` | `string` | `''` | Arbitrary CSS injected onto the root container element. |
|
|
78
79
|
| `backgroundColor` | `string` | `'#FFFFFF'` | Background color of the chart container. |
|
|
79
|
-
| `headerBackground` | `string` | `'#
|
|
80
|
-
| `rowHeight` | `number` | `
|
|
80
|
+
| `headerBackground` | `string` | `'#F8F9FB'` (light) / `'#2A2A2A'` (dark) | Background color of the header row. |
|
|
81
|
+
| `rowHeight` | `number` | `40` | Height of each task row in pixels. |
|
|
81
82
|
| `rowBackgroundColors` | `string[]` | `['#FFFFFF']` | Alternating row background colors; the pattern cycles automatically. |
|
|
82
83
|
| `tasksContainerWidth` | `number` | `425` | Initial pixel width of the task-list panel. |
|
|
83
84
|
| `columnConfig` | `ColumnListItem[]` | `undefined` | Custom column definitions for the task-list panel. Controls which columns are shown, their order, titles, and widths. See [Column Configuration](#column-configuration). |
|
|
85
|
+
| `sortBy` | `SortCriterion \| SortCriterion[]` | `[{ key: 'startTime', direction: 'asc' }]` | Initial sort for the task list. **Hierarchy-preserving**: siblings are reordered within each parent, never flattened. Each `SortCriterion` is `{ key, direction?: 'asc' \| 'desc' }`; pass an array for multi-key sort (first key wins, ties break on the next). Omit for the default (start-time ascending); pass `[]` for natural (input) order. Summary (parent) rows sort by their rolled-up span/value. See [Sorting & Filtering](#sorting--filtering). |
|
|
86
|
+
| `filterBy` | `(task: Task) => boolean` | `undefined` | Initial filter for the task list. A predicate run against each task; a task is kept when it **matches or has a matching descendant** (so ancestors of matches stay visible to preserve tree context). Filtering is view-only — it changes which rows render but not the tree, WBS, or task data. See [Sorting & Filtering](#sorting--filtering). |
|
|
87
|
+
| `enableQuickFilter` | `boolean` | `false` | Show a built-in quick-filter search box in the toolbar. Typing filters the task list to rows whose configured fields contain the query (ancestors of matches stay visible); clearing it removes the filter. Drives the same view-only filter as `gantt.filter()`. See [Sorting & Filtering](#sorting--filtering). |
|
|
88
|
+
| `quickFilter` | `QuickFilterOptions` | `undefined` | Fine-tunes the quick-filter box: `placeholder` (defaults to the localized `quickFilterPlaceholder` message), `fields` (task string fields matched against the query; default `['name']`), and `caseSensitive` (default `false`). |
|
|
89
|
+
| `filterRules` | `FilterRuleSet` | `undefined` | Initial structured filter (advanced filter builder): `{ match: 'all' \| 'any', rules: FilterRule[] }`. Each `FilterRule` is `{ field, operator, value? }`; combined with `'all'` (AND) or `'any'` (OR). Compiles to the same view-only filter as `filterBy` and takes precedence over it. See [Sorting & Filtering](#sorting--filtering). |
|
|
90
|
+
| `enableFilterBuilder` | `boolean` | `false` | Show a built-in advanced filter builder in the toolbar: a "Filter" button (with an active-rule count badge) that opens a popover for composing field/operator/value conditions combined with All / Any. Drives the same view-only filter as `gantt.setFilterRules()`. See [Sorting & Filtering](#sorting--filtering). |
|
|
91
|
+
| `groupBy` | `GroupCriterion \| ColumnKey \| string` | `undefined` | Initial grouping. When set, the parent/child tree is suspended and tasks are bucketed under collapsible group headers (label + member count). Pass a bare column key, or a `GroupCriterion` (`{ field, accessor?, label?, direction? }`) for custom value extraction, labelling, and header order. Also available at runtime via `gantt.groupBy()` / `gantt.clearGrouping()`. See [Grouping](#grouping). |
|
|
84
92
|
| `barBackgroundColor` | `string` | `'#318CE7'` (light) / `'#818CF8'` (dark) | Default background fill color for task bars. |
|
|
85
93
|
| `barBorderRadius` | `string` | `'5px'` | CSS border-radius applied to task bars. |
|
|
86
94
|
| `barMargin` | `number` | `4` | Top and bottom margin inside each row for the task bar. |
|
|
87
95
|
| `barTextColor` | `string` | `'#FFFFFF'` | Text color rendered inside task bars. |
|
|
88
96
|
| `barLabel` | `BarLabelOptions` | `{ position: 'right', field: 'name' }` | Per-task bar label. Defaults to `position: 'right'` so labels stay visible regardless of bar width. Set `position: 'inside'` to render centered inside the bar, `'left'` to render before it, or `'auto'` to pick between `'inside'` and `'right'` based on bar width; supply `render: (task) => string \| HTMLElement` to compose the name with chips, icons, or owner info. When `position: 'left'`, the timeline auto-reserves `120px` of leading space so labels don't disappear under the task-list panel — tune via `barLabel.leadingPadding`. Outside labels are not currently rendered for milestones. |
|
|
89
|
-
| `summaryBarColor` | `string` | `'#
|
|
97
|
+
| `summaryBarColor` | `string` | `'#94A3B8'` (light) / `'#8FBCBC'` (dark) | Fill color for summary (group) bars. |
|
|
90
98
|
| `milestoneColor` | `string` | `'#7C3AED'` (light) / `'#A78BFA'` (dark) | Fill color for milestone diamonds. |
|
|
91
99
|
| `arrowColor` | `string` | `'#94A3B8'` (light) / `'#94A3B8'` (dark) | Color of dependency arrows between tasks. Subtle slate-gray by default so links don't compete with bars. |
|
|
92
100
|
| `dependencies` | `DependencyOptions` | `{}` | Polish + editing for dependency arrows: `cornerRadius` (rounded joints), `hitWidth` (invisible thicker stroke for hover/click targeting), `tooltipTemplate: (ctx) => string` (HTML on hover — requires non-zero `hitWidth`), `classBuilder: (ctx) => string \| string[]` (per-arrow CSS class for cross-team / blocked / etc), `editable: boolean` (hover darkens the arrow, click selects it and reveals a "✕" affordance — click the ✕ or press <kbd>Delete</kbd> to remove via the undoable command path; on bar hover two anchor circles appear at the bar's start/finish edges, and dragging from one to another bar draws a dashed preview that commits the new dependency on release — the (source-anchor, target-anchor) pair determines the type: right→left FS, left→left SS, right→right FF, left→right SF), `allowSummaryDescendantLinks: boolean` (allow drawing edges between a summary task and its descendants; off by default since such edges confuse downstream date math). When `editable: true`, `hitWidth` is auto-bumped to at least `12` if unset. The `ctx` carries `fromTask`, `toTask`, `type`, and `lag`. |
|
|
93
101
|
| `calendar` | `CalendarOptions` | `undefined` | Working-calendar config. When set, weekends + holidays drive duration math, summary aggregation, and timeline stripes — durations stop counting calendar days and start counting working days. Fields: `workingWeekdays: number[]` (0 = Sunday … 6 = Saturday; default `[1, 2, 3, 4, 5]`), `holidays: Array<string \| Date \| { date, label? }>` (non-working dates regardless of weekday; mixed forms allowed), `showNonWorkingStripes: boolean` (render hatched bands over weekend/holiday columns; default `true`), `holidayTooltip: (ctx) => string` (optional HTML rendered when the user hovers a holiday stripe — `ctx.date` is the Date, `ctx.label` is whichever string was supplied in the matching entry), `dragSnapMode: 'next' \| 'previous' \| 'allow'` (what happens when a drag/resize commits onto a non-working day — `'next'` (default) snaps forward, `'previous'` snaps backward, `'allow'` permits non-working start/end. Drag preserves the source task's working-day duration across the snap; resize snaps the moving endpoint only. No effect when `snapUnit !== 'day'` or the input format carries time tokens). Absent calendar = today's behavior (every day is a working day, no stripes, no snap). |
|
|
94
|
-
| `borderColor` | `string` | `'#
|
|
95
|
-
| `cellBorderColor` | `string` | `'#
|
|
102
|
+
| `borderColor` | `string` | `'#E5E7EB'` (light) / `'#3A3A3A'` (dark) | Color of cell and row divider lines. |
|
|
103
|
+
| `cellBorderColor` | `string` | `'#EDEFF2'` (light) / `'#3A3A3A'` (dark) | Border color for all cells in the task table and timeline grid. |
|
|
96
104
|
| `cellBorderWidth` | `string` | `'1px'` | CSS border-width for all cell lines. |
|
|
97
105
|
| `columnLines` | `boolean` | `true` | Whether to draw vertical lines between timeline columns. Set to `false` for a cleaner look that keeps only the horizontal row dividers. |
|
|
98
106
|
| `enableProjectBoundary` | `boolean` | `false` | When `true`, two vertical lines mark the project's earliest start and latest end across all rows. Auto-recomputes when tasks are added, removed, or rescheduled. |
|
|
99
107
|
| `projectBoundaryColor` | `string` | `'#7C3AED'` | Stroke colour for the project-boundary lines. Falls back to `annotationBorderColor` when omitted. |
|
|
100
108
|
| `enableRollups` | `boolean` | `false` | When `true`, summary (parent) rows display thin rollup markers below the summary bar at each leaf descendant's date range. Useful for keeping children visible at a glance even when the parent is collapsed. |
|
|
101
109
|
| `enableResize` | `boolean` | `true` | Allow the task-list panel to be resized by dragging the divider. |
|
|
102
|
-
| `enableExport` | `boolean` | `true` | Show the
|
|
110
|
+
| `enableExport` | `boolean` | `true` | Show the export button in the toolbar. |
|
|
111
|
+
| `exportFormat` | `'svg' \| 'png' \| 'pdf'` | `'svg'` | Format produced by the toolbar export button. `svg` is vector; `png` rasterizes the chart; `pdf` embeds a raster on a single page. Any format is also available programmatically via `gantt.exportChart(format)`. |
|
|
112
|
+
| `autoSizeColumns` | `boolean` | `true` | Auto-size each task-list column to fit its header title and cell content, growing the panel (never below `tasksContainerWidth`) so nothing is clipped. `minWidth` sets a column's preferred (default) width and `maxWidth` (default `320px`) the ceiling. The panel stays freely resizable: dragging the divider stretches columns proportionally or shrinks them (down to a small floor, so a large `minWidth` never blocks resizing). Set `false` for the legacy behavior where the panel width is split purely by `flexGrow`. See [Column Configuration](#column-configuration). |
|
|
113
|
+
| `resizableColumns` | `boolean` | `true` | Allow individual columns to be resized by dragging the handle at the trailing edge of each column header. A resized column is pinned to its chosen pixel width and the other columns absorb the remaining space, so you can keep some columns wide and others thin. Double-click a handle to reset that column to its auto width. Opt a single column out with `columnConfig[].resizable: false`. Also available programmatically via `gantt.setColumnWidth()` / `gantt.resetColumnWidths()`. See [Column Configuration](#column-configuration). |
|
|
114
|
+
| `persistState` <a id="uistate"></a> | `boolean \| { key?: string }` | `false` | Persist and restore the UI view state (zoom, scroll, sort, filter, collapse, selection) via `localStorage`. `true` uses the default key (`'apexgantt-state'`); an object sets a custom `key`. Restored on the first `render()`; saved (debounced) whenever the view changes. Also available programmatically via `gantt.getState()` / `gantt.setState()`. See [UI state persistence](#ui-state-persistence). |
|
|
103
115
|
| `enableInlineEdit` | `boolean` | `false` | Allow editing task fields directly in the task-list cells (double-click to edit `name`, `startTime`, `endTime`, `duration`, `progress`). Auto-enabled when `enableTaskEdit` is `true`; set explicitly to `false` to opt out. See [Inline Editing](#inline-editing). |
|
|
104
116
|
| `enableTaskDrag` | `boolean` | `true` | Allow tasks to be reordered by dragging rows in the task list. |
|
|
105
117
|
| `enableTaskEdit` | `boolean` | `false` | Show the inline task-edit form when a task row is clicked. |
|
|
@@ -122,15 +134,15 @@ The layout can be configured by passing a second argument to `ApexGantt` with th
|
|
|
122
134
|
| `criticalBarColor` | `string` | `'#E53935'` (light) / `'#F87171'` (dark) | Fill color for task bars on the critical path. |
|
|
123
135
|
| `criticalArrowColor` | `string` | `'#E53935'` (light) / `'#F87171'` (dark) | Stroke color for dependency arrows on the critical path. |
|
|
124
136
|
| `enableCrosshair` | `boolean` | `false` | Show a vertical crosshair line that follows the cursor across the timeline, with a label showing the precise date/time at the pointer position. |
|
|
125
|
-
| `crosshairColor` | `string` | `'#
|
|
137
|
+
| `crosshairColor` | `string` | `'#3B82F6'` (light) / `'#818CF8'` (dark) | Color of the crosshair line and the label background. |
|
|
126
138
|
| `crosshairLabelFormat` | `(date, tier) => string` | _auto_ | Custom formatter for the crosshair label. Receives the date under the cursor and the active sub-tier (`'minute' \| 'hour' \| 'halfday' \| 'day' \| 'week' \| 'month' \| 'quarter' \| 'year'`). When omitted, the label auto-adapts to the active tier — `'ddd MM/DD/YYYY'` for day-and-coarser tiers, `'MM/DD HH:mm'` for halfday/hour/minute tiers. |
|
|
127
139
|
| `baseline` | `Partial<BaselineOptions>` | `undefined` | When `enabled: true`, renders a thin baseline bar below each task bar. Hovering the baseline shows a tooltip with its planned start/end dates. When `rowHeight` isn't explicitly set, the default rowHeight is bumped to make room for the baseline without squeezing the actual bar. Fields: `color: string` (primary fill / stripe color; default `'#9E9E9E'`), `striped: boolean` (fill the bar with thick diagonal stripes instead of a flat color; default `true`), `stripeColor: string` (color of the gaps between stripes; default `'#FFFFFF'`), `stripeWidth: number` (px width of each stripe band, larger values = thicker; default `3`), `stripeAngle: number` (stripe angle in degrees; default `45`). By default baselines render as thick grey/white diagonal stripes; set `striped: false` for a solid `color` fill. |
|
|
128
140
|
| `tooltipId` | `string` | `'apexgantt-tooltip-container'` | HTML `id` for the tooltip container element. |
|
|
129
141
|
| `tooltipTemplate` | `(task, dateFormat) => string` | built-in | Custom function returning an HTML string for the task tooltip. |
|
|
130
|
-
| `tooltipBorderColor` | `string` | `'#
|
|
142
|
+
| `tooltipBorderColor` | `string` | `'#E5E7EB'` (light) / `'#444444'` (dark) | Border color of the tooltip. |
|
|
131
143
|
| `tooltipBGColor` | `string` | `'#FFFFFF'` | Background color of the tooltip. |
|
|
132
|
-
| `fontColor` | `string` | `'#
|
|
133
|
-
| `fontFamily` | `string` | `''` | CSS font-family for the chart. |
|
|
144
|
+
| `fontColor` | `string` | `'#1F2933'` (light) / `'#E0E0E0'` (dark) | Color for all text in the chart. |
|
|
145
|
+
| `fontFamily` | `string` | `'system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'` | CSS font-family for the chart. |
|
|
134
146
|
| `fontSize` | `string` | `'14px'` | CSS font-size for the chart. |
|
|
135
147
|
| `fontWeight` | `string` | `'400'` | CSS font-weight for the chart. |
|
|
136
148
|
| `annotationBgColor` | `string` | `'#F9D1FC'` | Background color of annotation markers. |
|
|
@@ -143,6 +155,34 @@ The layout can be configured by passing a second argument to `ApexGantt` with th
|
|
|
143
155
|
| `toolbarItems` | `ToolbarItem[]` | `[]` | Custom controls rendered in the toolbar alongside the built-in zoom and export buttons. Each item can be a `ToolbarButton`, `ToolbarSelect`, or `ToolbarSeparator`. |
|
|
144
156
|
| `taskListAriaLabel` | `string` | `'Task list'` | `aria-label` for the task-list table, used by screen readers. |
|
|
145
157
|
|
|
158
|
+
### Localization & RTL
|
|
159
|
+
|
|
160
|
+
Pass a `locale` object to translate strings, localize dates, and flip text direction. With the defaults (`{ direction: 'ltr' }`, no `dateLocale`, no `messages`) the output is byte-for-byte unchanged.
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import localeFr from 'dayjs/locale/fr';
|
|
164
|
+
|
|
165
|
+
const gantt = new ApexGantt('#chart', {
|
|
166
|
+
series: tasks,
|
|
167
|
+
locale: {
|
|
168
|
+
direction: 'rtl',
|
|
169
|
+
dateLocale: localeFr, // months/weekdays in the timeline header render in French
|
|
170
|
+
messages: {
|
|
171
|
+
addTask: 'Ajouter une tâche',
|
|
172
|
+
editTaskTitle: (name) => `Modifier : ${name}`,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
| `locale` key | Type | Default | Description |
|
|
179
|
+
| --- | --- | --- | --- |
|
|
180
|
+
| `direction` | `'ltr' \| 'rtl' \| 'auto'` | `'ltr'` | Text/layout direction. `'rtl'` sets `dir="rtl"` on the container (flowing the toolbar, task list, task form, context menu, and tooltips right-to-left and moving the task-list panel to the right) **and mirrors the timeline time axis** so time flows right-to-left: the earliest date sits on the right, bars/header cells/grid lines/non-working stripes/dependency arrows/annotations are all mirrored, progress fills from the start (right) edge, and drag/resize/progress interactions are direction-aware. `'auto'` defers to the document/element. |
|
|
181
|
+
| `dateLocale` | `GanttDateLocale` (a `dayjs/locale/*` object) | `undefined` | Localizes every date, month, weekday, and quarter label the timeline renders. Import the dayjs locale object and pass it; ApexGantt registers it on its own bundled dayjs, so you do not need to configure dayjs yourself. |
|
|
182
|
+
| `messages` | `Partial<GanttMessages>` | `{}` | Overrides any subset of the generated strings (toolbar, context menu, task form + validation, baseline tooltip, add-task row, and bar aria-labels). Unset keys keep their English defaults, exported as `DEFAULT_GANTT_MESSAGES`. |
|
|
183
|
+
|
|
184
|
+
`GanttMessages` keys include: `addTask`, `deleteSelected`, `undo`, `redo`, `exportAsSvg`, `exportAsPng`, `exportAsPdf`, `quickFilterPlaceholder`, `filterButton`, `filterHeading`, `filterMatchLabel`, `filterMatchAll`, `filterMatchAny`, `filterAddCondition`, `filterApply`, `filterClear`, `filterRemoveCondition`, `filterNoConditions`, `filterOperatorLabel(operator)`, `groupNone`, `groupCountLabel(count)`, `exportFailedNoChart`, `exportFailedGeneric`, `editTask`, `addChildTask`, `addSiblingTask`, `indent`, `outdent`, `deleteTask`, `deleteTaskWithChildren`, `formTaskName`, `formStartDate`, `formEndDate`, `formProgress`, `formSubmit`, `editTaskTitle(name)`, `validationStartRequired`, `validationEndRequired`, `validationEndAfterStart`, `validationNameRequired`, `validationProgressRequired`, `validationProgressRange`, `addTaskRowLabel`, `baselineLabel`, `startLabel`, `endLabel`, `summaryAriaLabel(ctx)`, `barAriaLabel(ctx)`, `barAriaValueText(ctx)`, and `progressAriaLabel(name)`. Column headers (set via the columns API) and the default tooltip template (`tooltipTemplate`) are localized through their own options.
|
|
185
|
+
|
|
146
186
|
Default tooltip template
|
|
147
187
|
|
|
148
188
|
```js
|
|
@@ -259,7 +299,29 @@ Each tasks should be in below format
|
|
|
259
299
|
|
|
260
300
|
Customize which columns appear in the task-list panel, their order, titles, and widths. When `columnConfig` is provided, **it is authoritative** — only the columns you list are rendered, in the order you specify. Omitted columns are hidden. Each entry is merged with defaults, so you only need to specify overrides.
|
|
261
301
|
|
|
262
|
-
|
|
302
|
+
By default ([`autoSizeColumns`](#options)), each column is sized to fit its header title and the widest cell content, and the task-list panel grows so nothing is clipped. `minWidth` sets a column's preferred (default) width and `maxWidth` (default `320px`) the ceiling. The panel remains freely resizable: dragging the divider distributes width proportionally to content when widening, and shrinks columns toward a small floor when narrowing (so a large `minWidth` never blocks the resize). Set `autoSizeColumns: false` to split the fixed `tasksContainerWidth` purely by `flexGrow` (the legacy behavior), in which case columns clip to their `minWidth` when the panel is too narrow.
|
|
303
|
+
|
|
304
|
+
**Resizing a single column.** With `resizableColumns` on (the default), each column header has a drag handle at its trailing edge. Drag it to pin that column to an exact pixel width; the remaining columns absorb the leftover panel space, so you can keep some columns wide and others thin. Double-click a handle to reset that column to its auto width. Lock one column with `resizable: false` in its `columnConfig` entry. The same overrides are available programmatically via `gantt.setColumnWidth(key, px)`, `gantt.resetColumnWidths(key?)`, and `gantt.getColumnWidths()`, are included in `getState()` / `setState()`, and emit a `columnResize` event.
|
|
305
|
+
|
|
306
|
+
Available built-in column keys:
|
|
307
|
+
|
|
308
|
+
| Key | Title | Shows |
|
|
309
|
+
| --- | --- | --- |
|
|
310
|
+
| `Name` | Task Name | Task name with the collapse chevron + indentation |
|
|
311
|
+
| `StartTime` | Start | Start date (rolled-up start for summary rows) |
|
|
312
|
+
| `EndTime` | End | End date (rolled-up end for summary rows) |
|
|
313
|
+
| `Duration` | Duration | Duration in the active snap unit (working days when a calendar is set) |
|
|
314
|
+
| `Progress` | Progress | Progress percent as text |
|
|
315
|
+
| `ProgressRing` | Progress | Progress as an SVG ring |
|
|
316
|
+
| `Wbs` | WBS | Work Breakdown Structure code (`1`, `1.2`, …) |
|
|
317
|
+
| `Assignees` | Assignees | Comma-joined assignee names (from `task.assignees`) |
|
|
318
|
+
| `Predecessors` | Predecessors | Predecessor tasks by WBS, with a non-`FS` type + non-zero lag suffix (e.g. `1.2, 3SS+2d`) |
|
|
319
|
+
| `Successors` | Successors | Successor tasks by WBS (same notation) |
|
|
320
|
+
| `BaselineStart` | Baseline Start | Baseline start date (from `task.baseline.start`) |
|
|
321
|
+
| `BaselineEnd` | Baseline End | Baseline end date (from `task.baseline.end`) |
|
|
322
|
+
| `BaselineVariance` | Variance | Finish variance vs baseline in days (`+` = late, `-` = early) |
|
|
323
|
+
|
|
324
|
+
`Predecessors` / `Successors` are derived from the dependency graph and refresh automatically as dependencies or WBS change. Every built-in column except `Wbs` is sortable and filterable; `Assignees`, `Predecessors`, and `Successors` filter as text, the baseline dates as dates, and `BaselineVariance` as a number. All are groupable via [`gantt.groupBy()`](#grouping).
|
|
263
325
|
|
|
264
326
|
### Customize column widths
|
|
265
327
|
|
|
@@ -385,11 +447,188 @@ The code is also available on each `Task` as `task.wbs` if you need to read it f
|
|
|
385
447
|
| --- | --- | --- | --- |
|
|
386
448
|
| `key` | `ColumnKey \| string` | — | Built-in column identifier or any custom string id when `render` is supplied (required). |
|
|
387
449
|
| `title` | `string` | from defaults | Header text displayed for the column. |
|
|
388
|
-
| `minWidth` | `string` | `'30px'` | Minimum CSS width (used in `minmax()`). |
|
|
450
|
+
| `minWidth` | `string` | `'30px'` | Minimum CSS width (used in `minmax()`). With `autoSizeColumns` on this is the column's preferred (default) width. |
|
|
451
|
+
| `maxWidth` | `string` | `'320px'` | Ceiling for the auto-sized width, so one long value can't dominate the panel. Ignored when `autoSizeColumns` is off. |
|
|
389
452
|
| `flexGrow` | `number` | `1` | Flex proportion (used as `fr` units in CSS Grid). |
|
|
390
453
|
| `visible` | `boolean` | `true` | Set to `false` to hide the column. |
|
|
454
|
+
| `resizable` | `boolean` | `true` | Set to `false` to lock this column at its auto/configured width (no drag handle) when `resizableColumns` is on. |
|
|
391
455
|
| `render` | `ColumnRenderer` | — | Custom cell renderer. Required for custom columns; ignored for built-in keys. |
|
|
392
|
-
| `accessor` | `(task) => unknown` | — | Extracts the cell's underlying value
|
|
456
|
+
| `accessor` | `(task) => unknown` | — | Extracts the cell's underlying value. Used by SVG export and by sorting/filtering — it is what makes a **custom** column sortable. |
|
|
457
|
+
| `sortable` | `boolean` | _auto_ | Whether the column participates in sorting (header click + `sortBy` / `gantt.sort()`). Defaults to `true` for built-in value columns, `false` for `Wbs`, and `true` for custom columns only when an `accessor` or `comparator` is supplied. |
|
|
458
|
+
| `comparator` | `(a: Task, b: Task) => number` | — | Custom sort comparator for this column. Takes precedence over `accessor`. Return negative / zero / positive for ascending order; the active direction is applied on top, and ties fall back to natural (input) order. |
|
|
459
|
+
|
|
460
|
+
## Sorting & Filtering
|
|
461
|
+
|
|
462
|
+
### Sorting
|
|
463
|
+
|
|
464
|
+
Sorting a Gantt is **hierarchy-preserving**: siblings are reordered within each parent, never flattened, so summary bars, WBS codes, and rollups stay coherent. Summary (parent) rows sort by their rolled-up span (for date/duration columns) or aggregate value.
|
|
465
|
+
|
|
466
|
+
Set an initial sort with the `sortBy` option, or drive it imperatively. By default the chart sorts by start time ascending; pass `sortBy: []` for natural (input) order.
|
|
467
|
+
|
|
468
|
+
```js
|
|
469
|
+
import {ColumnKey} from 'apexgantt';
|
|
470
|
+
|
|
471
|
+
const gantt = new ApexGantt(element, {
|
|
472
|
+
series: tasks,
|
|
473
|
+
sortBy: {key: ColumnKey.Name, direction: 'asc'},
|
|
474
|
+
// multi-key: sort by progress desc, then name asc
|
|
475
|
+
// sortBy: [{ key: ColumnKey.Progress, direction: 'desc' }, { key: ColumnKey.Name }],
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
gantt.sort({key: ColumnKey.Progress, direction: 'desc'}); // replace the sort
|
|
479
|
+
gantt.getSort(); // [{ key: 'progress', direction: 'desc' }]
|
|
480
|
+
gantt.clearSort(); // back to natural (input) order
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**Clicking a sortable column header** cycles its sort ascending → descending → none (natural order), showing a ▲ / ▼ caret. **Shift+click** a header to add it as an additional sort key (multi-column sort) — each Shift+clicked column cycles ascending → descending → removed, the others are kept, and a small precedence number (1, 2, 3…) appears next to each caret. A plain click always collapses back to a single-key sort. Built-in value columns are sortable out of the box; `Wbs` is not (it is purely positional). A custom column becomes sortable when you give it an `accessor` (or a `comparator`). Override per column with `sortable`.
|
|
484
|
+
|
|
485
|
+
> Sorting is applied on demand. Editing a task's dates (drag / resize / inline edit) does not automatically re-sort the row — call `gantt.sort(gantt.getSort())` to re-apply the current sort if you want the row to move. Manual sibling re-ordering is not offered in this release, so there is no drag-vs-sort conflict.
|
|
486
|
+
|
|
487
|
+
### Filtering
|
|
488
|
+
|
|
489
|
+
A filter is a predicate run against each task. A task is **kept when it matches or has a matching descendant**, so the ancestors of matches stay visible and the tree context is preserved. Filtering is view-only: it changes which rows render but never the tree, WBS, or task data.
|
|
490
|
+
|
|
491
|
+
```js
|
|
492
|
+
const gantt = new ApexGantt(element, {
|
|
493
|
+
series: tasks,
|
|
494
|
+
filterBy: (task) => task.progress < 100, // initial filter: show incomplete work
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
gantt.filter((task) => /design/i.test(task.name)); // apply a filter
|
|
498
|
+
gantt.isFiltered(); // true
|
|
499
|
+
gantt.clearFilter(); // show every row again
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
**Built-in quick filter.** Set `enableQuickFilter: true` to render a search box in the toolbar; typing filters by the configured `quickFilter.fields` (default `['name']`).
|
|
503
|
+
|
|
504
|
+
```js
|
|
505
|
+
const gantt = new ApexGantt(element, {
|
|
506
|
+
series: tasks,
|
|
507
|
+
enableQuickFilter: true,
|
|
508
|
+
quickFilter: {placeholder: 'Find a task…', fields: ['name'], caseSensitive: false},
|
|
509
|
+
});
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**Advanced filter builder.** Set `enableFilterBuilder: true` for a "Filter" toolbar button that opens a popover for composing multiple conditions (field + operator + value) combined with **All** (AND) or **Any** (OR). The valid operators adapt to the column's type:
|
|
513
|
+
|
|
514
|
+
- **Text** (Name, custom): `contains`, `notContains`, `equals`, `notEquals`, `startsWith`, `endsWith`, `isEmpty`, `notEmpty`
|
|
515
|
+
- **Number** (Progress, Duration): `equals`, `notEquals`, `gt`, `gte`, `lt`, `lte`, `isEmpty`, `notEmpty`
|
|
516
|
+
- **Date** (Start, End): `on`, `before`, `after`, `isEmpty`, `notEmpty`
|
|
517
|
+
|
|
518
|
+
The same structured filter is available programmatically, with or without the UI:
|
|
519
|
+
|
|
520
|
+
```js
|
|
521
|
+
import {ColumnKey} from 'apexgantt';
|
|
522
|
+
|
|
523
|
+
gantt.setFilterRules({
|
|
524
|
+
match: 'all', // 'all' = AND, 'any' = OR
|
|
525
|
+
rules: [
|
|
526
|
+
{field: ColumnKey.Progress, operator: 'lt', value: 100},
|
|
527
|
+
{field: ColumnKey.StartTime, operator: 'after', value: '2024-02-01'},
|
|
528
|
+
],
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
gantt.getFilterRules(); // the active FilterRuleSet, or null
|
|
532
|
+
gantt.clearFilter(); // drop it
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
A custom column is filterable when it exposes an `accessor` (treated as text). For fully bespoke logic, wire `gantt.filter(predicate)` to your own controls (see the `sort-filter` demo).
|
|
536
|
+
|
|
537
|
+
> Filtering respects collapse state: a matching descendant under a collapsed parent stays hidden until the parent is expanded.
|
|
538
|
+
|
|
539
|
+
## UI state persistence
|
|
540
|
+
|
|
541
|
+
The Gantt can remember "where the user left off": zoom, scroll position, expand/collapse state, selection, sort, and filter. This view state is separate from the task data.
|
|
542
|
+
|
|
543
|
+
**Manual (`getState` / `setState`).** Capture a JSON-serializable snapshot and restore it whenever you like (for example, persist it to your own backend keyed by user).
|
|
544
|
+
|
|
545
|
+
```js
|
|
546
|
+
const saved = gantt.getState();
|
|
547
|
+
// { version: 1, zoom, scroll, collapsed, selected, sort, filterRules, quickFilter }
|
|
548
|
+
|
|
549
|
+
// later, or in a new session:
|
|
550
|
+
gantt.setState(saved);
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
`setState()` accepts a partial state, so you can restore just one slice:
|
|
554
|
+
|
|
555
|
+
```js
|
|
556
|
+
gantt.setState({sort: [{key: ColumnKey.Name, direction: 'asc'}]});
|
|
557
|
+
gantt.setState({collapsed: ['phase-1', 'phase-2']}, {silent: true}); // no sortChange/filterChange
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**Automatic (`persistState`).** Set the `persistState` option to have the Gantt read from and write to `localStorage` for you. State is restored on the first `render()` and saved (debounced) whenever the view changes.
|
|
561
|
+
|
|
562
|
+
```js
|
|
563
|
+
const gantt = new ApexGantt(element, {series: tasks, persistState: true});
|
|
564
|
+
// or a custom storage key:
|
|
565
|
+
const gantt = new ApexGantt(element, {series: tasks, persistState: {key: 'project-42-gantt'}});
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
State stored under an incompatible schema `version` (or malformed JSON) is ignored, so upgrading the library never breaks a load. Persistence is a no-op in environments without `localStorage` (for example, server-side rendering).
|
|
569
|
+
|
|
570
|
+
## Grouping
|
|
571
|
+
|
|
572
|
+
Group the task grid by a field to bucket tasks under collapsible group headers. While grouping is active the parent/child tree is **suspended**: every task appears flat under its group header (with a member count), and the timeline shows each task's bar aligned to its grouped row.
|
|
573
|
+
|
|
574
|
+
Set it up front with the `groupBy` option or at runtime with `gantt.groupBy()`:
|
|
575
|
+
|
|
576
|
+
```js
|
|
577
|
+
// Bare column key — group by that column's value.
|
|
578
|
+
gantt.groupBy(ColumnKey.Progress);
|
|
579
|
+
|
|
580
|
+
// GroupCriterion — custom value extraction, labelling, and header order.
|
|
581
|
+
gantt.groupBy({
|
|
582
|
+
field: 'status',
|
|
583
|
+
accessor: (task) => task.status, // defaults to the column's accessor
|
|
584
|
+
label: (value) => `Status: ${value}`, // defaults to String(value)
|
|
585
|
+
direction: 'desc', // header order; defaults to 'asc'
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
gantt.getGroupBy(); // the active GroupCriterion, or null
|
|
589
|
+
gantt.isGrouping(); // boolean
|
|
590
|
+
gantt.clearGrouping(); // restore the tree view
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
Grouping composes with sorting and filtering: members are ordered within each group by the active sort, and a filter drops non-matching members (empty groups disappear). Tasks whose group value is empty collect under a localized "(None)" group, which always sorts last. Each group header is collapsible; clicking its chevron hides that group's members. Group headers themselves have no task bar.
|
|
594
|
+
|
|
595
|
+
> Grouping is view-only — it never mutates the task tree, WBS, or task data; clearing it returns the exact prior hierarchy. A `GroupCriterion`'s `accessor`/`label` functions are not serialized by [`persistState`](#ui-state-persistence) / `getState()` (only the `field` and `direction` are), so a restored grouping falls back to the column's own accessor.
|
|
596
|
+
|
|
597
|
+
## Split tasks
|
|
598
|
+
|
|
599
|
+
A task can be split into several **worked segments** separated by gaps on a single row (for example: work Mon–Wed, pause, resume Fri). Provide a `segments` array on the task, or split at runtime with `gantt.splitTask()`.
|
|
600
|
+
|
|
601
|
+
```js
|
|
602
|
+
const gantt = new ApexGantt(element, {
|
|
603
|
+
series: [
|
|
604
|
+
{
|
|
605
|
+
id: 't1',
|
|
606
|
+
name: 'Implementation',
|
|
607
|
+
startTime: '2026-06-01',
|
|
608
|
+
endTime: '2026-06-20',
|
|
609
|
+
progress: 50,
|
|
610
|
+
segments: [
|
|
611
|
+
{start: '2026-06-01', end: '2026-06-06'},
|
|
612
|
+
{start: '2026-06-12', end: '2026-06-20'},
|
|
613
|
+
],
|
|
614
|
+
},
|
|
615
|
+
],
|
|
616
|
+
});
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
The task's `startTime` / `endTime` are the **envelope** (first segment start → last segment end) and are derived automatically from the segments, so summary rollups, dependencies, the timeline header, and the duration column all keep working. The bar renders one filled piece per segment joined by a thin connector line across the gaps; progress fills the worked segments left-to-right (gaps carry no progress).
|
|
620
|
+
|
|
621
|
+
Split at runtime, then clear the split by setting `segments` back to an empty array:
|
|
622
|
+
|
|
623
|
+
```js
|
|
624
|
+
gantt.splitTask('t1', '2026-06-08', {resumeAt: '2026-06-12'}); // open a gap
|
|
625
|
+
gantt.isSplit('t1'); // true
|
|
626
|
+
gantt.updateTask('t1', {segments: []}); // back to one contiguous bar
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
Interactions are preserved: dragging a split task moves all its segments together, and resizing adjusts its outer segment — both inferred automatically, so the same drag/resize handles work as for a normal bar.
|
|
630
|
+
|
|
631
|
+
> v1 is API-driven. Interactive split gestures (double-click / context-menu "split here"), per-segment drag/resize, and critical-path math that excludes gap time are not yet implemented; the envelope is treated as the task's span.
|
|
393
632
|
|
|
394
633
|
## Custom column renderers
|
|
395
634
|
|
|
@@ -518,6 +757,18 @@ The library invokes the cleanup function in **all three** of these cases:
|
|
|
518
757
|
|
|
519
758
|
You do not need to listen for DOM mutations yourself. If your renderer returns a function, the library will call it.
|
|
520
759
|
|
|
760
|
+
## Touch & pointer support
|
|
761
|
+
|
|
762
|
+
All interactive gestures are built on **Pointer Events**, so they work with mouse, touch, and pen alike — no separate touch mode to enable. This covers dragging a task bar to reschedule it, resizing via the edge handles, dragging the in-bar progress handle, drawing dependencies from a bar's anchors, and dragging the task-list / timeline split bar.
|
|
763
|
+
|
|
764
|
+
Implementation notes:
|
|
765
|
+
|
|
766
|
+
- Interactive elements set `touch-action: none` so a touch-drag isn't stolen by the browser's pan/zoom (which would otherwise cancel the gesture).
|
|
767
|
+
- Each gesture is owned by the pointer that started it, so a second finger can't hijack an in-progress drag.
|
|
768
|
+
- If the OS interrupts a gesture (`pointercancel`), an in-flight bar drag reverts to its starting position rather than committing a partial move.
|
|
769
|
+
|
|
770
|
+
> Hover-only affordances (the crosshair, bar tooltips) naturally don't appear on touch since there is no hover, but every editing gesture and tap/selection works.
|
|
771
|
+
|
|
521
772
|
## Sub-day scheduling
|
|
522
773
|
|
|
523
774
|
Set `inputDateFormat` to a format that includes time tokens (e.g. `'YYYY-MM-DD HH:mm'`) and choose a finer `snapUnit` to schedule tasks at the hour or minute level:
|
|
@@ -925,6 +1176,130 @@ Zooms out the gantt based on current view mode. View mode direction for zoom in
|
|
|
925
1176
|
ganttInstance.zoomOut();
|
|
926
1177
|
```
|
|
927
1178
|
|
|
1179
|
+
### 15. `sort(criteria)`
|
|
1180
|
+
|
|
1181
|
+
Apply a hierarchy-preserving sort. Pass one `SortCriterion` or an array (multi-key). Re-renders and emits `sortChange`. See [Sorting & Filtering](#sorting--filtering).
|
|
1182
|
+
|
|
1183
|
+
```js
|
|
1184
|
+
gantt.sort({key: ColumnKey.Name, direction: 'asc'});
|
|
1185
|
+
```
|
|
1186
|
+
|
|
1187
|
+
### 16. `clearSort()`
|
|
1188
|
+
|
|
1189
|
+
Clear the active sort and return to natural (input) order. Emits `sortChange`.
|
|
1190
|
+
|
|
1191
|
+
### 17. `getSort()`
|
|
1192
|
+
|
|
1193
|
+
Return the active sort criteria as `SortCriterion[]` (empty array = natural order).
|
|
1194
|
+
|
|
1195
|
+
### 18. `toggleSort(key, opts?)`
|
|
1196
|
+
|
|
1197
|
+
Cycle a column's sort ascending → descending → none. Backs the column-header click UX; no-op for non-sortable columns. Pass `{ append: true }` (Shift+click) to add the column as an extra sort key for multi-column sort instead of replacing the current one. Emits `sortChange`.
|
|
1198
|
+
|
|
1199
|
+
### 19. `filter(predicate)`
|
|
1200
|
+
|
|
1201
|
+
Apply a filter. `predicate: (task) => boolean`; a task is kept when it matches or has a matching descendant. Re-renders and emits `filterChange`.
|
|
1202
|
+
|
|
1203
|
+
```js
|
|
1204
|
+
gantt.filter((task) => task.progress < 100);
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1207
|
+
### 20. `clearFilter()`
|
|
1208
|
+
|
|
1209
|
+
Clear the active filter so every row is shown again. Emits `filterChange`.
|
|
1210
|
+
|
|
1211
|
+
### 21. `isFiltered()`
|
|
1212
|
+
|
|
1213
|
+
Returns `true` when a filter is currently active.
|
|
1214
|
+
|
|
1215
|
+
### 22. `setFilterRules(ruleSet)`
|
|
1216
|
+
|
|
1217
|
+
Apply a structured filter (`FilterRuleSet`) — conditions combined with `'all'` (AND) or `'any'` (OR). Pass `null` or an empty rule list to clear. Compiles to the same view-only filter as `filter()`. Emits `filterChange`.
|
|
1218
|
+
|
|
1219
|
+
### 23. `getFilterRules()`
|
|
1220
|
+
|
|
1221
|
+
Return the active `FilterRuleSet`, or `null` when none is set.
|
|
1222
|
+
|
|
1223
|
+
### 24. `exportChart(format?)`
|
|
1224
|
+
|
|
1225
|
+
Export the chart and trigger a download. `format` is `'svg'` (vector), `'png'` (raster), or `'pdf'` (single-page, image-based); defaults to the configured `exportFormat`. Under row virtualization the full dataset is expanded for the snapshot and restored afterward. Returns a `Promise` that resolves once the download has been triggered.
|
|
1226
|
+
|
|
1227
|
+
```js
|
|
1228
|
+
await gantt.exportChart('png');
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
> PNG and PDF rasterize the chart via a `<canvas>`, so they run in the browser (not in headless/jsdom environments). The PDF is generated dependency-free (a single page embedding a JPEG of the chart).
|
|
1232
|
+
|
|
1233
|
+
### 25. `getState()`
|
|
1234
|
+
|
|
1235
|
+
Capture the current UI view state (zoom, scroll, collapse, selection, sort, filter) as a JSON-serializable `GanttUiState`. Pair with `setState()` to save and restore "where the user left off", for example to your own backend.
|
|
1236
|
+
|
|
1237
|
+
```js
|
|
1238
|
+
const saved = gantt.getState();
|
|
1239
|
+
// { version: 1, zoom, scroll, collapsed, selected, sort, filterRules, quickFilter }
|
|
1240
|
+
```
|
|
1241
|
+
|
|
1242
|
+
### 26. `setState(state, opts?)`
|
|
1243
|
+
|
|
1244
|
+
Restore a state produced by `getState()`. Any omitted field is left untouched, so a partial state (for example `{ sort: [...] }`) applies just that slice. Re-renders once, then emits `sortChange` / `filterChange` for the parts that changed. Pass `{ silent: true }` to suppress those events.
|
|
1245
|
+
|
|
1246
|
+
```js
|
|
1247
|
+
gantt.setState(saved);
|
|
1248
|
+
gantt.setState({sort: [{key: ColumnKey.Name, direction: 'asc'}]}); // partial
|
|
1249
|
+
```
|
|
1250
|
+
|
|
1251
|
+
> To have the Gantt save and restore state automatically via `localStorage`, set the [`persistState`](#uistate) option instead of calling these by hand. See [UI state persistence](#ui-state-persistence).
|
|
1252
|
+
|
|
1253
|
+
### 27. `groupBy(criterion)`
|
|
1254
|
+
|
|
1255
|
+
Group the task grid by a field. While grouping is active the parent/child tree is suspended and every task appears flat under a collapsible group header (label + member count). Pass a bare column key or a `GroupCriterion` (`{ field, accessor?, label?, direction? }`). Re-renders and emits `groupChange`. See [Grouping](#grouping).
|
|
1256
|
+
|
|
1257
|
+
```js
|
|
1258
|
+
gantt.groupBy(ColumnKey.Progress);
|
|
1259
|
+
gantt.groupBy({field: 'status', label: (v) => `Status: ${v}`, direction: 'desc'});
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
### 28. `clearGrouping()`
|
|
1263
|
+
|
|
1264
|
+
Clear the active grouping and restore the tree view. Emits `groupChange`.
|
|
1265
|
+
|
|
1266
|
+
### 29. `getGroupBy()` / `isGrouping()`
|
|
1267
|
+
|
|
1268
|
+
`getGroupBy()` returns the active `GroupCriterion` (or `null`); `isGrouping()` returns whether grouping is active.
|
|
1269
|
+
|
|
1270
|
+
### 30. `splitTask(taskId, at, options?)`
|
|
1271
|
+
|
|
1272
|
+
Split a task into separate worked segments at `at`, producing a gap on the timeline (see [Split tasks](#split-tasks)). The segment containing `at` is cut so its first piece ends at `at` and the rest resumes at `options.resumeAt` (default: the next day — pass a later `resumeAt` for a wider gap). Routed through `updateTask`, so it is validated, undoable, and emits `taskUpdate`. No-op on milestones, summary bars, or when `at` is not strictly inside a worked span.
|
|
1273
|
+
|
|
1274
|
+
```js
|
|
1275
|
+
gantt.splitTask('t3', '2026-06-10', {resumeAt: '2026-06-14'});
|
|
1276
|
+
```
|
|
1277
|
+
|
|
1278
|
+
### 31. `isSplit(taskId)`
|
|
1279
|
+
|
|
1280
|
+
Returns whether a task is currently split into multiple worked segments.
|
|
1281
|
+
|
|
1282
|
+
### 32. `setColumnWidth(key, width)`
|
|
1283
|
+
|
|
1284
|
+
Pin a task-list column to an exact pixel width (the other columns absorb the remaining panel space). Mirrors dragging the column-header resize handle. Re-renders and emits `columnResize`.
|
|
1285
|
+
|
|
1286
|
+
```js
|
|
1287
|
+
gantt.setColumnWidth(ColumnKey.Name, 260);
|
|
1288
|
+
```
|
|
1289
|
+
|
|
1290
|
+
### 33. `resetColumnWidths(key?)`
|
|
1291
|
+
|
|
1292
|
+
Clear the manual width of one column (pass its `key`) or of every column (omit the argument), returning them to their auto/flex width. Re-renders and emits `columnResize`.
|
|
1293
|
+
|
|
1294
|
+
```js
|
|
1295
|
+
gantt.resetColumnWidths(ColumnKey.Name); // one column
|
|
1296
|
+
gantt.resetColumnWidths(); // all columns
|
|
1297
|
+
```
|
|
1298
|
+
|
|
1299
|
+
### 34. `getColumnWidths()`
|
|
1300
|
+
|
|
1301
|
+
Return the active manual column-width overrides as a plain object (`key` → pixels). Included in `getState()` and restorable via `setState({ columnWidths })`.
|
|
1302
|
+
|
|
928
1303
|
## Events
|
|
929
1304
|
|
|
930
1305
|
ApexGantt emits CustomEvents on the container element for various user interactions, allowing you to track and respond to changes in real-time.
|
|
@@ -946,6 +1321,10 @@ ApexGantt emits CustomEvents on the container element for various user interacti
|
|
|
946
1321
|
| `taskResized` | Task bar is resized | `{ taskId, resizeHandle, oldStartTime, oldEndTime, newStartTime, newEndTime, durationChange, timestamp }` |
|
|
947
1322
|
| `taskProgressChanged` | In-bar progress handle is dragged to a new value | `{ taskId, oldProgress, newProgress, timestamp }` |
|
|
948
1323
|
| `historyChange` | The undo/redo stack changed — `kind` is `'record'`, `'undo'`, `'redo'`, or `'clear'` | `{ kind, canUndo, canRedo, undoSize, redoSize, topUndoLabel?, topRedoLabel?, timestamp }` |
|
|
1324
|
+
| `sortChange` | Active sort changed via API or header click | `{ criteria: { key, direction }[], timestamp }` |
|
|
1325
|
+
| `filterChange` | Active filter changed | `{ active, visibleCount, timestamp }` |
|
|
1326
|
+
| `groupChange` | Active grouping changed via `gantt.groupBy()` / `gantt.clearGrouping()` | `{ active, field, groupCount, timestamp }` |
|
|
1327
|
+
| `columnResize` | A task-list column was resized (header drag or API) | `{ key, width, widths, timestamp }` |
|
|
949
1328
|
|
|
950
1329
|
### Events Usage
|
|
951
1330
|
|