@operato/gantt 8.0.0-alpha.6 → 8.0.0-beta.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +113 -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/src/gantt-chart-controller.ts +100 -34
  25. package/src/ox-gantt-chart.ts +92 -192
  26. package/src/ox-gantt-resize-splitter.ts +72 -44
  27. package/src/ox-gantt.ts +12 -9
  28. package/src/ox-resource-chart.ts +2 -0
  29. package/src/ox-task-tooltip.ts +31 -9
  30. package/src/types.ts +1 -0
  31. package/stories/ox-gantt.stories.ts +37 -1
  32. package/themes/calendar-theme.css +3 -1
  33. package/assets/images/icon-editor-gradient-direction.png +0 -0
  34. package/assets/images/icon-properties-label.png +0 -0
  35. package/assets/images/icon-properties-line-type.png +0 -0
  36. package/assets/images/icon-properties-table.png +0 -0
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.6",
5
+ "version": "8.0.0-beta.0",
6
6
  "main": "dist/src/index.js",
7
7
  "module": "dist/src/index.js",
8
8
  "license": "MIT",
@@ -42,9 +42,9 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "@operato/i18n": "^8.0.0-alpha.0",
46
- "@operato/styles": "^8.0.0-alpha.4",
47
- "@operato/utils": "^8.0.0-alpha.0",
45
+ "@operato/i18n": "^8.0.0-beta.0",
46
+ "@operato/styles": "^8.0.0-beta.0",
47
+ "@operato/utils": "^8.0.0-beta.0",
48
48
  "d3": "^7.8.5",
49
49
  "d3-time-format": "^4.1.0",
50
50
  "i18next": "^23.11.5",
@@ -52,18 +52,18 @@
52
52
  "lodash-es": "^4.17.21"
53
53
  },
54
54
  "devDependencies": {
55
- "@custom-elements-manifest/analyzer": "^0.9.2",
55
+ "@custom-elements-manifest/analyzer": "^0.10.0",
56
56
  "@hatiolab/prettier-config": "^1.0.0",
57
57
  "@open-wc/eslint-config": "^12.0.3",
58
- "@open-wc/testing": "^3.1.6",
58
+ "@open-wc/testing": "^4.0.0",
59
59
  "@types/lodash-es": "^4.17.5",
60
- "@typescript-eslint/eslint-plugin": "^7.0.1",
61
- "@typescript-eslint/parser": "^7.0.1",
62
- "@web/dev-server": "^0.3.0",
60
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
61
+ "@typescript-eslint/parser": "^8.0.0",
62
+ "@web/dev-server": "^0.4.0",
63
63
  "@web/dev-server-storybook": "^2.0.1",
64
- "@web/test-runner": "^0.18.0",
65
- "concurrently": "^8.0.1",
66
- "eslint": "^8.39.0",
64
+ "@web/test-runner": "^0.19.0",
65
+ "concurrently": "^9.0.0",
66
+ "eslint": "^9.0.0",
67
67
  "eslint-config-prettier": "^9.1.0",
68
68
  "husky": "^9.0.11",
69
69
  "lint-staged": "^15.2.2",
@@ -85,5 +85,5 @@
85
85
  "prettier --write"
86
86
  ]
87
87
  },
88
- "gitHead": "f0c1979adcf64df1f543f383ae7385a56df1e57a"
88
+ "gitHead": "c4e9cc245659d050a9ffd66542083a6daad4bcb9"
89
89
  }
@@ -3,19 +3,16 @@ 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'
7
+ import { GestureEventPinch, GestureEventDoubleTap, GestureEventDrag } from '@operato/utils/gesture-mixin.js'
6
8
 
7
9
  export class GanttChartController implements ReactiveController {
8
- private host: ReactiveControllerHost & LitElement
10
+ private host: (ReactiveControllerHost & LitElement) | null
9
11
  private fromTime: Date
10
12
  private toTime: Date
11
13
  private totalDays: number
12
14
  private _timeScale?: d3.ScaleTime<number, number, never>
13
15
 
14
- private touchStartX?: number
15
- private touchStartY?: number
16
- private scrollStartX?: number
17
- private scrollStartY?: number
18
-
19
16
  private colorProvider?: (task: Task) => string
20
17
 
21
18
  public baseWidth: number = 30
@@ -34,6 +31,10 @@ export class GanttChartController implements ReactiveController {
34
31
  this.host.addController(this)
35
32
  }
36
33
 
34
+ dispose() {
35
+ this.host = null
36
+ }
37
+
37
38
  hostConnected() {
38
39
  this.updateTimeScale()
39
40
  }
@@ -57,12 +58,12 @@ export class GanttChartController implements ReactiveController {
57
58
  this.toTime = new Date(toDate)
58
59
  this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1))
