@operato/gantt 8.0.0-alpha.10 → 8.0.0-alpha.27
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/CHANGELOG.md +18 -0
- package/dist/src/gantt-chart-controller.d.ts +12 -6
- package/dist/src/gantt-chart-controller.js +149 -29
- package/dist/src/gantt-chart-controller.js.map +1 -1
- package/dist/src/ox-gantt-chart.d.ts +2 -0
- package/dist/src/ox-gantt-chart.js +41 -69
- package/dist/src/ox-gantt-chart.js.map +1 -1
- package/dist/src/ox-gantt-resize-splitter.d.ts +6 -2
- package/dist/src/ox-gantt-resize-splitter.js +70 -39
- package/dist/src/ox-gantt-resize-splitter.js.map +1 -1
- package/dist/src/ox-gantt.js +9 -0
- package/dist/src/ox-gantt.js.map +1 -1
- package/dist/src/ox-resource-chart.js +2 -0
- package/dist/src/ox-resource-chart.js.map +1 -1
- package/dist/src/ox-task-tooltip.d.ts +3 -1
- package/dist/src/ox-task-tooltip.js +36 -11
- package/dist/src/ox-task-tooltip.js.map +1 -1
- package/dist/stories/ox-gantt.stories.js +16 -0
- package/dist/stories/ox-gantt.stories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/gantt-chart-controller.ts +171 -37
- package/src/ox-gantt-chart.ts +46 -69
- package/src/ox-gantt-resize-splitter.ts +72 -44
- package/src/ox-gantt.ts +9 -0
- package/src/ox-resource-chart.ts +2 -0
- package/src/ox-task-tooltip.ts +31 -9
- package/stories/ox-gantt.stories.ts +16 -0
- package/themes/calendar-theme.css +3 -1
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@operato/gantt",
|
|
3
3
|
"description": "Webcomponents for gantt chart following open-wc recommendations",
|
|
4
4
|
"author": "heartyoh@hatiolab.com",
|
|
5
|
-
"version": "8.0.0-alpha.
|
|
5
|
+
"version": "8.0.0-alpha.27",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
7
7
|
"module": "dist/src/index.js",
|
|
8
8
|
"license": "MIT",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@operato/i18n": "^8.0.0-alpha.0",
|
|
46
|
-
"@operato/styles": "^8.0.0-alpha.
|
|
46
|
+
"@operato/styles": "^8.0.0-alpha.27",
|
|
47
47
|
"@operato/utils": "^8.0.0-alpha.0",
|
|
48
48
|
"d3": "^7.8.5",
|
|
49
49
|
"d3-time-format": "^4.1.0",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"prettier --write"
|
|
86
86
|
]
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "7f16dfa02491950f7a8782cb305605925a9e0be4"
|
|
89
89
|
}
|
|
@@ -3,18 +3,22 @@ import * as d3 from 'd3'
|
|
|
3
3
|
import { TimeScale, Task, TaskTag } from './types'
|
|
4
4
|
import { OxTaskTooltip } from './ox-task-tooltip'
|
|
5
5
|
import { drawTimeScaleHeader, getScale, getChartWidth } from './draw-time-scale-header'
|
|
6
|
+
import { levelDown, levelUp } from './utils'
|
|
6
7
|
|
|
7
8
|
export class GanttChartController implements ReactiveController {
|
|
8
|
-
private host: ReactiveControllerHost & LitElement
|
|
9
|
+
private host: (ReactiveControllerHost & LitElement) | null
|
|
9
10
|
private fromTime: Date
|
|
10
11
|
private toTime: Date
|
|
11
12
|
private totalDays: number
|
|
12
13
|
private _timeScale?: d3.ScaleTime<number, number, never>
|
|
13
14
|
|
|
14
|
-
private touchStartX
|
|
15
|
-
private touchStartY
|
|
16
|
-
private scrollStartX
|
|
17
|
-
private scrollStartY
|
|
15
|
+
private touchStartX: number | null = null
|
|
16
|
+
private touchStartY: number | null = null
|
|
17
|
+
private scrollStartX: number | null = null
|
|
18
|
+
private scrollStartY: number | null = null
|
|
19
|
+
private lastTouchDistance?: number | null
|
|
20
|
+
private draggingThreshold: number = 20
|
|
21
|
+
private dragging: boolean = false
|
|
18
22
|
|
|
19
23
|
private colorProvider?: (task: Task) => string
|
|
20
24
|
|
|
@@ -34,6 +38,10 @@ export class GanttChartController implements ReactiveController {
|
|
|
34
38
|
this.host.addController(this)
|
|
35
39
|
}
|
|
36
40
|
|
|
41
|
+
dispose() {
|
|
42
|
+
this.host = null
|
|
43
|
+
}
|
|
44
|
+
|
|
37
45
|
hostConnected() {
|
|
38
46
|
this.updateTimeScale()
|
|
39
47
|
}
|
|
@@ -57,12 +65,12 @@ export class GanttChartController implements ReactiveController {
|
|
|
57
65
|
this.toTime = new Date(toDate)
|
|
58
66
|
this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1))
|
|
59
67
|
this._timeScale = undefined
|
|
60
|
-
this.host
|
|
68
|
+
this.host?.requestUpdate()
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
setTasks(tasks: Task[]) {
|
|
64
72
|
this.tasks = tasks
|
|
65
|
-
this.host
|
|
73
|
+
this.host?.requestUpdate()
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
updateTimeScale() {
|
|
@@ -93,7 +101,7 @@ export class GanttChartController implements ReactiveController {
|
|
|
93
101
|
.append('marker')
|
|
94
102
|
.attr('id', 'arrow')
|
|
95
103
|
.attr('viewBox', '0 0 10 10')
|
|
96
|
-
.attr('refX', 10)
|
|
104
|
+
.attr('refX', 10)
|
|
97
105
|
.attr('refY', 5)
|
|
98
106
|
.attr('markerWidth', 6)
|
|
99
107
|
.attr('markerHeight', 6)
|
|
@@ -150,14 +158,20 @@ export class GanttChartController implements ReactiveController {
|
|
|
150
158
|
const taskWidth = endX - startX + this.baseWidth / this.getScale()
|
|
151
159
|
const taskY = index * 30 + 7.5
|
|
152
160
|
|
|
153
|
-
const showTooltip = (event: MouseEvent) => {
|
|
161
|
+
const showTooltip = (event: MouseEvent | TouchEvent) => {
|
|
162
|
+
tooltip.hide()
|
|
163
|
+
|
|
164
|
+
const touch = 'touches' in event
|
|
165
|
+
const x = touch ? event.touches[0].clientX : event.clientX
|
|
166
|
+
const y = touch ? event.touches[0].clientY : event.clientY
|
|
167
|
+
|
|
154
168
|
tooltip.title = task.title
|
|
155
169
|
tooltip.startDate = startDate.toISOString().split('T')[0]
|
|
156
170
|
tooltip.endDate = endDate.toISOString().split('T')[0]
|
|
157
171
|
tooltip.progress = task.progress ?? 0
|
|
158
172
|
tooltip.type = task.type
|
|
159
173
|
|
|
160
|
-
tooltip.show(
|
|
174
|
+
tooltip.show(x, y)
|
|
161
175
|
}
|
|
162
176
|
|
|
163
177
|
const hideTooltip = () => {
|
|
@@ -192,8 +206,21 @@ export class GanttChartController implements ReactiveController {
|
|
|
192
206
|
bubbles: true,
|
|
193
207
|
composed: true
|
|
194
208
|
})
|
|
195
|
-
this.host
|
|
196
|
-
this.host
|
|
209
|
+
this.host?.dispatchEvent(customEvent)
|
|
210
|
+
this.host?.requestUpdate()
|
|
211
|
+
})
|
|
212
|
+
.on('touchstart', e => {
|
|
213
|
+
this.selectedTaskId = task.id
|
|
214
|
+
const customEvent = new CustomEvent('task-clicked', {
|
|
215
|
+
detail: { taskId: task.id },
|
|
216
|
+
bubbles: true,
|
|
217
|
+
composed: true
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
showTooltip(e)
|
|
221
|
+
|
|
222
|
+
this.host?.dispatchEvent(customEvent)
|
|
223
|
+
this.host?.requestUpdate()
|
|
197
224
|
})
|
|
198
225
|
.on('mouseover', showTooltip)
|
|
199
226
|
.on('mouseout', hideTooltip)
|
|
@@ -216,8 +243,21 @@ export class GanttChartController implements ReactiveController {
|
|
|
216
243
|
bubbles: true,
|
|
217
244
|
composed: true
|
|
218
245
|
})
|
|
219
|
-
this.host
|
|
220
|
-
this.host
|
|
246
|
+
this.host?.dispatchEvent(customEvent)
|
|
247
|
+
this.host?.requestUpdate()
|
|
248
|
+
})
|
|
249
|
+
.on('touchstart', e => {
|
|
250
|
+
this.selectedTaskId = task.id
|
|
251
|
+
const customEvent = new CustomEvent('task-clicked', {
|
|
252
|
+
detail: { taskId: task.id },
|
|
253
|
+
bubbles: true,
|
|
254
|
+
composed: true
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
showTooltip(e)
|
|
258
|
+
|
|
259
|
+
this.host?.dispatchEvent(customEvent)
|
|
260
|
+
this.host?.requestUpdate()
|
|
221
261
|
})
|
|
222
262
|
.on('mouseover', showTooltip)
|
|
223
263
|
.on('mouseout', hideTooltip)
|
|
@@ -256,7 +296,7 @@ export class GanttChartController implements ReactiveController {
|
|
|
256
296
|
.attr('stroke', 'var(--md-sys-color-on-primary-container, black)')
|
|
257
297
|
.attr('fill', 'none')
|
|
258
298
|
.attr('stroke-width', 1)
|
|
259
|
-
.attr('marker-end', 'url(#arrow)')
|
|
299
|
+
.attr('marker-end', 'url(#arrow)')
|
|
260
300
|
}
|
|
261
301
|
})
|
|
262
302
|
}
|
|
@@ -299,38 +339,132 @@ export class GanttChartController implements ReactiveController {
|
|
|
299
339
|
composed: true
|
|
300
340
|
})
|
|
301
341
|
|
|
302
|
-
this.host
|
|
342
|
+
this.host?.dispatchEvent(customEvent)
|
|
303
343
|
}
|
|
304
344
|
|
|
305
|
-
handleTouchStartForBody(event: TouchEvent, container: HTMLDivElement) {
|
|
345
|
+
handleTouchStartForBody(event: MouseEvent | TouchEvent, container: HTMLDivElement) {
|
|
346
|
+
event.preventDefault()
|
|
306
347
|
event.stopPropagation()
|
|
307
348
|
|
|
308
|
-
|
|
309
|
-
|
|
349
|
+
const touch = 'touches' in event
|
|
350
|
+
const x = touch ? event.touches[0].clientX : event.clientX
|
|
351
|
+
const y = touch ? event.touches[0].clientY : event.clientY
|
|
310
352
|
|
|
311
|
-
this.
|
|
312
|
-
|
|
353
|
+
this.dragging = false
|
|
354
|
+
|
|
355
|
+
if (touch && event.touches.length === 2) {
|
|
356
|
+
this.lastTouchDistance = this.getTouchDistance(event.touches)
|
|
357
|
+
} else {
|
|
358
|
+
this.touchStartX = x
|
|
359
|
+
this.touchStartY = y
|
|
360
|
+
|
|
361
|
+
this.scrollStartX = container.scrollLeft
|
|
362
|
+
this.scrollStartY = container.scrollTop
|
|
363
|
+
}
|
|
313
364
|
}
|
|
314
365
|
|
|
315
|
-
handleTouchMoveForBody(event: TouchEvent, container: HTMLDivElement) {
|
|
316
|
-
|
|
317
|
-
|
|
366
|
+
handleTouchMoveForBody(event: MouseEvent | TouchEvent, container: HTMLDivElement) {
|
|
367
|
+
event.preventDefault()
|
|
368
|
+
event.stopPropagation()
|
|
318
369
|
|
|
319
|
-
const
|
|
320
|
-
const
|
|
370
|
+
const touch = 'touches' in event
|
|
371
|
+
const x = touch ? event.touches[0].clientX : event.clientX
|
|
372
|
+
const y = touch ? event.touches[0].clientY : event.clientY
|
|
373
|
+
|
|
374
|
+
if (touch && event.touches.length > 1 && this.lastTouchDistance !== null) {
|
|
375
|
+
const currentDistance = this.getTouchDistance(event.touches)
|
|
376
|
+
|
|
377
|
+
const zoomSensitivity = 0.3
|
|
378
|
+
let zoomFactor = currentDistance / this.lastTouchDistance!
|
|
379
|
+
zoomFactor = 1 + (zoomFactor - 1) * zoomSensitivity
|
|
380
|
+
|
|
381
|
+
this.baseWidth *= zoomFactor
|
|
382
|
+
|
|
383
|
+
if (this.baseWidth > 40) {
|
|
384
|
+
if (this.level === 'week-day') {
|
|
385
|
+
this.baseWidth = 40
|
|
386
|
+
} else {
|
|
387
|
+
this.level = levelDown(this.level)
|
|
388
|
+
this.baseWidth = 30
|
|
389
|
+
}
|
|
390
|
+
} else if (this.baseWidth < 30) {
|
|
391
|
+
if (this.level === 'year-quarter') {
|
|
392
|
+
this.baseWidth = 30
|
|
393
|
+
}
|
|
394
|
+
}
|
|
321
395
|
|
|
322
|
-
|
|
323
|
-
|
|
396
|
+
if (this.baseWidth < 20) {
|
|
397
|
+
this.level = levelUp(this.level)
|
|
398
|
+
this.baseWidth = 30
|
|
399
|
+
}
|
|
324
400
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
401
|
+
this.lastTouchDistance = currentDistance
|
|
402
|
+
this.updateTimeScale()
|
|
403
|
+
this.host?.requestUpdate()
|
|
404
|
+
|
|
405
|
+
const customEvent = new CustomEvent('timescale-changed', {
|
|
406
|
+
detail: {
|
|
407
|
+
baseWidth: this.baseWidth,
|
|
408
|
+
level: this.level
|
|
409
|
+
},
|
|
410
|
+
bubbles: true,
|
|
411
|
+
composed: true
|
|
412
|
+
})
|
|
413
|
+
this.host?.dispatchEvent(customEvent)
|
|
414
|
+
} else if (this.touchStartX !== null) {
|
|
415
|
+
const dx = this.touchStartX! - x
|
|
416
|
+
const dy = this.touchStartY! - y
|
|
417
|
+
|
|
418
|
+
if (!this.dragging) {
|
|
419
|
+
if (Math.sqrt(dx * dx + dy * dy) > this.draggingThreshold) {
|
|
420
|
+
this.dragging = true
|
|
421
|
+
} else {
|
|
422
|
+
return
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
container.scrollLeft = this.scrollStartX! + dx
|
|
427
|
+
container.scrollTop = this.scrollStartY! + dy
|
|
428
|
+
|
|
429
|
+
const customEvent = new CustomEvent('scroll', {
|
|
430
|
+
detail: {
|
|
431
|
+
scrollLeft: container.scrollLeft,
|
|
432
|
+
scrollTop: container.scrollTop
|
|
433
|
+
},
|
|
434
|
+
bubbles: true,
|
|
435
|
+
composed: true
|
|
436
|
+
})
|
|
437
|
+
|
|
438
|
+
this.host?.dispatchEvent(customEvent)
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
handleTouchEndForBody(event: MouseEvent | TouchEvent) {
|
|
443
|
+
event.preventDefault()
|
|
444
|
+
event.stopPropagation()
|
|
445
|
+
|
|
446
|
+
if ('touches' in event && event.touches.length > 1) {
|
|
447
|
+
this.lastTouchDistance = null
|
|
448
|
+
} else if (this.touchStartX !== null) {
|
|
449
|
+
if (!this.dragging) {
|
|
450
|
+
this.host?.dispatchEvent(
|
|
451
|
+
new CustomEvent('date-range-cleared', {
|
|
452
|
+
bubbles: true,
|
|
453
|
+
composed: true
|
|
454
|
+
})
|
|
455
|
+
)
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
this.touchStartX = null
|
|
459
|
+
this.touchStartY = null
|
|
460
|
+
this.scrollStartX = null
|
|
461
|
+
this.scrollStartY = null
|
|
462
|
+
}
|
|
463
|
+
}
|
|
333
464
|
|
|
334
|
-
|
|
465
|
+
getTouchDistance(touches: TouchList): number {
|
|
466
|
+
const dx = touches[0].clientX - touches[1].clientX
|
|
467
|
+
const dy = touches[0].clientY - touches[1].clientY
|
|
468
|
+
return Math.sqrt(dx * dx + dy * dy)
|
|
335
469
|
}
|
|
336
470
|
}
|
package/src/ox-gantt-chart.ts
CHANGED
|
@@ -23,15 +23,20 @@ export class OxGanttChart extends LitElement {
|
|
|
23
23
|
display: flex;
|
|
24
24
|
overflow: hidden;
|
|
25
25
|
position: relative;
|
|
26
|
+
user-select: none;
|
|
26
27
|
}
|
|
28
|
+
|
|
27
29
|
div[chart-container] {
|
|
28
30
|
display: block;
|
|
29
31
|
overflow-x: auto;
|
|
30
32
|
overflow-y: hidden;
|
|
33
|
+
overscroll-behavior: none;
|
|
31
34
|
}
|
|
35
|
+
|
|
32
36
|
svg {
|
|
33
37
|
min-width: 100%;
|
|
34
38
|
}
|
|
39
|
+
|
|
35
40
|
svg[header] {
|
|
36
41
|
display: block;
|
|
37
42
|
min-width: 100%;
|
|
@@ -44,27 +49,27 @@ export class OxGanttChart extends LitElement {
|
|
|
44
49
|
top: 0;
|
|
45
50
|
z-index: 1;
|
|
46
51
|
}
|
|
47
|
-
|
|
48
|
-
position: absolute;
|
|
49
|
-
top: 44px; /* 헤더 바로 아래 위치 */
|
|
50
|
-
right: 4px;
|
|
51
|
-
display: flex;
|
|
52
|
-
align-items: center;
|
|
53
|
-
gap: 2px;
|
|
54
|
-
}
|
|
52
|
+
|
|
55
53
|
.scroll-button {
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
position: absolute;
|
|
55
|
+
top: 46px; /* 헤더 바로 아래 위치 */
|
|
56
|
+
width: 14px;
|
|
57
|
+
height: 14px;
|
|
58
58
|
background-color: var(--ox-gantt-header-color, var(--md-sys-color-on-secondary-container));
|
|
59
|
+
opacity: 0.5;
|
|
59
60
|
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
|
|
60
61
|
cursor: pointer;
|
|
61
62
|
transform: rotate(90deg);
|
|
62
63
|
}
|
|
64
|
+
|
|
63
65
|
.scroll-button.left {
|
|
66
|
+
left: 6px;
|
|
64
67
|
transform: rotate(-90deg);
|
|
65
68
|
}
|
|
69
|
+
|
|
66
70
|
.scroll-button.right {
|
|
67
71
|
transform: rotate(90deg);
|
|
72
|
+
right: 6px;
|
|
68
73
|
}
|
|
69
74
|
`
|
|
70
75
|
]
|
|
@@ -95,6 +100,14 @@ export class OxGanttChart extends LitElement {
|
|
|
95
100
|
|
|
96
101
|
protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
|
|
97
102
|
this.initHeaderGestureHandlers()
|
|
103
|
+
|
|
104
|
+
this.addEventListener('date-range-cleared', e => this.clearSelection())
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
disconnectedCallback(): void {
|
|
108
|
+
super.disconnectedCallback()
|
|
109
|
+
|
|
110
|
+
this.ganttChartController.dispose()
|
|
98
111
|
}
|
|
99
112
|
|
|
100
113
|
updated(changedProperties: PropertyValues<this>) {
|
|
@@ -133,8 +146,12 @@ export class OxGanttChart extends LitElement {
|
|
|
133
146
|
<div
|
|
134
147
|
chart-container
|
|
135
148
|
@wheel=${(e: WheelEvent) => this.ganttChartController.handleWheelForBody(e, this.container)}
|
|
149
|
+
@mousedown=${(e: MouseEvent) => this.ganttChartController.handleTouchStartForBody(e, this.container)}
|
|
150
|
+
@mousemove=${(e: MouseEvent) => this.ganttChartController.handleTouchMoveForBody(e, this.container)}
|
|
151
|
+
@mouseup=${(e: MouseEvent) => this.ganttChartController.handleTouchEndForBody(e)}
|
|
136
152
|
@touchstart=${(e: TouchEvent) => this.ganttChartController.handleTouchStartForBody(e, this.container)}
|
|
137
153
|
@touchmove=${(e: TouchEvent) => this.ganttChartController.handleTouchMoveForBody(e, this.container)}
|
|
154
|
+
@touchend=${(e: TouchEvent) => this.ganttChartController.handleTouchEndForBody(e)}
|
|
138
155
|
>
|
|
139
156
|
<svg
|
|
140
157
|
header
|
|
@@ -142,10 +159,8 @@ export class OxGanttChart extends LitElement {
|
|
|
142
159
|
@wheel=${this.handleWheelForHeader.bind(this)}
|
|
143
160
|
></svg>
|
|
144
161
|
<svg body></svg>
|
|
145
|
-
<div class="scroll-
|
|
146
|
-
|
|
147
|
-
<div class="scroll-button right" @click=${this.scrollToEnd}></div>
|
|
148
|
-
</div>
|
|
162
|
+
<div class="scroll-button left" @click=${this.scrollToStart} @touchstart=${this.scrollToStart}></div>
|
|
163
|
+
<div class="scroll-button right" @click=${this.scrollToEnd} @touchstart=${this.scrollToEnd}></div>
|
|
149
164
|
<ox-task-tooltip></ox-task-tooltip>
|
|
150
165
|
</div>
|
|
151
166
|
`
|
|
@@ -266,60 +281,22 @@ export class OxGanttChart extends LitElement {
|
|
|
266
281
|
|
|
267
282
|
let isDragging = false
|
|
268
283
|
let startX: number | null = null
|
|
269
|
-
let lastTouchDistance: number | null = null
|
|
270
284
|
|
|
271
285
|
const handleTouchStart = (event: TouchEvent) => {
|
|
272
286
|
event.preventDefault()
|
|
287
|
+
event.stopPropagation()
|
|
273
288
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const touch = event.touches[0]
|
|
279
|
-
const containerOffsetX = header.node()!.getBoundingClientRect().left
|
|
280
|
-
startX = touch.clientX - containerOffsetX
|
|
281
|
-
}
|
|
289
|
+
isDragging = true
|
|
290
|
+
const touch = event.touches[0]
|
|
291
|
+
const containerOffsetX = header.node()!.getBoundingClientRect().left
|
|
292
|
+
startX = touch.clientX - containerOffsetX
|
|
282
293
|
}
|
|
283
294
|
|
|
284
295
|
const handleTouchMove = (event: TouchEvent) => {
|
|
285
296
|
event.preventDefault()
|
|
297
|
+
event.stopPropagation()
|
|
286
298
|
|
|
287
|
-
if (
|
|
288
|
-
const currentDistance = getTouchDistance(event.touches)
|
|
289
|
-
const zoomFactor = currentDistance / lastTouchDistance
|
|
290
|
-
this.ganttChartController.baseWidth *= zoomFactor
|
|
291
|
-
|
|
292
|
-
if (this.ganttChartController.baseWidth > 60) {
|
|
293
|
-
if (this.ganttChartController.level == 'year-quarter') {
|
|
294
|
-
this.ganttChartController.baseWidth = 60
|
|
295
|
-
} else {
|
|
296
|
-
this.ganttChartController.level = levelUp(this.ganttChartController.level)
|
|
297
|
-
this.ganttChartController.baseWidth = 30
|
|
298
|
-
}
|
|
299
|
-
} else if (this.ganttChartController.baseWidth < 30) {
|
|
300
|
-
if (this.ganttChartController.level == 'week-day') {
|
|
301
|
-
this.ganttChartController.baseWidth = 30
|
|
302
|
-
} else {
|
|
303
|
-
this.ganttChartController.level = levelDown(this.ganttChartController.level)
|
|
304
|
-
this.ganttChartController.baseWidth = 60
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
lastTouchDistance = currentDistance
|
|
309
|
-
this.ganttChartController.updateTimeScale()
|
|
310
|
-
this.requestUpdate()
|
|
311
|
-
|
|
312
|
-
// Dispatch custom event to sync with ox-resource-chart
|
|
313
|
-
const customEvent = new CustomEvent('timescale-changed', {
|
|
314
|
-
detail: {
|
|
315
|
-
baseWidth: this.ganttChartController.baseWidth,
|
|
316
|
-
level: this.ganttChartController.level
|
|
317
|
-
},
|
|
318
|
-
bubbles: true,
|
|
319
|
-
composed: true
|
|
320
|
-
})
|
|
321
|
-
this.dispatchEvent(customEvent)
|
|
322
|
-
} else if (isDragging && startX !== null) {
|
|
299
|
+
if (isDragging && startX !== null) {
|
|
323
300
|
const touch = event.touches[0]
|
|
324
301
|
const containerOffsetX = header.node()!.getBoundingClientRect().left
|
|
325
302
|
const currentX = touch.clientX - containerOffsetX
|
|
@@ -329,10 +306,7 @@ export class OxGanttChart extends LitElement {
|
|
|
329
306
|
|
|
330
307
|
const handleTouchEnd = (event: TouchEvent) => {
|
|
331
308
|
event.preventDefault()
|
|
332
|
-
|
|
333
|
-
if (event.touches.length < 2) {
|
|
334
|
-
lastTouchDistance = null
|
|
335
|
-
}
|
|
309
|
+
event.stopPropagation()
|
|
336
310
|
|
|
337
311
|
if (!isDragging || startX === null) {
|
|
338
312
|
const touch = event.changedTouches[0]
|
|
@@ -351,12 +325,6 @@ export class OxGanttChart extends LitElement {
|
|
|
351
325
|
startX = null
|
|
352
326
|
}
|
|
353
327
|
|
|
354
|
-
const getTouchDistance = (touches: TouchList): number => {
|
|
355
|
-
const dx = touches[0].clientX - touches[1].clientX
|
|
356
|
-
const dy = touches[0].clientY - touches[1].clientY
|
|
357
|
-
return Math.sqrt(dx * dx + dy * dy)
|
|
358
|
-
}
|
|
359
|
-
|
|
360
328
|
const handleMouseDown = (event: MouseEvent) => {
|
|
361
329
|
isDragging = true
|
|
362
330
|
const containerOffsetX = header.node()!.getBoundingClientRect().left
|
|
@@ -515,4 +483,13 @@ export class OxGanttChart extends LitElement {
|
|
|
515
483
|
|
|
516
484
|
header.node()?.dispatchEvent(customEvent)
|
|
517
485
|
}
|
|
486
|
+
|
|
487
|
+
clearSelection() {
|
|
488
|
+
const header = d3.select(this.svgHeader)
|
|
489
|
+
const body = d3.select(this.svgBody)
|
|
490
|
+
|
|
491
|
+
// 선택한 영역을 나타내는 모든 'selection-rect' 요소를 제거합니다.
|
|
492
|
+
header.selectAll('.selection-rect').remove()
|
|
493
|
+
body.selectAll('.selection-rect').remove()
|
|
494
|
+
}
|
|
518
495
|
}
|