@operato/gantt 8.0.0-alpha.6 → 8.0.0-beta.1

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/dist/src/gantt-chart-controller.d.ts +5 -6
  3. package/dist/src/gantt-chart-controller.js +92 -37
  4. package/dist/src/gantt-chart-controller.js.map +1 -1
  5. package/dist/src/ox-gantt-chart.d.ts +378 -3
  6. package/dist/src/ox-gantt-chart.js +86 -180
  7. package/dist/src/ox-gantt-chart.js.map +1 -1
  8. package/dist/src/ox-gantt-resize-splitter.d.ts +6 -2
  9. package/dist/src/ox-gantt-resize-splitter.js +70 -39
  10. package/dist/src/ox-gantt-resize-splitter.js.map +1 -1
  11. package/dist/src/ox-gantt.js +11 -11
  12. package/dist/src/ox-gantt.js.map +1 -1
  13. package/dist/src/ox-resource-chart.js +2 -0
  14. package/dist/src/ox-resource-chart.js.map +1 -1
  15. package/dist/src/ox-task-tooltip.d.ts +3 -1
  16. package/dist/src/ox-task-tooltip.js +36 -11
  17. package/dist/src/ox-task-tooltip.js.map +1 -1
  18. package/dist/src/types.d.ts +1 -0
  19. package/dist/src/types.js.map +1 -1
  20. package/dist/stories/ox-gantt.stories.js +37 -1
  21. package/dist/stories/ox-gantt.stories.js.map +1 -1
  22. package/dist/tsconfig.tsbuildinfo +1 -1
  23. package/package.json +13 -13
  24. package/themes/calendar-theme.css +3 -1
  25. package/.editorconfig +0 -29
  26. package/.storybook/main.js +0 -3
  27. package/.storybook/preview.js +0 -52
  28. package/.storybook/server.mjs +0 -8
  29. package/assets/images/icon-editor-gradient-direction.png +0 -0
  30. package/assets/images/icon-properties-label.png +0 -0
  31. package/assets/images/icon-properties-line-type.png +0 -0
  32. package/assets/images/icon-properties-table.png +0 -0
  33. package/src/draw-time-scale-header.ts +0 -142
  34. package/src/gantt-chart-controller.ts +0 -336
  35. package/src/index.ts +0 -0
  36. package/src/locales.ts +0 -78
  37. package/src/ox-gantt-chart.ts +0 -518
  38. package/src/ox-gantt-resize-splitter.ts +0 -131
  39. package/src/ox-gantt.ts +0 -532
  40. package/src/ox-resource-chart.ts +0 -145
  41. package/src/ox-task-tooltip.ts +0 -120
  42. package/src/resource-chart-controller.ts +0 -284
  43. package/src/types.ts +0 -32
  44. package/src/utils.ts +0 -13
  45. package/stories/ox-gantt-chart.stories.ts +0 -125
  46. package/stories/ox-gantt.stories.ts +0 -417
  47. package/tsconfig.json +0 -25
  48. package/web-dev-server.config.mjs +0 -27
  49. package/web-test-runner.config.mjs +0 -41