59
60
  this._timeScale = undefined
60
- this.host.requestUpdate()
61
+ this.host?.requestUpdate()
61
62
  }
62
63
 
63
64
  setTasks(tasks: Task[]) {
64
65
  this.tasks = tasks
65
- this.host.requestUpdate()
66
+ this.host?.requestUpdate()
66
67
  }
67
68
 
68
69
  updateTimeScale() {
@@ -93,7 +94,7 @@ export class GanttChartController implements ReactiveController {
93
94
  .append('marker')
94
95
  .attr('id', 'arrow')
95
96
  .attr('viewBox', '0 0 10 10')
96
- .attr('refX', 10) // Adjusted refX to move the arrow tip closer to the line's end
97
+ .attr('refX', 10)
97
98
  .attr('refY', 5)
98
99
  .attr('markerWidth', 6)
99
100
  .attr('markerHeight', 6)
@@ -150,14 +151,20 @@ export class GanttChartController implements ReactiveController {
150
151
  const taskWidth = endX - startX + this.baseWidth / this.getScale()
151
152
  const taskY = index * 30 + 7.5
152
153
 
153
- const showTooltip = (event: MouseEvent) => {
154
+ const showTooltip = (event: MouseEvent | TouchEvent) => {
155
+ tooltip.hide()
156
+
157
+ const touch = 'touches' in event
158
+ const x = touch ? event.touches[0].clientX : event.clientX
159
+ const y = touch ? event.touches[0].clientY : event.clientY
160
+
154
161
  tooltip.title = task.title
155
162
  tooltip.startDate = startDate.toISOString().split('T')[0]
156
163
  tooltip.endDate = endDate.toISOString().split('T')[0]
157
164
  tooltip.progress = task.progress ?? 0
158
165
  tooltip.type = task.type
159
166
 
160
- tooltip.show(event.clientX, event.clientY)
167
+ tooltip.show(x, y)
161
168
  }
162
169
 
163
170
  const hideTooltip = () => {
@@ -185,15 +192,18 @@ export class GanttChartController implements ReactiveController {
185
192
  .attr('stroke-width', 1)
186
193
 
187
194
  taskBar
188
- .on('click', () => {
195
+ .on('click', e => {
189
196
  this.selectedTaskId = task.id
190
197
  const customEvent = new CustomEvent('task-clicked', {
191
198
  detail: { taskId: task.id },
192
199
  bubbles: true,
193
200
  composed: true
194
201
  })
195
- this.host.dispatchEvent(customEvent)
196
- this.host.requestUpdate()
202
+
203
+ showTooltip(e)
204
+
205
+ this.host?.dispatchEvent(customEvent)
206
+ this.host?.requestUpdate()
197
207
  })
198
208
  .on('mouseover', showTooltip)
199
209
  .on('mouseout', hideTooltip)
@@ -209,15 +219,18 @@ export class GanttChartController implements ReactiveController {
209
219
  .attr('fill', 'lightgreen')
210
220
 
211
221
  progressBar
212
- .on('click', () => {
222
+ .on('click', e => {
213
223
  this.selectedTaskId = task.id
214
224
  const customEvent = new CustomEvent('task-clicked', {
215
225
  detail: { taskId: task.id },
216
226
  bubbles: true,
217
227
  composed: true
218
228
  })
219
- this.host.dispatchEvent(customEvent)
220
- this.host.requestUpdate()
229
+
230
+ showTooltip(e)
231
+
232
+ this.host?.dispatchEvent(customEvent)
233
+ this.host?.requestUpdate()
221
234
  })
222
235
  .on('mouseover', showTooltip)
223
236
  .on('mouseout', hideTooltip)
@@ -256,7 +269,7 @@ export class GanttChartController implements ReactiveController {
256
269
  .attr('stroke', 'var(--md-sys-color-on-primary-container, black)')
257
270
  .attr('fill', 'none')
258
271
  .attr('stroke-width', 1)
259
- .attr('marker-end', 'url(#arrow)') // Add arrow marker
272
+ .attr('marker-end', 'url(#arrow)')
260
273
  }
261
274
  })
262
275
  }
@@ -277,6 +290,8 @@ export class GanttChartController implements ReactiveController {
277
290
  event.preventDefault()
278
291
  event.stopPropagation()
279
292
 
293
+ const { offsetHeight } = container
294
+
280
295
  const deltaModeFactor =
281
296
  event.deltaMode === WheelEvent.DOM_DELTA_LINE
282
297
  ? 16
@@ -288,7 +303,8 @@ export class GanttChartController implements ReactiveController {
288
303
 
289
304
  // 가로 스크롤 및 세로 스크롤 모두 처리
290
305
  container.scrollLeft += deltaX
291
- container.scrollTop += deltaY
306
+ // container.scrollTop += deltaY
307
+ container.scrollTop = Math.min(this.tasks.length * 30 - (offsetHeight - 40), container.scrollTop + deltaY)
292
308
 
293
309
  const customEvent = new CustomEvent('scroll', {
294
310
  detail: {
@@ -299,28 +315,78 @@ export class GanttChartController implements ReactiveController {
299
315
  composed: true
300
316
  })
301
317
 
302
- this.host.dispatchEvent(customEvent)
318
+ this.host?.dispatchEvent(customEvent)
303
319
  }
304
320
 
305
- handleTouchStartForBody(event: TouchEvent, container: HTMLDivElement) {
306
- event.stopPropagation()
321
+ handlePinchForBody = (event: GestureEventPinch) => {
322
+ const { scale } = event.detail
323
+
324
+ this.baseWidth *= scale
325
+
326
+ if (this.baseWidth > 40) {
327
+ if (this.level === 'week-day') {
328
+ this.baseWidth = 40
329
+ } else {
330
+ this.level = levelDown(this.level)
331
+ this.baseWidth = 30
332
+ }
333
+ } else if (this.baseWidth < 30) {
334
+ if (this.level === 'year-quarter') {
335
+ this.baseWidth = 30
336
+ }
337
+ }
307
338
 
308
- this.touchStartX = event.touches[0].clientX
309
- this.touchStartY = event.touches[0].clientY
339
+ if (this.baseWidth < 20) {
340
+ this.level = levelUp(this.level)
341
+ this.baseWidth = 30
342
+ }
310
343
 
311
- this.scrollStartX = container.scrollLeft
312
- this.scrollStartY = container.scrollTop
344
+ this.updateTimeScale()
345
+ this.host?.requestUpdate()
346
+
347
+ const customEvent = new CustomEvent('timescale-changed', {
348
+ detail: {
349
+ baseWidth: this.baseWidth,
350
+ level: this.level
351
+ },
352
+ bubbles: true,
353
+ composed: true
354
+ })
355
+
356
+ this.host?.dispatchEvent(customEvent)
313
357
  }
314
358
 
315
- handleTouchMoveForBody(event: TouchEvent, container: HTMLDivElement) {
316
- const touchCurrentX = event.touches[0].clientX
317
- const touchCurrentY = event.touches[0].clientY
359
+ handleDoubleTapForBody = (event: GestureEventDoubleTap) => {
360
+ const container = (this.host as any).container
361
+
362
+ container.scrollLeft = 0
363
+ container.scrollTop = 0
364
+
365
+ this.baseWidth = 30
366
+ this.level = 'week-day'
367
+
368
+ this.updateTimeScale()
369
+ this.host?.requestUpdate()
370
+
371
+ const customEvent = new CustomEvent('timescale-changed', {
372
+ detail: {
373
+ baseWidth: this.baseWidth,
374
+ level: this.level
375
+ },
376
+ bubbles: true,
377
+ composed: true
378
+ })
379
+
380
+ this.host?.dispatchEvent(customEvent)
381
+ }
318
382
 
319
- const deltaX = this.touchStartX! - touchCurrentX
320
- const deltaY = this.touchStartY! - touchCurrentY
383
+ handleDragForBody = (event: GestureEventDrag) => {
384
+ const { deltaX: dx, deltaY: dy } = event.detail
385
+ const container = (this.host as any).container
386
+ const { offsetHeight } = container
321
387
 
322
- container.scrollLeft = this.scrollStartX! + deltaX
323
- container.scrollTop = this.scrollStartY! + deltaY
388
+ container.scrollLeft -= dx
389
+ container.scrollTop = Math.min(this.tasks.length * 30 - (offsetHeight - 40), container.scrollTop - dy)
324
390
 
325
391
  const customEvent = new CustomEvent('scroll', {
326
392
  detail: {
@@ -331,6 +397,6 @@ export class GanttChartController implements ReactiveController {
331
397
  composed: true
332
398
  })
333
399
 
334
- this.host.dispatchEvent(customEvent)
400
+ this.host?.dispatchEvent(customEvent)
335
401
  }
336
402
  }