Skip to content

Commit 80197bf

Browse files
committed
feat: custom column configuration for tasks
1 parent 6bdc14b commit 80197bf

File tree

12 files changed

+79
-8
lines changed

12 files changed

+79
-8
lines changed

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ The layout can be configured by either setting the properties in the table below
6767
| barTextColor | `#FFFFFF` | Text color for timeline bar |
6868
| cellBorderColor | `#eff0f0` | Border color for all table cells and timeline cells |
6969
| cellBorderWidth | `1px` | Border width for all table cells and timeline cells |
70+
| columnConfig | `undefined` | Custom column widths |
7071
| enableToolbar | `false` | Enable/disable graph toolbar |
7172
| enableResize | `true` | Enable/disable gantt sidebar resize |
7273
| enableExport | `true` | Enable/disable gantt export options |
@@ -185,6 +186,44 @@ Each tasks should be in below format
185186
];
186187
```
187188

189+
## Column Configuration
190+
191+
Customize task table column widths:
192+
193+
```js
194+
import {ColumnKey} from 'apexgantt';
195+
196+
const gantt = new ApexGantt(element, {
197+
series: tasks,
198+
columnConfig: [
199+
{
200+
key: ColumnKey.Name,
201+
title: 'Task Name',
202+
minWidth: '100px',
203+
flexGrow: 3,
204+
},
205+
{
206+
key: ColumnKey.StartTime,
207+
title: 'Start',
208+
minWidth: '100px',
209+
flexGrow: 1.5,
210+
},
211+
{
212+
key: ColumnKey.Duration,
213+
title: 'Duration',
214+
minWidth: '80px',
215+
flexGrow: 1,
216+
},
217+
{
218+
key: ColumnKey.Progress,
219+
title: 'Progress',
220+
minWidth: '80px',
221+
flexGrow: 1,
222+
},
223+
],
224+
});
225+
```
226+
188227
## Data Parsing
189228

190229
Map your existing data structure to ApexGantt format without manual transformation.

demo/basic-gantt-large-range.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<script src="../apexgantt.min.js"></script>
99
</head>
1010
<body>
11-
<div id="svg-gantt" style="margin: 0 auto; width: 90%; height: 600px"></div>
11+
<div id="svg-gantt" style="margin: 0 auto"></div>
1212
<script>
1313
const ganttOptions = {
1414
series: [

demo/basic-gantt.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<script src="../apexgantt.min.js"></script>
99
</head>
1010
<body>
11-
<div id="svg-gantt" style="margin: 0 auto; width: 90%; height: 600px"></div>
11+
<div id="svg-gantt" style="margin: 0 auto"></div>
1212
<script>
1313
const ganttOptions = {
1414
enableTaskDrag: false,

demo/data-parsing.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<script src="../apexgantt.min.js"></script>
99
</head>
1010
<body>
11-
<div id="svg-gantt" style="margin: 0 auto; width: 90%; height: 600px"></div>
11+
<div id="svg-gantt" style="margin: 0 auto"></div>
1212
<script>
1313
const nestedData = [
1414
{

demo/gantt-with-annotations.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<script src="../apexgantt.min.js"></script>
99
</head>
1010
<body>
11-
<div id="svg-gantt" style="margin: 0 auto; width: 90%; height: 600px"></div>
11+
<div id="svg-gantt" style="margin: 0 auto"></div>
1212
<script>
1313
const ganttOptions = {
1414
series: [

demo/gantt-with-interactions.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
<script src="../apexgantt.min.js"></script>
99
</head>
1010
<body>
11-
<div id="svg-gantt" style="margin: 0 auto; width: 90%; height: 600px"></div>
11+
<div id="svg-gantt" style="margin: 0 auto"></div>
1212
<script>
1313
const ganttOptions = {
14+
width: '90%',
1415
enableTooltip: false,
1516
enableTaskDrag: true,
1617
enableTaskEdit: true,

lib/gantt.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ export declare class ApexGantt extends BaseChart {
1414
private scrollbarResizeObserver;
1515
private splitBarResizeHandler;
1616
private stateManager;
17+
private containerResizeObserver;
18+
private lastKnownWidth;
19+
private resizeDebounceTimer;
1720
constructor(element: HTMLElement, options?: GanttUserOptions);
1821
static setLicense(key: string): void;
1922
private setupShadowDOMEnvironment;
@@ -30,6 +33,7 @@ export declare class ApexGantt extends BaseChart {
3033
private isColorDark;
3134
private initializeTooltip;
3235
render(data?: any): any;
36+
private performAfterActions;
3337
/**
3438
* Setup proper positioning for chart container to support dialogs
3539
*/
@@ -77,6 +81,12 @@ export declare class ApexGantt extends BaseChart {
7781
* Normalize dimension value to CSS string
7882
*/
7983
private normalizeDimension;
84+
/**
85+
* resize observer for container to handle responsive width changes
86+
*/
87+
private setupContainerResizeObserver;
88+
private handleContainerResize;
89+
private performResize;
8090
destroy(): void;
8191
isDestroyed(): boolean;
8292
}

lib/models/Options.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ParsingConfig } from '../models/DataParser';
22
import { ThemeMode } from './Theme';
33
import { Task, TaskInput } from './Tasks';
44
import { Annotation, Orientation } from './Annotation';
5+
import { ColumnListItem } from '../util/task.util';
56
import { ViewMode } from '../util/gantt.util';
67

78
export interface AnnotationOptions {
@@ -28,6 +29,9 @@ export interface CommonOptions {
2829
readonly viewMode: ViewMode;
2930
readonly width: number | string;
3031
}
32+
export interface ColumnOptions {
33+
readonly columnConfig?: ColumnListItem[];
34+
}
3135
export interface FontOptions {
3236
readonly fontColor: string;
3337
readonly fontFamily: string;
@@ -61,7 +65,7 @@ export interface TooltipOptions {
6165
readonly tooltipId: string;
6266
readonly tooltipTemplate?: (task: Task, dateFormat: string) => string;
6367
}
64-
export type GanttOptionsInternal = AnnotationOptions & BorderOptions & CommonOptions & FontOptions & GanttBarOptions & GanttData & GanttRowOptions & InteractiveOptions & TooltipOptions;
68+
export type GanttOptionsInternal = AnnotationOptions & BorderOptions & CommonOptions & ColumnOptions & FontOptions & GanttBarOptions & GanttData & GanttRowOptions & InteractiveOptions & TooltipOptions;
6569
export interface GanttUserOptions {
6670
readonly theme?: ThemeMode;
6771
readonly annotationBgColor?: string;
@@ -80,6 +84,7 @@ export interface GanttUserOptions {
8084
readonly canvasStyle?: string;
8185
readonly cellBorderColor?: string;
8286
readonly cellBorderWidth?: string;
87+
readonly columnConfig?: ColumnListItem[];
8388
readonly enableExport?: boolean;
8489
readonly enableResize?: boolean;
8590
readonly enableTaskDrag?: boolean;

lib/models/Tasks.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,16 @@ export declare class Tasks {
3131
options: GanttOptions;
3232
chartContext: ChartContext;
3333
dataManager: DataManager;
34+
private effectiveColumnList;
3435
constructor(options: GanttOptions, chartContext: ChartContext, dataManager: DataManager);
36+
/**
37+
* Merges user column config with defaults
38+
*/
39+
private mergeColumnConfig;
40+
/**
41+
* Dynamic CSS for column widths based on configuration
42+
*/
43+
private injectDynamicColumnStyles;
3544
generateBody(tasks: Task[], reRender: () => void): HTMLElement;
3645
generateHeader(headerList: string[]): HTMLElement;
3746
generateRow(task: Task, reRender: () => void): HTMLElement;

lib/styles/Tasks.style.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export declare const TableStyle = "\n .tasks-container {\n height: 100%;\n position: relative;\n display: flex;\n flex-direction: column;\n overflow-x: visible;\n overflow-y: visible;\n }\n\n .tasks-header {\n flex-shrink: 0;\n position: sticky;\n top: 0;\n z-index: 10;\n background-color: var(--header-bg-color, #F3F3F3);\n overflow: hidden;\n }\n\n .tasks-header-row {\n display: flex;\n width: 100%;\n }\n\n .tasks-header-cell {\n padding: 0 10px;\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n display: flex;\n align-items: center;\n border: var(--cell-border-width, 1px) solid var(--cell-border-color, #eff0f0);\n color: var(--text-color, #000);\n box-sizing: border-box;\n flex-shrink: 0;\n font-weight: 600;\n }\n\n .tasks-body-wrapper {\n flex: 1;\n overflow: visible;\n position: relative;\n }\n\n .tasks-data-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n }\n\n .tasks-data-row {\n display: flex;\n width: 100%;\n border-bottom: var(--cell-border-width, 1px) solid var(--cell-border-color, #eff0f0);\n box-sizing: border-box;\n }\n\n .tasks-data-cell {\n padding: 0 10px;\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n display: flex;\n align-items: center;\n border-left: var(--cell-border-width, 1px) solid var(--cell-border-color, #eff0f0);\n border-right: var(--cell-border-width, 1px) solid var(--cell-border-color, #eff0f0);\n color: var(--text-color, #000);\n box-sizing: border-box;\n flex-shrink: 0;\n }\n\n .tasks-data-row .tasks-data-cell:first-child {\n border-left: none;\n }\n\n .tasks-data-row .tasks-data-cell:last-child {\n border-right: none;\n }\n\n .tasks-data-row .task-toggle-icon,\n .tasks-data-row .task-toggle-icon-blank {\n display: inline-block;\n margin-right: 5px;\n width: 10px;\n height: 10px;\n vertical-align: middle;\n flex-shrink: 0;\n }\n\n .tasks-data-row .task-toggle-icon {\n cursor: pointer;\n position: relative;\n }\n\n /* Chevron (expanded) - pointing down */\n .tasks-data-row .task-toggle-icon.expanded::before {\n content: '';\n position: absolute;\n width: 6px;\n height: 6px;\n border-right: 2px solid var(--text-color, #000000);\n border-bottom: 2px solid var(--text-color, #000000);\n transform: rotate(45deg);\n top: 0;\n left: 2px;\n }\n\n /* Chevron - pointing right (collapsed) */\n .tasks-data-row .task-toggle-icon.collapsed::before {\n content: '';\n position: absolute;\n width: 6px;\n height: 6px;\n border-right: 2px solid var(--text-color, #000000);\n border-bottom: 2px solid var(--text-color, #000000);\n transform: rotate(-45deg);\n top: 2px;\n left: 0;\n }\n\n .tasks-data-row .task-toggle-icon:hover::before {\n opacity: 0.7;\n }\n\n /* Shadow DOM specific */\n :host .tasks-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n :host .tasks-header {\n position: sticky;\n top: 0;\n z-index: 10;\n }\n";
1+
export declare const TableStyle = "\n .tasks-container {\n height: 100%;\n position: relative;\n display: flex;\n flex-direction: column;\n overflow-x: visible;\n overflow-y: visible;\n }\n\n .tasks-header {\n flex-shrink: 0;\n position: sticky;\n top: 0;\n z-index: 10;\n background-color: var(--header-bg-color, #F3F3F3);\n overflow: hidden;\n }\n\n .tasks-header-row {\n display: grid;\n width: 100%;\n }\n\n .tasks-header-cell {\n padding: 0 10px;\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n display: flex;\n align-items: center;\n border: var(--cell-border-width, 1px) solid var(--cell-border-color, #eff0f0);\n color: var(--text-color, #000);\n box-sizing: border-box;\n font-weight: 600;\n }\n\n .tasks-body-wrapper {\n flex: 1;\n overflow: visible;\n position: relative;\n }\n\n .tasks-data-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n }\n\n .tasks-data-row {\n display: grid;\n width: 100%;\n border-bottom: var(--cell-border-width, 1px) solid var(--cell-border-color, #eff0f0);\n box-sizing: border-box;\n }\n\n .tasks-data-cell {\n padding: 0 10px;\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n display: flex;\n align-items: center;\n border-left: var(--cell-border-width, 1px) solid var(--cell-border-color, #eff0f0);\n border-right: var(--cell-border-width, 1px) solid var(--cell-border-color, #eff0f0);\n color: var(--text-color, #000);\n box-sizing: border-box;\n }\n\n .tasks-data-row .tasks-data-cell:first-child {\n border-left: none;\n }\n\n .tasks-data-row .tasks-data-cell:last-child {\n border-right: none;\n }\n\n .tasks-data-row .task-toggle-icon,\n .tasks-data-row .task-toggle-icon-blank {\n display: inline-block;\n margin-right: 5px;\n width: 10px;\n height: 10px;\n vertical-align: middle;\n flex-shrink: 0;\n }\n\n .tasks-data-row .task-toggle-icon {\n cursor: pointer;\n position: relative;\n }\n\n /* Chevron (expanded) - pointing down */\n .tasks-data-row .task-toggle-icon.expanded::before {\n content: '';\n position: absolute;\n width: 6px;\n height: 6px;\n border-right: 2px solid var(--text-color, #000000);\n border-bottom: 2px solid var(--text-color, #000000);\n transform: rotate(45deg);\n top: 0;\n left: 2px;\n }\n\n /* Chevron - pointing right (collapsed) */\n .tasks-data-row .task-toggle-icon.collapsed::before {\n content: '';\n position: absolute;\n width: 6px;\n height: 6px;\n border-right: 2px solid var(--text-color, #000000);\n border-bottom: 2px solid var(--text-color, #000000);\n transform: rotate(-45deg);\n top: 2px;\n left: 0;\n }\n\n .tasks-data-row .task-toggle-icon:hover::before {\n opacity: 0.7;\n }\n\n /* Shadow DOM specific */\n :host .tasks-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n :host .tasks-header {\n position: sticky;\n top: 0;\n z-index: 10;\n }\n";

0 commit comments

Comments
 (0)