@@ -1,131 +0,0 @@
1
- import { LitElement, css, html } from 'lit'
2
- import { customElement } from 'lit/decorators.js'
3
-
4
- @customElement('ox-gantt-resize-splitter')
5
- export class OxGanttResizeSplitter extends LitElement {
6
- static styles = css`
7
- :host {
8
- position: relative;
9
- opacity: 0.7;
10
- background-color: var(--splitter-background-color);
11
- width: var(--width);
12
- height: var(--height);
13
- }
14
-
15
- :host(:hover) {
16
- background-color: var(--splitter-hover-background-color);
17
- }
18
-
19
- div {
20
- width: var(--width);
21
- height: var(--height);
22
- }
23
- `
24
-
25
- private dragstart?: { x: number; y: number }
26
-
27
- connectedCallback() {
28
- super.connectedCallback()
29
-
30
- if (this.hasAttribute('vertical')) {
31
- this.style.setProperty('--width', '3px')
32
- this.style.setProperty('--height', '100%')
33
- this.style.cursor = 'col-resize'
34
- } else {
35
- this.style.setProperty('--height', '3px')
36
- this.style.setProperty('--width', '100%')
37
- this.style.cursor = 'row-resize'
38
- }
39
- }
40
-
41
- render() {
42
- return html`<div @mousedown=${(e: MouseEvent) => this.onMouseDown(e)}></div>`
43
- }
44
-
45
- private onMouseDown(e: MouseEvent) {
46
- this.dragstart = {
47
- x: e.clientX,
48
- y: e.clientY
49
- }
50
-
51
- this.dispatchEvent(
52
- new CustomEvent('splitter-dragstart', {
53
- bubbles: true,
54
- composed: true
55
- })
56
- )
57
-
58
- this.parentElement!.addEventListener('mousemove', this.onMouseMoveHandler)
59
- this.parentElement!.addEventListener('mouseup', this.onMouseUpHandler)
60
- window.addEventListener('mousemove', this.onMouseMoveHandler)
61
- window.addEventListener('mouseup', this.onMouseUpHandler)
62
-
63
- e.stopPropagation()
64
- }
65
-
66
- private onMouseMoveHandler = (e: MouseEvent) => this.onMouseMove(e)
67
- private onMouseUpHandler = (e: MouseEvent) => this.onMouseUp(e)
68
-
69
- private onMouseMove(e: MouseEvent) {
70
- if (!this.dragstart) {
71
- return
72
- }
73
-
74
- const parentRect = this.parentElement!.getBoundingClientRect()
75
- if (
76
- e.clientX < parentRect.left ||
77
- e.clientX > parentRect.right ||
78
- e.clientY < parentRect.top ||
79
- e.clientY > parentRect.bottom
80
- ) {
81
- this.onMouseUp(e)
82
- return
83
- }
84
-
85
- e.preventDefault()
86
-
87
- this.dispatchEvent(
88
- new CustomEvent('splitter-drag', {
89
- bubbles: true,
90
- composed: true,
91
- detail: {
92
- x: e.clientX - this.dragstart!.x,
93
- y: e.clientY - this.dragstart!.y
94
- }
95
- })
96
- )
97
-
98
- if (this.hasAttribute('vertical')) {
99
- document.body.style.cursor = 'col-resize'
100
- } else {
101
- document.body.style.cursor = 'row-resize'
102
- }
103
-
104
- document.body.style.userSelect = 'none'
105
-
106
- e.stopPropagation()
107
- }
108
-
109
- private onMouseUp(e: MouseEvent) {
110
- this.parentElement!.removeEventListener('mousemove', this.onMouseMoveHandler)
111
- this.parentElement!.removeEventListener('mouseup', this.onMouseUpHandler)
112
- window.removeEventListener('mousemove', this.onMouseMoveHandler)
113
- window.removeEventListener('mouseup', this.onMouseUpHandler)
114
-
115
- this.dispatchEvent(
116
- new CustomEvent('splitter-dragend', {
117
- bubbles: true,
118
- composed: true,
119
- detail: {
120
- x: e.clientX - this.dragstart!.x,
121
- y: e.clientY - this.dragstart!.y
122
- }
123
- })
124
- )
125
-
126
- document.body.style.cursor = ''
127
- document.body.style.userSelect = ''
128
-
129
- e.stopPropagation()
130
- }
131
- }
package/src/ox-gantt.ts DELETED
@@ -1,532 +0,0 @@
1
- import { LitElement, html, css, PropertyValues, PropertyValueMap, nothing, TemplateResult } from 'lit'
2
- import * as d3 from 'd3'
3
- import { customElement, property, query, state } from 'lit/decorators.js'
4
- import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'
5
- import { i18next, localize } from '@operato/i18n'
6
- import { ScrollbarStyles } from '@operato/styles'
7
-
8
- import './ox-gantt-chart.js'
9
- import './ox-resource-chart.js'
10
- import './ox-gantt-resize-splitter.js'
11
- import { OxGanttChart } from './ox-gantt-chart.js'
12
- import { OxResourceChart } from './ox-resource-chart.js'
13
- import { ColumnConfig, Task, TimeScale, Resource } from './types.js'
14
-
15
- @customElement('ox-gantt')
16
- export class OxGantt extends localize(i18next)(LitElement) {
17
- static styles = [
18
- MDTypeScaleStyles,
19
- ScrollbarStyles,
20
- css`
21
- :host {
22
- display: block;
23
- font-family: Arial, sans-serif;
24
- text-wrap: nowrap;
25
- position: relative;
26
- }
27
-
28
- .container {
29
- flex: 1;
30
-
31
- display: flex;
32
- flex-direction: column;
33
- width: 100%;
34
- height: 100%;
35
- box-sizing: border-box;
36
- }
37
-
38
- .resource-container {
39
- height: 300px;
40
-
41
- display: flex;
42
- overflow: hidden;
43
- box-sizing: border-box;
44
- }
45
-
46
- .resource-table-container {
47
- padding: 0;
48
- overflow: auto;
49
- overflow-y: overlay;
50
- box-sizing: border-box;
51
- border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-outline));
52
- }
53
-
54
- .resource-chart-container {
55
- flex: 1;
56
- padding: 0;
57
- box-sizing: border-box;
58
- border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-outline));
59
- }
60
-
61
- .task-container {
62
- flex: 1;
63
-
64
- display: flex;
65
- overflow: hidden;
66
- box-sizing: border-box;
67
- }
68
-
69
- .task-table-container {
70
- padding: 0;
71
- overflow: auto;
72
- overflow-y: overlay;
73
- box-sizing: border-box;
74
- border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-outline));
75
- }
76
-
77
- .task-chart-container {
78
- flex: 1;
79
- padding: 0;
80
- box-sizing: border-box;
81
- border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-outline));
82
- }
83
-
84
- table {
85
- width: 100%;
86
- border-collapse: collapse;
87
- border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-outline));
88
- margin: -1px;
89
- margin-right: 0;
90
- }
91
-
92
- thead th {
93
- position: sticky;
94
- top: -1px;
95
- z-index: 1;
96
- color: var(--ox-gantt-header-color, var(--md-sys-color-on-secondary-container));
97
- background-color: var(--ox-gantt-header-background-color, var(--md-sys-color-secondary-container));
98
- border-color: var(--ox-gantt-header-border-color, var(--md-sys-color-outline));
99
- text-transform: capitalize;
100
- }
101
-
102
- th,
103
- td {
104
- border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-outline));
105
- padding: 4px;
106
- text-align: left;
107
- }
108
-
109
- th {
110
- height: 40px;
111
- box-sizing: border-box;
112
- text-align: center;
113
- }
114
-
115
- td {
116
- height: 30px;
117
- box-sizing: border-box;
118
- }
119
-
120
- tr.selected {
121
- color: var(--ox-gantt-selected-color, var(--md-sys-color-on-surface));
122
- background-color: var(--ox-gantt-selected-background-color, var(--md-sys-color-surface-variant));
123
- }
124
-
125
- .resource-table-container th {
126
- height: 30px;
127
- }
128
-
129
- svg.toggle-icon[collapsed] {
130
- transform: rotate(-90deg);
131
- }
132
-
133
- span[group] {
134
- cursor: pointer;
135
- user-select: none;
136
- }
137
- `
138
- ]
139
-
140
- @property({ type: Array }) tasks: Task[] = []
141
- @property({ type: Array }) resources: Resource[] = []
142
- @property({ type: String, attribute: 'from-date' })
143
- fromDate: string = new Date(new Date().getFullYear(), 0, 1).toISOString().split('T')[0] /* beginning of this year */
144
- @property({ type: String, attribute: 'to-date' })
145
- toDate: string = new Date(new Date().getFullYear(), 11, 31).toISOString().split('T')[0] /* end of this year */
146
- @property({ type: Boolean, attribute: 'extend-grid-lines' }) extendGridLines: boolean = false
147
- @property({ type: String, attribute: 'time-scale' }) timeScale: TimeScale = 'week-day'
148
- @property({ type: Object }) colorProvider: (task: Task) => string = (task: Task) => {
149
- const { tags = [] } = task
150
- if (tags.includes('critical')) {
151
- return 'red'
152
- } else if (tags.includes('milestone')) {
153
- return 'blue'
154
- } else if (tags.includes('done')) {
155
- return 'green'
156
- }
157
- return 'grey'
158
- }
159
- @property({ type: Object }) columnConfigProvider: () => ColumnConfig[] = function () {
160
- return [
161
- { name: 'id', label: i18next.t('label.gantt-task-id') || 'ID', visible: true, width: 50, order: 1 },
162
- { name: 'title', label: i18next.t('label.gantt-task-title') || 'title', visible: true, width: 150, order: 2 },
163
- { name: 'type', label: i18next.t('label.gantt-task-type') || 'type', visible: true, width: 100, order: 3 },
164
- {
165
- name: 'startDate',
166
- label: i18next.t('label.gantt-task-start-date') || 'start date',
167
- visible: true,
168
- width: 100,
169
- order: 4
170
- },
171
- {
172
- name: 'endDate',
173
- label: i18next.t('label.gantt-task-end-date') || 'end date',
174
- visible: true,
175
- width: 100,
176
- order: 5
177
- },
178
- {
179
- name: 'duration',
180
- label: i18next.t('label.gantt-task-duration') || 'duration',
181
- visible: true,
182
- width: 30,
183
- order: 6
184
- },
185
- { name: 'tags', label: i18next.t('label.gantt-task-tags') || 'tags', visible: true, width: 100, order: 7 },
186
- {
187
- name: 'progress',
188
- label: i18next.t('label.gantt-task-progress') || 'progress',
189
- visible: true,
190
- width: 100,
191
- order: 8
192
- },
193
- {
194
- name: 'dependsOn',
195
- label: i18next.t('label.gantt-task-previous') || 'previous',
196
- visible: true,
197
- width: 100,
198
- order: 9
199
- },
200
- {
201
- name: 'resources',
202
- label: i18next.t('label.gantt-task-resources') || 'resources',
203
- visible: true,
204
- width: 100,
205
- order: 10
206
- }
207
- ]
208
- }
209
-
210
- @state() selectedTaskId?: string
211
-
212
- @query('.task-container') taskContainer!: HTMLDivElement
213
- @query('.task-table-container') taskTableContainer!: HTMLDivElement
214
- @query('.resource-container') resourceContainer!: HTMLDivElement
215
- @query('.resource-table-container') resourceTableContainer!: HTMLDivElement
216
- @query('.task-table') taskTable!: HTMLTableElement
217
- @query('ox-gantt-chart') ganttChart!: OxGanttChart
218
- @query('ox-resource-chart') resourceChart!: OxResourceChart
219
-
220
- private _startWidth: number = 0
221
- private _startHeight: number = 0
222
- private _isDragging: boolean = false
223
-
224
- render() {
225
- return html`
226
- <div class="container md-typescale-body-medium">
227
- <div class="task-container">
228
- <div class="task-table-container" @scroll=${this.syncScroll}>${this.renderTaskTable()}</div>
229
- <ox-gantt-resize-splitter
230
- vertical
231
- @splitter-dragstart=${(e: CustomEvent) => this.resizeHorizontalStart(e)}
232
- @splitter-drag=${(e: CustomEvent) => this.resizeHorizontalDrag(e)}
233
- @splitter-dragend=${(e: CustomEvent) => this.resizeHorizontalEnd(e)}
234
- ></ox-gantt-resize-splitter>
235
- <ox-gantt-chart
236
- class="task-chart-container"
237
- @scroll=${this.syncScroll}
238
- .fromDate=${this.fromDate}
239
- .toDate=${this.toDate}
240
- .tasks=${this.tasks}
241
- .selectedTaskId=${this.selectedTaskId}
242
- .axisScale=${this.timeScale}
243
- .colorProvider=${this.colorProvider}
244
- ?extend-grid-lines=${this.extendGridLines}
245
- @task-clicked=${this.handleTaskClicked}
246
- @timescale-changed=${(e: CustomEvent) => this.syncTimeScale(e)}
247
- ></ox-gantt-chart>
248
- </div>
249
- <ox-gantt-resize-splitter
250
- horizontal
251
- @splitter-dragstart=${(e: CustomEvent) => this.resizeVerticalStart(e)}
252
- @splitter-drag=${(e: CustomEvent) => this.resizeVerticalDrag(e)}
253
- @splitter-dragend=${(e: CustomEvent) => this.resizeVerticalEnd(e)}
254
- ></ox-gantt-resize-splitter>
255
- <div class="resource-container">
256
- <div class="resource-table-container" @scroll=${this.syncScroll}>
257
- <table>
258
- <thead>
259
- <tr>
260
- <th style="width: 100px">${i18next.t('label.gantt-resource-type')}</th>
261
- <th>${i18next.t('label.gantt-resource-allocated')}</th>
262
- </tr>
263
- </thead>
264
- <tbody>
265
- ${this.resources.map(resource => this.renderResourceRow(resource))}
266
- </tbody>
267
- </table>
268
- </div>
269
- <ox-gantt-resize-splitter
270
- vertical
271
- @splitter-dragstart=${(e: CustomEvent) => this.resizeHorizontalStart(e)}
272
- @splitter-drag=${(e: CustomEvent) => this.resizeHorizontalDrag(e)}
273
- @splitter-dragend=${(e: CustomEvent) => this.resizeHorizontalEnd(e)}
274
- ></ox-gantt-resize-splitter>
275
- <ox-resource-chart
276
- class="resource-chart-container"
277
- .fromDate=${this.fromDate}
278
- .toDate=${this.toDate}
279
- .tasks=${this.tasks}
280
- .resources=${this.resources}
281
- .axisScale=${this.timeScale}
282
- @scroll=${this.syncScroll}
283
- ></ox-resource-chart>
284
- </div>
285
- </div>
286
- `
287
- }
288
-
289
- renderTaskTable() {
290
- const columnConfig = this.columnConfigProvider()
291
- if (!columnConfig) {
292
- return
293
- }
294
-
295
- // Sort columns by the configured order
296
- const sortedColumns = [...columnConfig].sort((a, b) => a.order - b.order)
297
-
298
- return html`
299
- <table class="task-table">
300
- <thead>
301
- <tr>
302
- ${sortedColumns.map(col =>
303
- col.visible ? html`<th style="width: ${col.width}px">${col.label}</th>` : nothing
304
- )}
305
- </tr>
306
- </thead>
307
- <tbody>
308
- ${this.renderTaskRows(this.tasks, 0, columnConfig)}
309
- </tbody>
310
- </table>
311
- `
312
- }
313
-
314
- renderTaskRows(tasks: Task[], level: number = 0, columnConfig: ColumnConfig[]): TemplateResult[] {
315
- return (tasks || []).flatMap(task => {
316
- if (task.collapsed) {
317
- return [this.renderTaskRow(task, level, columnConfig)]
318
- } else {
319
- return [
320
- this.renderTaskRow(task, level, columnConfig),
321
- ...this.renderTaskRows(task.children || [], level + 1, columnConfig)
322
- ]
323
- }
324
- })
325
- }
326
-
327
- renderTaskRow(task: Task, level: number, columnConfig: ColumnConfig[]) {
328
- const isGroupTask = task.children && task.children.length > 0
329
- const isCollapsed = !!task.collapsed
330
- const paddingLeft = level * 16 + 4 // 트리 구조를 위한 패딩
331
-
332
- return html`
333
- <tr class=${this.selectedTaskId === task.id ? 'selected' : ''} @click=${() => this.selectTask(task.id)}>
334
- ${columnConfig.map(col =>
335
- col.visible
336
- ? html`
337
- <td class="task-row" style="padding-left: ${col.name === 'title' ? paddingLeft : 4}px">
338
- ${col.name === 'title'
339
- ? html`
340
- ${isGroupTask
341
- ? html`
342
- <span class="toggle-icon" @click=${(e: Event) => this.toggleCollapse(e, task)} group>
343
- ${isGroupTask
344
- ? html`
345
- <svg
346
- class="toggle-icon"
347
- width="10"
348
- height="10"
349
- viewBox="0 0 10 10"
350
- xmlns="http://www.w3.org/2000/svg"
351
- ?collapsed=${isCollapsed}
352
- >
353
- <polygon
354
- points="0,1 10,1 5,9"
355
- fill="var(--md-sys-color-on-primary-container)"
356
- opacity="0.5"
357
- />
358
- </svg>
359
- `
360
- : nothing}
361
- </span>
362
- `
363
- : nothing}
364
- ${this.getTaskFieldValue(task, col.name)}
365
- `
366
- : this.getTaskFieldValue(task, col.name)}
367
- </td>
368
- `
369
- : nothing
370
- )}
371
- </tr>
372
- `
373
- }
374
-
375
- toggleCollapse(e: Event, task: Task) {
376
- e.stopPropagation() // 클릭 이벤트 전파 방지
377
-
378
- task.collapsed = !task.collapsed
379
- this.requestUpdate()
380
-
381
- this.ganttChart.tasks = [...this.tasks]
382
- }
383
-
384
- renderResourceRow(resource: Resource) {
385
- return html`
386
- <tr>
387
- <td>${resource.type}</td>
388
- <td>${resource.allocated}</td>
389
- </tr>
390
- `
391
- }
392
-
393
- getTaskFieldValue(task: Task, field: string) {
394
- switch (field) {
395
- case 'id':
396
- return task.id
397
- case 'title':
398
- return task.title
399
- case 'type':
400
- return task.type
401
- case 'startDate':
402
- return new Date(task.startDate).toISOString().split('T')[0]
403
- case 'endDate':
404
- return new Date(task.endDate).toISOString().split('T')[0]
405
- case 'duration':
406
- return task.duration || 0
407
- case 'tags':
408
- return task.tags?.join(', ') || ''
409
- case 'progress':
410
- return task.progress || ''
411
- case 'dependsOn':
412
- return task.dependsOn || ''
413
- case 'resources':
414
- return task.resources?.map(res => `${res.type}: ${res.allocated}`).join(', ') || ''
415
- default:
416
- return ''
417
- }
418
- }
419
-
420
- selectTask(taskId: string) {
421
- this.selectedTaskId = taskId
422
- }
423
-
424
- handleTaskClicked(event: CustomEvent) {
425
- this.selectedTaskId = event.detail.taskId
426
- }
427
-
428
- protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
429
- this.taskTableContainer.style.width = '254px'
430
- this.resourceTableContainer.style.width = '254px'
431
- }
432
-
433
- updated(changedProperties: PropertyValues<this>) {
434
- if (changedProperties.has('tasks')) {
435
- this.resources = this.aggregateResources(this.tasks)
436
- }
437
- }
438
-
439
- aggregateResources(tasks: Task[]): Resource[] {
440
- const resourceMap: { [key: string]: number } = {}
441
-
442
- const traverseTasks = (tasks: Task[]) => {
443
- tasks.forEach(task => {
444
- if (task.resources) {
445
- const startDate = new Date(task.startDate)
446
- const endDate = new Date(task.endDate)
447
- const durationDays = d3.timeDay.count(startDate, d3.timeDay.offset(endDate, 1))
448
-
449
- task.resources.forEach(resource => {
450
- const totalAllocation = resource.allocated * durationDays
451
- if (!resourceMap[resource.type]) {
452
- resourceMap[resource.type] = 0
453
- }
454
- resourceMap[resource.type] += totalAllocation
455
- })
456
- }
457
-
458
- if (task.children) {
459
- traverseTasks(task.children)
460
- }
461
- })
462
- }
463
-
464
- traverseTasks(tasks)
465
-
466
- return Object.keys(resourceMap).map(type => ({
467
- type,
468
- allocated: resourceMap[type]
469
- }))
470
- }
471
-
472
- syncScroll(e: Event) {
473
- const target = e.target as HTMLElement
474
-
475
- if (target === this.taskTableContainer) {
476
- const newScrollTop = this.taskTableContainer.scrollTop
477
- this.ganttChart.setVerticalOffset(newScrollTop)
478
- } else if (target === this.ganttChart) {
479
- const newScrollTop = this.ganttChart.getVerticalOffset()
480
- this.taskTableContainer.scrollTop = newScrollTop
481
-
482
- const newScrollLeft = this.ganttChart.getHorizontalOffset()
483
- this.resourceChart.setHorizontalOffset(newScrollLeft)
484
- } else if (target === this.resourceChart) {
485
- const newScrollTop = this.resourceChart.getVerticalOffset()
486
- this.resourceTableContainer.scrollTop = newScrollTop
487
-
488
- const newScrollLeft = this.resourceChart.getHorizontalOffset()
489
- this.ganttChart.setHorizontalOffset(newScrollLeft)
490
- } else if (target === this.resourceTableContainer) {
491
- const newScrollTop = this.resourceTableContainer.scrollTop
492
- this.resourceChart.setVerticalOffset(newScrollTop)
493
- }
494
- }
495
-
496
- syncTimeScale(e: CustomEvent) {
497
- const detail = e.detail
498
- this.resourceChart.syncTimeScale(detail)
499
- }
500
-
501
- resizeHorizontalStart(e: CustomEvent) {
502
- this._startWidth = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement)?.offsetWidth
503
- this._isDragging = true
504
- }
505
-
506
- resizeHorizontalDrag(e: CustomEvent) {
507
- if (!this._isDragging) return
508
- const delta = e.detail
509
- this.taskTableContainer.style.width = `${this._startWidth + delta.x}px`
510
- this.resourceTableContainer.style.width = `${this._startWidth + delta.x}px`
511
- }
512
-
513
- resizeHorizontalEnd(e: CustomEvent) {
514
- this._isDragging = false
515
- }
516
-
517
- resizeVerticalStart(e: CustomEvent) {
518
- this._startHeight = ((e.target as HTMLElement)?.nextElementSibling as HTMLElement)?.offsetHeight
519
- this._isDragging = true
520
- }
521
-
522
- resizeVerticalDrag(e: CustomEvent) {
523
- if (!this._isDragging) return
524
- const delta = e.detail
525
-
526
- this.resourceContainer.style.height = `${this._startHeight - delta.y}px`
527
- }
528
-
529
- resizeVerticalEnd(e: CustomEvent) {
530
- this._isDragging = false
531
- }
532
- }