@operato/gantt 8.0.0-alpha.10 → 8.0.0-alpha.25

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 CHANGED
@@ -3,6 +3,15 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [8.0.0-alpha.25](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.24...v8.0.0-alpha.25) (2024-10-06)
7
+
8
+
9
+ ### :bug: Bug Fix
10
+
11
+ * ox-gantt ([a05370d](https://github.com/hatiolab/operato/commit/a05370d6bc3c9f7d35819f21b1b19b7c40c8e3fe))
12
+
13
+
14
+
6
15
  ## [8.0.0-alpha.10](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.9...v8.0.0-alpha.10) (2024-09-18)
7
16
 
8
17
 
@@ -8,10 +8,13 @@ export declare class GanttChartController implements ReactiveController {
8
8
  private toTime;
9
9
  private totalDays;
10
10
  private _timeScale?;
11
- private touchStartX?;
12
- private touchStartY?;
13
- private scrollStartX?;
14
- private scrollStartY?;
11
+ private touchStartX;
12
+ private touchStartY;
13
+ private scrollStartX;
14
+ private scrollStartY;
15
+ private lastTouchDistance?;
16
+ private draggingThreshold;
17
+ private dragging;
15
18
  private colorProvider?;
16
19
  baseWidth: number;
17
20
  level: TimeScale;
@@ -19,6 +22,7 @@ export declare class GanttChartController implements ReactiveController {
19
22
  tasks: Task[];
20
23
  extendGridLines: boolean;
21
24
  constructor(host: ReactiveControllerHost & LitElement, fromDate: string, toDate: string, axisScale: TimeScale);
25
+ dispose(): void;
22
26
  hostConnected(): void;
23
27
  setColorProvider(colorProvider: (task: Task) => string): void;
24
28
  get timeScale(): d3.ScaleTime<number, number, never>;
@@ -31,6 +35,8 @@ export declare class GanttChartController implements ReactiveController {
31
35
  drawBody(svgBody: SVGElement, tooltip: OxTaskTooltip): void;
32
36
  getTaskColor(tags: TaskTag[]): string;
33
37
  handleWheelForBody(event: WheelEvent, container: HTMLDivElement): void;
34
- handleTouchStartForBody(event: TouchEvent, container: HTMLDivElement): void;
35
- handleTouchMoveForBody(event: TouchEvent, container: HTMLDivElement): void;
38
+ handleTouchStartForBody(event: MouseEvent | TouchEvent, container: HTMLDivElement): void;
39
+ handleTouchMoveForBody(event: MouseEvent | TouchEvent, container: HTMLDivElement): void;
40
+ handleTouchEndForBody(event: MouseEvent | TouchEvent): void;
41
+ getTouchDistance(touches: TouchList): number;
36
42
  }
@@ -1,7 +1,14 @@
1
1
  import * as d3 from 'd3';
2
2
  import { drawTimeScaleHeader, getScale, getChartWidth } from './draw-time-scale-header';
3
+ import { levelDown, levelUp } from './utils';
3
4
  export class GanttChartController {
4
5
  constructor(host, fromDate, toDate, axisScale) {
6
+ this.touchStartX = null;
7
+ this.touchStartY = null;
8
+ this.scrollStartX = null;
9
+ this.scrollStartY = null;
10
+ this.draggingThreshold = 20;
11
+ this.dragging = false;
5
12
  this.baseWidth = 30;
6
13
  this.tasks = [];
7
14
  this.extendGridLines = false;
@@ -12,6 +19,9 @@ export class GanttChartController {
12
19
  this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1));
13
20
  this.host.addController(this);
14
21
  }
22
+ dispose() {
23
+ this.host = null;
24
+ }
15
25
  hostConnected() {
16
26
  this.updateTimeScale();
17
27
  }
@@ -32,11 +42,11 @@ export class GanttChartController {
32
42
  this.toTime = new Date(toDate);
33
43
  this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1));
34
44
  this._timeScale = undefined;
35
- this.host.requestUpdate();
45
+ this.host?.requestUpdate();
36
46
  }
37
47
  setTasks(tasks) {
38
48
  this.tasks = tasks;
39
- this.host.requestUpdate();
49
+ this.host?.requestUpdate();
40
50
  }
41
51
  updateTimeScale() {
42
52
  this.timeScale.range([0, this.getChartWidth()]);
@@ -60,7 +70,7 @@ export class GanttChartController {
60
70
  .append('marker')
61
71
  .attr('id', 'arrow')
62
72
  .attr('viewBox', '0 0 10 10')
63
- .attr('refX', 10) // Adjusted refX to move the arrow tip closer to the line's end
73
+ .attr('refX', 10)
64
74
  .attr('refY', 5)
65
75
  .attr('markerWidth', 6)
66
76
  .attr('markerHeight', 6)
@@ -114,12 +124,16 @@ export class GanttChartController {
114
124
  const taskWidth = endX - startX + this.baseWidth / this.getScale();
115
125
  const taskY = index * 30 + 7.5;
116
126
  const showTooltip = (event) => {
127
+ tooltip.hide();
128
+ const touch = 'touches' in event;
129
+ const x = touch ? event.touches[0].clientX : event.clientX;
130
+ const y = touch ? event.touches[0].clientY : event.clientY;
117
131
  tooltip.title = task.title;
118
132
  tooltip.startDate = startDate.toISOString().split('T')[0];
119
133
  tooltip.endDate = endDate.toISOString().split('T')[0];
120
134
  tooltip.progress = task.progress ?? 0;
121
135
  tooltip.type = task.type;
122
- tooltip.show(event.clientX, event.clientY);
136
+ tooltip.show(x, y);
123
137
  };
124
138
  const hideTooltip = () => {
125
139
  tooltip.hide();
@@ -150,8 +164,19 @@ export class GanttChartController {
150
164
  bubbles: true,
151
165
  composed: true
152
166
  });
153
- this.host.dispatchEvent(customEvent);
154
- this.host.requestUpdate();
167
+ this.host?.dispatchEvent(customEvent);
168
+ this.host?.requestUpdate();
169
+ })
170
+ .on('touchstart', e => {
171
+ this.selectedTaskId = task.id;
172
+ const customEvent = new CustomEvent('task-clicked', {
173
+ detail: { taskId: task.id },
174
+ bubbles: true,
175
+ composed: true
176
+ });
177
+ showTooltip(e);
178
+ this.host?.dispatchEvent(customEvent);
179
+ this.host?.requestUpdate();
155
180
  })
156
181
  .on('mouseover', showTooltip)
157
182
  .on('mouseout', hideTooltip);
@@ -172,8 +197,19 @@ export class GanttChartController {
172
197
  bubbles: true,
173
198
  composed: true
174
199
  });
175
- this.host.dispatchEvent(customEvent);
176
- this.host.requestUpdate();
200
+ this.host?.dispatchEvent(customEvent);
201
+ this.host?.requestUpdate();
202
+ })
203
+ .on('touchstart', e => {
204
+ this.selectedTaskId = task.id;
205
+ const customEvent = new CustomEvent('task-clicked', {
206
+ detail: { taskId: task.id },
207
+ bubbles: true,
208
+ composed: true
209
+ });
210
+ showTooltip(e);
211
+ this.host?.dispatchEvent(customEvent);
212
+ this.host?.requestUpdate();
177
213
  })
178
214
  .on('mouseover', showTooltip)
179
215
  .on('mouseout', hideTooltip);
@@ -204,7 +240,7 @@ export class GanttChartController {
204
240
  .attr('stroke', 'var(--md-sys-color-on-primary-container, black)')
205
241
  .attr('fill', 'none')
206
242
  .attr('stroke-width', 1)
207
- .attr('marker-end', 'url(#arrow)'); // Add arrow marker
243
+ .attr('marker-end', 'url(#arrow)');
208
244
  }
209
245
  });
210
246
  }
@@ -243,31 +279,115 @@ export class GanttChartController {
243
279
  bubbles: true,
244
280
  composed: true
245
281
  });
246
- this.host.dispatchEvent(customEvent);
282
+ this.host?.dispatchEvent(customEvent);
247
283
  }
248
284
  handleTouchStartForBody(event, container) {
285
+ event.preventDefault();
249
286
  event.stopPropagation();
250
- this.touchStartX = event.touches[0].clientX;
251
- this.touchStartY = event.touches[0].clientY;
252
- this.scrollStartX = container.scrollLeft;
253
- this.scrollStartY = container.scrollTop;
287
+ const touch = 'touches' in event;
288
+ const x = touch ? event.touches[0].clientX : event.clientX;
289
+ const y = touch ? event.touches[0].clientY : event.clientY;
290
+ this.dragging = false;
291
+ if (touch && event.touches.length === 2) {
292
+ this.lastTouchDistance = this.getTouchDistance(event.touches);
293
+ }
294
+ else {
295
+ this.touchStartX = x;
296
+ this.touchStartY = y;
297
+ this.scrollStartX = container.scrollLeft;
298
+ this.scrollStartY = container.scrollTop;
299
+ }
254
300
  }
255
301
  handleTouchMoveForBody(event, container) {
256
- const touchCurrentX = event.touches[0].clientX;
257
- const touchCurrentY = event.touches[0].clientY;
258
- const deltaX = this.touchStartX - touchCurrentX;
259
- const deltaY = this.touchStartY - touchCurrentY;
260
- container.scrollLeft = this.scrollStartX + deltaX;
261
- container.scrollTop = this.scrollStartY + deltaY;
262
- const customEvent = new CustomEvent('scroll', {
263
- detail: {
264
- scrollLeft: container.scrollLeft,
265
- scrollTop: container.scrollTop
266
- },
267
- bubbles: true,
268
- composed: true
269
- });
270
- this.host.dispatchEvent(customEvent);
302
+ event.preventDefault();
303
+ event.stopPropagation();
304
+ const touch = 'touches' in event;
305
+ const x = touch ? event.touches[0].clientX : event.clientX;
306
+ const y = touch ? event.touches[0].clientY : event.clientY;
307
+ if (touch && event.touches.length > 1 && this.lastTouchDistance !== null) {
308
+ const currentDistance = this.getTouchDistance(event.touches);
309
+ const zoomSensitivity = 0.3;
310
+ let zoomFactor = currentDistance / this.lastTouchDistance;
311
+ zoomFactor = 1 + (zoomFactor - 1) * zoomSensitivity;
312
+ this.baseWidth *= zoomFactor;
313
+ if (this.baseWidth > 40) {
314
+ if (this.level === 'week-day') {
315
+ this.baseWidth = 40;
316
+ }
317
+ else {
318
+ this.level = levelDown(this.level);
319
+ this.baseWidth = 30;
320
+ }
321
+ }
322
+ else if (this.baseWidth < 30) {
323
+ if (this.level === 'year-quarter') {
324
+ this.baseWidth = 30;
325
+ }
326
+ }
327
+ if (this.baseWidth < 20) {
328
+ this.level = levelUp(this.level);
329
+ this.baseWidth = 30;
330
+ }
331
+ this.lastTouchDistance = currentDistance;
332
+ this.updateTimeScale();
333
+ this.host?.requestUpdate();
334
+ const customEvent = new CustomEvent('timescale-changed', {
335
+ detail: {
336
+ baseWidth: this.baseWidth,
337
+ level: this.level
338
+ },
339
+ bubbles: true,
340
+ composed: true
341
+ });
342
+ this.host?.dispatchEvent(customEvent);
343
+ }
344
+ else if (this.touchStartX !== null) {
345
+ const dx = this.touchStartX - x;
346
+ const dy = this.touchStartY - y;
347
+ if (!this.dragging) {
348
+ if (Math.sqrt(dx * dx + dy * dy) > this.draggingThreshold) {
349
+ this.dragging = true;
350
+ }
351
+ else {
352
+ return;
353
+ }
354
+ }
355
+ container.scrollLeft = this.scrollStartX + dx;
356
+ container.scrollTop = this.scrollStartY + dy;
357
+ const customEvent = new CustomEvent('scroll', {
358
+ detail: {
359
+ scrollLeft: container.scrollLeft,
360
+ scrollTop: container.scrollTop
361
+ },
362
+ bubbles: true,
363
+ composed: true
364
+ });
365
+ this.host?.dispatchEvent(customEvent);
366
+ }
367
+ }
368
+ handleTouchEndForBody(event) {
369
+ event.preventDefault();
370
+ event.stopPropagation();
371
+ if ('touches' in event && event.touches.length > 1) {
372
+ this.lastTouchDistance = null;
373
+ }
374
+ else if (this.touchStartX !== null) {
375
+ if (!this.dragging) {
376
+ this.host?.dispatchEvent(new CustomEvent('date-range-cleared', {
377
+ bubbles: true,
378
+ composed: true
379
+ }));
380
+ }
381
+ this.touchStartX = null;
382
+ this.touchStartY = null;
383
+ this.scrollStartX = null;
384
+ this.scrollStartY = null;
385
+ }
386
+ }
387
+ getTouchDistance(touches) {
388
+ const dx = touches[0].clientX - touches[1].clientX;
389
+ const dy = touches[0].clientY - touches[1].clientY;
390
+ return Math.sqrt(dx * dx + dy * dy);
271
391
  }
272
392
  }
273
393
  //# sourceMappingURL=gantt-chart-controller.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gantt-chart-controller.js","sourceRoot":"","sources":["../../src/gantt-chart-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, ReactiveController, ReactiveControllerHost } from 'lit'\nimport * as d3 from 'd3'\nimport { TimeScale, Task, TaskTag } from './types'\nimport { OxTaskTooltip } from './ox-task-tooltip'\nimport { drawTimeScaleHeader, getScale, getChartWidth } from './draw-time-scale-header'\n\nexport class GanttChartController implements ReactiveController {\n private host: ReactiveControllerHost & LitElement\n private fromTime: Date\n private toTime: Date\n private totalDays: number\n private _timeScale?: d3.ScaleTime<number, number, never>\n\n private touchStartX?: number\n private touchStartY?: number\n private scrollStartX?: number\n private scrollStartY?: number\n\n private colorProvider?: (task: Task) => string\n\n public baseWidth: number = 30\n public level: TimeScale\n public selectedTaskId?: string\n\n public tasks: Task[] = []\n public extendGridLines: boolean = false\n\n constructor(host: ReactiveControllerHost & LitElement, fromDate: string, toDate: string, axisScale: TimeScale) {\n this.host = host\n this.fromTime = new Date(fromDate)\n this.toTime = new Date(toDate)\n this.level = axisScale\n this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1))\n this.host.addController(this)\n }\n\n hostConnected() {\n this.updateTimeScale()\n }\n\n setColorProvider(colorProvider: (task: Task) => string) {\n this.colorProvider = colorProvider\n }\n\n get timeScale() {\n if (!this._timeScale) {\n this._timeScale = d3\n .scaleTime()\n .domain([d3.timeDay.floor(this.fromTime), d3.timeDay.offset(this.toTime, 1)])\n .range([0, this.getChartWidth()])\n }\n return this._timeScale\n }\n\n updateRange(fromDate: string, toDate: string) {\n this.fromTime = new Date(fromDate)\n this.toTime = new Date(toDate)\n this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1))\n this._timeScale = undefined\n this.host.requestUpdate()\n }\n\n setTasks(tasks: Task[]) {\n this.tasks = tasks\n this.host.requestUpdate()\n }\n\n updateTimeScale() {\n this.timeScale.range([0, this.getChartWidth()])\n }\n\n getScale() {\n return getScale(this.level)\n }\n\n getChartWidth() {\n return getChartWidth(this.fromTime, this.toTime, this.baseWidth, this.level)\n }\n\n drawAxes(svgHeader: SVGElement) {\n drawTimeScaleHeader(svgHeader, this.timeScale, this.fromTime, this.toTime, this.baseWidth, this.level)\n }\n\n drawBody(svgBody: SVGElement, tooltip: OxTaskTooltip) {\n const body = d3.select(svgBody)\n\n body.selectAll('*').remove()\n body.attr('width', this.getChartWidth())\n\n // Define the arrow marker\n const defs = body.append('defs')\n defs\n .append('marker')\n .attr('id', 'arrow')\n .attr('viewBox', '0 0 10 10')\n .attr('refX', 10) // Adjusted refX to move the arrow tip closer to the line's end\n .attr('refY', 5)\n .attr('markerWidth', 6)\n .attr('markerHeight', 6)\n .attr('orient', 'auto-start-reverse')\n .append('path')\n .attr('d', 'M 0 0 L 10 5 L 0 10 z')\n .attr('fill', 'var(--md-sys-color-on-primary-container, black)')\n\n if (this.extendGridLines) {\n const addGridLines = (ticks: Date[]) => {\n ticks.forEach(tick => {\n const startX = this.timeScale(tick)\n body\n .append('line')\n .attr('x1', startX)\n .attr('x2', startX)\n .attr('y1', 0)\n .attr('y2', Number(svgBody.getBoundingClientRect().height) || 0)\n .attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')\n .attr('stroke-width', 1)\n })\n }\n\n if (this.level === 'week-day') {\n const dayTicks = d3.timeDay.every(1)!.range(d3.timeDay.floor(this.fromTime), d3.timeDay.offset(this.toTime, 1))\n addGridLines(dayTicks)\n } else if (this.level === 'quarter-week') {\n const weekTicks = d3.timeWeek\n .every(1)!\n .range(d3.timeWeek.floor(this.fromTime), d3.timeWeek.offset(this.toTime, 1))\n addGridLines(weekTicks)\n } else if (this.level === 'year-month') {\n const monthTicks = d3.timeMonth\n .every(1)!\n .range(d3.timeMonth.floor(this.fromTime), d3.timeMonth.offset(this.toTime, 1))\n addGridLines(monthTicks)\n } else if (this.level === 'year-quarter') {\n const quarterTicks = d3.timeMonth\n .every(3)!\n .range(d3.timeMonth.floor(this.fromTime), d3.timeMonth.offset(this.toTime, 3))\n addGridLines(quarterTicks)\n }\n }\n\n const taskPositions: { [key: string]: { x: number; y: number; width: number } } = {}\n\n this.tasks.forEach((task, index) => {\n const startDate = new Date(task.startDate)\n const endDate = new Date(task.endDate)\n\n const startX = this.timeScale(d3.timeDay.floor(d3.min([startDate, endDate])!))\n const endX = this.timeScale(d3.timeDay.offset(d3.timeDay.ceil(d3.max([startDate, endDate])!), -1))\n\n const taskWidth = endX - startX + this.baseWidth / this.getScale()\n const taskY = index * 30 + 7.5\n\n const showTooltip = (event: MouseEvent) => {\n tooltip.title = task.title\n tooltip.startDate = startDate.toISOString().split('T')[0]\n tooltip.endDate = endDate.toISOString().split('T')[0]\n tooltip.progress = task.progress ?? 0\n tooltip.type = task.type\n\n tooltip.show(event.clientX, event.clientY)\n }\n\n const hideTooltip = () => {\n tooltip.hide()\n }\n\n if (this.selectedTaskId === task.id) {\n body\n .append('rect')\n .attr('x', 0)\n .attr('y', taskY - 7.5)\n .attr('width', this.getChartWidth())\n .attr('height', 30)\n .attr('fill', 'var(--ox-gantt-selected-row-background-color, var(--md-sys-color-surface-variant))')\n }\n\n const taskBar = body\n .append('rect')\n .attr('x', startX)\n .attr('y', taskY)\n .attr('width', taskWidth)\n .attr('height', 15)\n .attr('fill', this.colorProvider ? this.colorProvider(task) : 'gray')\n .attr('stroke', 'black')\n .attr('stroke-width', 1)\n\n taskBar\n .on('click', () => {\n this.selectedTaskId = task.id\n const customEvent = new CustomEvent('task-clicked', {\n detail: { taskId: task.id },\n bubbles: true,\n composed: true\n })\n this.host.dispatchEvent(customEvent)\n this.host.requestUpdate()\n })\n .on('mouseover', showTooltip)\n .on('mouseout', hideTooltip)\n\n if (task.progress !== undefined) {\n const progressWidth = taskWidth * (task.progress / 100)\n const progressBar = body\n .append('rect')\n .attr('x', startX)\n .attr('y', taskY + 7.5 - 3.75)\n .attr('width', progressWidth)\n .attr('height', 7.5)\n .attr('fill', 'lightgreen')\n\n progressBar\n .on('click', () => {\n this.selectedTaskId = task.id\n const customEvent = new CustomEvent('task-clicked', {\n detail: { taskId: task.id },\n bubbles: true,\n composed: true\n })\n this.host.dispatchEvent(customEvent)\n this.host.requestUpdate()\n })\n .on('mouseover', showTooltip)\n .on('mouseout', hideTooltip)\n }\n\n taskPositions[task.id] = { x: endX + this.baseWidth / this.getScale(), y: taskY + 7.5, width: taskWidth }\n })\n\n this.tasks.forEach(task => {\n if (task.dependsOn && taskPositions[task.dependsOn]) {\n const prevTask = taskPositions[task.dependsOn]\n const currTask = taskPositions[task.id]\n\n body\n .append('path')\n .attr(\n 'd',\n `\n M${prevTask.x},${prevTask.y}\n L${prevTask.x + 10},${prevTask.y}\n ${\n prevTask.x + 10 < currTask.x - 10 - currTask.width\n ? `\n L${(prevTask.x + currTask.x - currTask.width) / 2},${prevTask.y}\n L${(prevTask.x + currTask.x - currTask.width) / 2},${currTask.y}\n `\n : `\n L${prevTask.x + 10},${(prevTask.y + currTask.y) / 2}\n L${currTask.x - 10 - currTask.width},${(prevTask.y + currTask.y) / 2}\n `\n }\n L${currTask.x - 10 - currTask.width},${currTask.y}\n L${currTask.x - currTask.width},${currTask.y}\n `\n )\n .attr('stroke', 'var(--md-sys-color-on-primary-container, black)')\n .attr('fill', 'none')\n .attr('stroke-width', 1)\n .attr('marker-end', 'url(#arrow)') // Add arrow marker\n }\n })\n }\n\n getTaskColor(tags: TaskTag[]): string {\n if (tags.includes('critical')) {\n return 'red'\n } else if (tags.includes('milestone')) {\n return 'blue'\n } else if (tags.includes('done')) {\n return 'green'\n } else {\n return 'grey'\n }\n }\n\n handleWheelForBody(event: WheelEvent, container: HTMLDivElement) {\n event.preventDefault()\n event.stopPropagation()\n\n const deltaModeFactor =\n event.deltaMode === WheelEvent.DOM_DELTA_LINE\n ? 16\n : event.deltaMode === WheelEvent.DOM_DELTA_PAGE\n ? container.clientHeight\n : 1\n const deltaX = event.deltaX * deltaModeFactor\n const deltaY = event.deltaY * deltaModeFactor\n\n // 가로 스크롤 및 세로 스크롤 모두 처리\n container.scrollLeft += deltaX\n container.scrollTop += deltaY\n\n const customEvent = new CustomEvent('scroll', {\n detail: {\n scrollLeft: container.scrollLeft,\n scrollTop: container.scrollTop\n },\n bubbles: true,\n composed: true\n })\n\n this.host.dispatchEvent(customEvent)\n }\n\n handleTouchStartForBody(event: TouchEvent, container: HTMLDivElement) {\n event.stopPropagation()\n\n this.touchStartX = event.touches[0].clientX\n this.touchStartY = event.touches[0].clientY\n\n this.scrollStartX = container.scrollLeft\n this.scrollStartY = container.scrollTop\n }\n\n handleTouchMoveForBody(event: TouchEvent, container: HTMLDivElement) {\n const touchCurrentX = event.touches[0].clientX\n const touchCurrentY = event.touches[0].clientY\n\n const deltaX = this.touchStartX! - touchCurrentX\n const deltaY = this.touchStartY! - touchCurrentY\n\n container.scrollLeft = this.scrollStartX! + deltaX\n container.scrollTop = this.scrollStartY! + deltaY\n\n const customEvent = new CustomEvent('scroll', {\n detail: {\n scrollLeft: container.scrollLeft,\n scrollTop: container.scrollTop\n },\n bubbles: true,\n composed: true\n })\n\n this.host.dispatchEvent(customEvent)\n }\n}\n"]}
1
+ {"version":3,"file":"gantt-chart-controller.js","sourceRoot":"","sources":["../../src/gantt-chart-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, ReactiveController, ReactiveControllerHost } from 'lit'\nimport * as d3 from 'd3'\nimport { TimeScale, Task, TaskTag } from './types'\nimport { OxTaskTooltip } from './ox-task-tooltip'\nimport { drawTimeScaleHeader, getScale, getChartWidth } from './draw-time-scale-header'\nimport { levelDown, levelUp } from './utils'\n\nexport class GanttChartController implements ReactiveController {\n private host: (ReactiveControllerHost & LitElement) | null\n private fromTime: Date\n private toTime: Date\n private totalDays: number\n private _timeScale?: d3.ScaleTime<number, number, never>\n\n private touchStartX: number | null = null\n private touchStartY: number | null = null\n private scrollStartX: number | null = null\n private scrollStartY: number | null = null\n private lastTouchDistance?: number | null\n private draggingThreshold: number = 20\n private dragging: boolean = false\n\n private colorProvider?: (task: Task) => string\n\n public baseWidth: number = 30\n public level: TimeScale\n public selectedTaskId?: string\n\n public tasks: Task[] = []\n public extendGridLines: boolean = false\n\n constructor(host: ReactiveControllerHost & LitElement, fromDate: string, toDate: string, axisScale: TimeScale) {\n this.host = host\n this.fromTime = new Date(fromDate)\n this.toTime = new Date(toDate)\n this.level = axisScale\n this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1))\n this.host.addController(this)\n }\n\n dispose() {\n this.host = null\n }\n\n hostConnected() {\n this.updateTimeScale()\n }\n\n setColorProvider(colorProvider: (task: Task) => string) {\n this.colorProvider = colorProvider\n }\n\n get timeScale() {\n if (!this._timeScale) {\n this._timeScale = d3\n .scaleTime()\n .domain([d3.timeDay.floor(this.fromTime), d3.timeDay.offset(this.toTime, 1)])\n .range([0, this.getChartWidth()])\n }\n return this._timeScale\n }\n\n updateRange(fromDate: string, toDate: string) {\n this.fromTime = new Date(fromDate)\n this.toTime = new Date(toDate)\n this.totalDays = d3.timeDay.count(this.fromTime, d3.timeDay.offset(this.toTime, 1))\n this._timeScale = undefined\n this.host?.requestUpdate()\n }\n\n setTasks(tasks: Task[]) {\n this.tasks = tasks\n this.host?.requestUpdate()\n }\n\n updateTimeScale() {\n this.timeScale.range([0, this.getChartWidth()])\n }\n\n getScale() {\n return getScale(this.level)\n }\n\n getChartWidth() {\n return getChartWidth(this.fromTime, this.toTime, this.baseWidth, this.level)\n }\n\n drawAxes(svgHeader: SVGElement) {\n drawTimeScaleHeader(svgHeader, this.timeScale, this.fromTime, this.toTime, this.baseWidth, this.level)\n }\n\n drawBody(svgBody: SVGElement, tooltip: OxTaskTooltip) {\n const body = d3.select(svgBody)\n\n body.selectAll('*').remove()\n body.attr('width', this.getChartWidth())\n\n // Define the arrow marker\n const defs = body.append('defs')\n defs\n .append('marker')\n .attr('id', 'arrow')\n .attr('viewBox', '0 0 10 10')\n .attr('refX', 10)\n .attr('refY', 5)\n .attr('markerWidth', 6)\n .attr('markerHeight', 6)\n .attr('orient', 'auto-start-reverse')\n .append('path')\n .attr('d', 'M 0 0 L 10 5 L 0 10 z')\n .attr('fill', 'var(--md-sys-color-on-primary-container, black)')\n\n if (this.extendGridLines) {\n const addGridLines = (ticks: Date[]) => {\n ticks.forEach(tick => {\n const startX = this.timeScale(tick)\n body\n .append('line')\n .attr('x1', startX)\n .attr('x2', startX)\n .attr('y1', 0)\n .attr('y2', Number(svgBody.getBoundingClientRect().height) || 0)\n .attr('stroke', 'var(--ox-gantt-color-gridlines, var(--md-sys-color-outline))')\n .attr('stroke-width', 1)\n })\n }\n\n if (this.level === 'week-day') {\n const dayTicks = d3.timeDay.every(1)!.range(d3.timeDay.floor(this.fromTime), d3.timeDay.offset(this.toTime, 1))\n addGridLines(dayTicks)\n } else if (this.level === 'quarter-week') {\n const weekTicks = d3.timeWeek\n .every(1)!\n .range(d3.timeWeek.floor(this.fromTime), d3.timeWeek.offset(this.toTime, 1))\n addGridLines(weekTicks)\n } else if (this.level === 'year-month') {\n const monthTicks = d3.timeMonth\n .every(1)!\n .range(d3.timeMonth.floor(this.fromTime), d3.timeMonth.offset(this.toTime, 1))\n addGridLines(monthTicks)\n } else if (this.level === 'year-quarter') {\n const quarterTicks = d3.timeMonth\n .every(3)!\n .range(d3.timeMonth.floor(this.fromTime), d3.timeMonth.offset(this.toTime, 3))\n addGridLines(quarterTicks)\n }\n }\n\n const taskPositions: { [key: string]: { x: number; y: number; width: number } } = {}\n\n this.tasks.forEach((task, index) => {\n const startDate = new Date(task.startDate)\n const endDate = new Date(task.endDate)\n\n const startX = this.timeScale(d3.timeDay.floor(d3.min([startDate, endDate])!))\n const endX = this.timeScale(d3.timeDay.offset(d3.timeDay.ceil(d3.max([startDate, endDate])!), -1))\n\n const taskWidth = endX - startX + this.baseWidth / this.getScale()\n const taskY = index * 30 + 7.5\n\n const showTooltip = (event: MouseEvent | TouchEvent) => {\n tooltip.hide()\n\n const touch = 'touches' in event\n const x = touch ? event.touches[0].clientX : event.clientX\n const y = touch ? event.touches[0].clientY : event.clientY\n\n tooltip.title = task.title\n tooltip.startDate = startDate.toISOString().split('T')[0]\n tooltip.endDate = endDate.toISOString().split('T')[0]\n tooltip.progress = task.progress ?? 0\n tooltip.type = task.type\n\n tooltip.show(x, y)\n }\n\n const hideTooltip = () => {\n tooltip.hide()\n }\n\n if (this.selectedTaskId === task.id) {\n body\n .append('rect')\n .attr('x', 0)\n .attr('y', taskY - 7.5)\n .attr('width', this.getChartWidth())\n .attr('height', 30)\n .attr('fill', 'var(--ox-gantt-selected-row-background-color, var(--md-sys-color-surface-variant))')\n }\n\n const taskBar = body\n .append('rect')\n .attr('x', startX)\n .attr('y', taskY)\n .attr('width', taskWidth)\n .attr('height', 15)\n .attr('fill', this.colorProvider ? this.colorProvider(task) : 'gray')\n .attr('stroke', 'black')\n .attr('stroke-width', 1)\n\n taskBar\n .on('click', () => {\n this.selectedTaskId = task.id\n const customEvent = new CustomEvent('task-clicked', {\n detail: { taskId: task.id },\n bubbles: true,\n composed: true\n })\n this.host?.dispatchEvent(customEvent)\n this.host?.requestUpdate()\n })\n .on('touchstart', e => {\n this.selectedTaskId = task.id\n const customEvent = new CustomEvent('task-clicked', {\n detail: { taskId: task.id },\n bubbles: true,\n composed: true\n })\n\n showTooltip(e)\n\n this.host?.dispatchEvent(customEvent)\n this.host?.requestUpdate()\n })\n .on('mouseover', showTooltip)\n .on('mouseout', hideTooltip)\n\n if (task.progress !== undefined) {\n const progressWidth = taskWidth * (task.progress / 100)\n const progressBar = body\n .append('rect')\n .attr('x', startX)\n .attr('y', taskY + 7.5 - 3.75)\n .attr('width', progressWidth)\n .attr('height', 7.5)\n .attr('fill', 'lightgreen')\n\n progressBar\n .on('click', () => {\n this.selectedTaskId = task.id\n const customEvent = new CustomEvent('task-clicked', {\n detail: { taskId: task.id },\n bubbles: true,\n composed: true\n })\n this.host?.dispatchEvent(customEvent)\n this.host?.requestUpdate()\n })\n .on('touchstart', e => {\n this.selectedTaskId = task.id\n const customEvent = new CustomEvent('task-clicked', {\n detail: { taskId: task.id },\n bubbles: true,\n composed: true\n })\n\n showTooltip(e)\n\n this.host?.dispatchEvent(customEvent)\n this.host?.requestUpdate()\n })\n .on('mouseover', showTooltip)\n .on('mouseout', hideTooltip)\n }\n\n taskPositions[task.id] = { x: endX + this.baseWidth / this.getScale(), y: taskY + 7.5, width: taskWidth }\n })\n\n this.tasks.forEach(task => {\n if (task.dependsOn && taskPositions[task.dependsOn]) {\n const prevTask = taskPositions[task.dependsOn]\n const currTask = taskPositions[task.id]\n\n body\n .append('path')\n .attr(\n 'd',\n `\n M${prevTask.x},${prevTask.y}\n L${prevTask.x + 10},${prevTask.y}\n ${\n prevTask.x + 10 < currTask.x - 10 - currTask.width\n ? `\n L${(prevTask.x + currTask.x - currTask.width) / 2},${prevTask.y}\n L${(prevTask.x + currTask.x - currTask.width) / 2},${currTask.y}\n `\n : `\n L${prevTask.x + 10},${(prevTask.y + currTask.y) / 2}\n L${currTask.x - 10 - currTask.width},${(prevTask.y + currTask.y) / 2}\n `\n }\n L${currTask.x - 10 - currTask.width},${currTask.y}\n L${currTask.x - currTask.width},${currTask.y}\n `\n )\n .attr('stroke', 'var(--md-sys-color-on-primary-container, black)')\n .attr('fill', 'none')\n .attr('stroke-width', 1)\n .attr('marker-end', 'url(#arrow)')\n }\n })\n }\n\n getTaskColor(tags: TaskTag[]): string {\n if (tags.includes('critical')) {\n return 'red'\n } else if (tags.includes('milestone')) {\n return 'blue'\n } else if (tags.includes('done')) {\n return 'green'\n } else {\n return 'grey'\n }\n }\n\n handleWheelForBody(event: WheelEvent, container: HTMLDivElement) {\n event.preventDefault()\n event.stopPropagation()\n\n const deltaModeFactor =\n event.deltaMode === WheelEvent.DOM_DELTA_LINE\n ? 16\n : event.deltaMode === WheelEvent.DOM_DELTA_PAGE\n ? container.clientHeight\n : 1\n const deltaX = event.deltaX * deltaModeFactor\n const deltaY = event.deltaY * deltaModeFactor\n\n // 가로 스크롤 및 세로 스크롤 모두 처리\n container.scrollLeft += deltaX\n container.scrollTop += deltaY\n\n const customEvent = new CustomEvent('scroll', {\n detail: {\n scrollLeft: container.scrollLeft,\n scrollTop: container.scrollTop\n },\n bubbles: true,\n composed: true\n })\n\n this.host?.dispatchEvent(customEvent)\n }\n\n handleTouchStartForBody(event: MouseEvent | TouchEvent, container: HTMLDivElement) {\n event.preventDefault()\n event.stopPropagation()\n\n const touch = 'touches' in event\n const x = touch ? event.touches[0].clientX : event.clientX\n const y = touch ? event.touches[0].clientY : event.clientY\n\n this.dragging = false\n\n if (touch && event.touches.length === 2) {\n this.lastTouchDistance = this.getTouchDistance(event.touches)\n } else {\n this.touchStartX = x\n this.touchStartY = y\n\n this.scrollStartX = container.scrollLeft\n this.scrollStartY = container.scrollTop\n }\n }\n\n handleTouchMoveForBody(event: MouseEvent | TouchEvent, container: HTMLDivElement) {\n event.preventDefault()\n event.stopPropagation()\n\n const touch = 'touches' in event\n const x = touch ? event.touches[0].clientX : event.clientX\n const y = touch ? event.touches[0].clientY : event.clientY\n\n if (touch && event.touches.length > 1 && this.lastTouchDistance !== null) {\n const currentDistance = this.getTouchDistance(event.touches)\n\n const zoomSensitivity = 0.3\n let zoomFactor = currentDistance / this.lastTouchDistance!\n zoomFactor = 1 + (zoomFactor - 1) * zoomSensitivity\n\n this.baseWidth *= zoomFactor\n\n if (this.baseWidth > 40) {\n if (this.level === 'week-day') {\n this.baseWidth = 40\n } else {\n this.level = levelDown(this.level)\n this.baseWidth = 30\n }\n } else if (this.baseWidth < 30) {\n if (this.level === 'year-quarter') {\n this.baseWidth = 30\n }\n }\n\n if (this.baseWidth < 20) {\n this.level = levelUp(this.level)\n this.baseWidth = 30\n }\n\n this.lastTouchDistance = currentDistance\n this.updateTimeScale()\n this.host?.requestUpdate()\n\n const customEvent = new CustomEvent('timescale-changed', {\n detail: {\n baseWidth: this.baseWidth,\n level: this.level\n },\n bubbles: true,\n composed: true\n })\n this.host?.dispatchEvent(customEvent)\n } else if (this.touchStartX !== null) {\n const dx = this.touchStartX! - x\n const dy = this.touchStartY! - y\n\n if (!this.dragging) {\n if (Math.sqrt(dx * dx + dy * dy) > this.draggingThreshold) {\n this.dragging = true\n } else {\n return\n }\n }\n\n container.scrollLeft = this.scrollStartX! + dx\n container.scrollTop = this.scrollStartY! + dy\n\n const customEvent = new CustomEvent('scroll', {\n detail: {\n scrollLeft: container.scrollLeft,\n scrollTop: container.scrollTop\n },\n bubbles: true,\n composed: true\n })\n\n this.host?.dispatchEvent(customEvent)\n }\n }\n\n handleTouchEndForBody(event: MouseEvent | TouchEvent) {\n event.preventDefault()\n event.stopPropagation()\n\n if ('touches' in event && event.touches.length > 1) {\n this.lastTouchDistance = null\n } else if (this.touchStartX !== null) {\n if (!this.dragging) {\n this.host?.dispatchEvent(\n new CustomEvent('date-range-cleared', {\n bubbles: true,\n composed: true\n })\n )\n }\n\n this.touchStartX = null\n this.touchStartY = null\n this.scrollStartX = null\n this.scrollStartY = null\n }\n }\n\n getTouchDistance(touches: TouchList): number {\n const dx = touches[0].clientX - touches[1].clientX\n const dy = touches[0].clientY - touches[1].clientY\n return Math.sqrt(dx * dx + dy * dy)\n }\n}\n"]}
@@ -19,6 +19,7 @@ export declare class OxGanttChart extends LitElement {
19
19
  private ganttChartController;
20
20
  constructor();
21
21
  protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
22
+ disconnectedCallback(): void;
22
23
  updated(changedProperties: PropertyValues<this>): void;
23
24
  render(): import("lit-html").TemplateResult<1>;
24
25
  scrollToStart(): void;
@@ -35,4 +36,5 @@ export declare class OxGanttChart extends LitElement {
35
36
  initHeaderGestureHandlers(): void;
36
37
  highlightSelection(startX: number, endX: number): void;
37
38
  finalizeSelection(startX: number, endX: number): void;
39
+ clearSelection(): void;
38
40
  }
@@ -18,15 +18,20 @@ let OxGanttChart = class OxGanttChart extends LitElement {
18
18
  display: flex;
19
19
  overflow: hidden;
20
20
  position: relative;
21
+ user-select: none;
21
22
  }
23
+
22
24
  div[chart-container] {
23
25
  display: block;
24
26
  overflow-x: auto;
25
27
  overflow-y: hidden;
28
+ overscroll-behavior: none;
26
29
  }
30
+
27
31
  svg {
28
32
  min-width: 100%;
29
33
  }
34
+
30
35
  svg[header] {
31
36
  display: block;
32
37
  min-width: 100%;
@@ -39,27 +44,27 @@ let OxGanttChart = class OxGanttChart extends LitElement {
39
44
  top: 0;
40
45
  z-index: 1;
41
46
  }
42
- .scroll-buttons {
43
- position: absolute;
44
- top: 44px; /* 헤더 바로 아래 위치 */
45
- right: 4px;
46
- display: flex;
47
- align-items: center;
48
- gap: 2px;
49
- }
47
+
50
48
  .scroll-button {
51
- width: 10px;
52
- height: 10px;
49
+ position: absolute;
50
+ top: 46px; /* 헤더 바로 아래 위치 */
51
+ width: 14px;
52
+ height: 14px;
53
53
  background-color: var(--ox-gantt-header-color, var(--md-sys-color-on-secondary-container));
54
+ opacity: 0.5;
54
55
  clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
55
56
  cursor: pointer;
56
57
  transform: rotate(90deg);
57
58
  }
59
+
58
60
  .scroll-button.left {
61
+ left: 6px;
59
62
  transform: rotate(-90deg);
60
63
  }
64
+
61
65
  .scroll-button.right {
62
66
  transform: rotate(90deg);
67
+ right: 6px;
63
68
  }
64
69
  `
65
70
  ]; }
@@ -78,6 +83,11 @@ let OxGanttChart = class OxGanttChart extends LitElement {
78
83
  }
79
84
  firstUpdated(_changedProperties) {
80
85
  this.initHeaderGestureHandlers();
86
+ this.addEventListener('date-range-cleared', e => this.clearSelection());
87
+ }
88
+ disconnectedCallback() {
89
+ super.disconnectedCallback();
90
+ this.ganttChartController.dispose();
81
91
  }
82
92
  updated(changedProperties) {
83
93
  if (changedProperties.has('fromDate') || changedProperties.has('toDate')) {
@@ -108,8 +118,12 @@ let OxGanttChart = class OxGanttChart extends LitElement {
108
118
  <div
109
119
  chart-container
110
120
  @wheel=${(e) => this.ganttChartController.handleWheelForBody(e, this.container)}
121
+ @mousedown=${(e) => this.ganttChartController.handleTouchStartForBody(e, this.container)}
122
+ @mousemove=${(e) => this.ganttChartController.handleTouchMoveForBody(e, this.container)}
123
+ @mouseup=${(e) => this.ganttChartController.handleTouchEndForBody(e)}
111
124
  @touchstart=${(e) => this.ganttChartController.handleTouchStartForBody(e, this.container)}
112
125
  @touchmove=${(e) => this.ganttChartController.handleTouchMoveForBody(e, this.container)}
126
+ @touchend=${(e) => this.ganttChartController.handleTouchEndForBody(e)}
113
127
  >
114
128
  <svg
115
129
  header
@@ -117,10 +131,8 @@ let OxGanttChart = class OxGanttChart extends LitElement {
117
131
  @wheel=${this.handleWheelForHeader.bind(this)}
118
132
  ></svg>
119
133
  <svg body></svg>
120
- <div class="scroll-buttons">
121
- <div class="scroll-button left" @click=${this.scrollToStart}></div>
122
- <div class="scroll-button right" @click=${this.scrollToEnd}></div>
123
- </div>
134
+ <div class="scroll-button left" @click=${this.scrollToStart} @touchstart=${this.scrollToStart}></div>
135
+ <div class="scroll-button right" @click=${this.scrollToEnd} @touchstart=${this.scrollToEnd}></div>
124
136
  <ox-task-tooltip></ox-task-tooltip>
125
137
  </div>
126
138
  `;
@@ -218,58 +230,18 @@ let OxGanttChart = class OxGanttChart extends LitElement {
218
230
  const header = d3.select(this.svgHeader);
219
231
  let isDragging = false;
220
232
  let startX = null;
221
- let lastTouchDistance = null;
222
233
  const handleTouchStart = (event) => {
223
234
  event.preventDefault();
224
- if (event.touches.length === 2) {
225
- lastTouchDistance = getTouchDistance(event.touches);
226
- }
227
- else {
228
- isDragging = true;
229
- const touch = event.touches[0];
230
- const containerOffsetX = header.node().getBoundingClientRect().left;
231
- startX = touch.clientX - containerOffsetX;
232
- }
235
+ event.stopPropagation();
236
+ isDragging = true;
237
+ const touch = event.touches[0];
238
+ const containerOffsetX = header.node().getBoundingClientRect().left;
239
+ startX = touch.clientX - containerOffsetX;
233
240
  };
234
241
  const handleTouchMove = (event) => {
235
242
  event.preventDefault();
236
- if (event.touches.length === 2 && lastTouchDistance !== null) {
237
- const currentDistance = getTouchDistance(event.touches);
238
- const zoomFactor = currentDistance / lastTouchDistance;
239
- this.ganttChartController.baseWidth *= zoomFactor;
240
- if (this.ganttChartController.baseWidth > 60) {
241
- if (this.ganttChartController.level == 'year-quarter') {
242
- this.ganttChartController.baseWidth = 60;
243
- }
244
- else {
245
- this.ganttChartController.level = levelUp(this.ganttChartController.level);
246
- this.ganttChartController.baseWidth = 30;
247
- }
248
- }
249
- else if (this.ganttChartController.baseWidth < 30) {
250
- if (this.ganttChartController.level == 'week-day') {
251
- this.ganttChartController.baseWidth = 30;
252
- }
253
- else {
254
- this.ganttChartController.level = levelDown(this.ganttChartController.level);
255
- this.ganttChartController.baseWidth = 60;
256
- }
257
- }
258
- lastTouchDistance = currentDistance;
259
- this.ganttChartController.updateTimeScale();
260
- this.requestUpdate();
261
- // Dispatch custom event to sync with ox-resource-chart
262
- const customEvent = new CustomEvent('timescale-changed', {
263
- detail: {
264
- baseWidth: this.ganttChartController.baseWidth,
265
- level: this.ganttChartController.level
266
- },
267
- bubbles: true,
268
- composed: true
269
- });
270
- this.dispatchEvent(customEvent);
271
- }
272
- else if (isDragging && startX !== null) {
243
+ event.stopPropagation();
244
+ if (isDragging && startX !== null) {
273
245
  const touch = event.touches[0];
274
246
  const containerOffsetX = header.node().getBoundingClientRect().left;
275
247
  const currentX = touch.clientX - containerOffsetX;
@@ -278,9 +250,7 @@ let OxGanttChart = class OxGanttChart extends LitElement {
278
250
  };
279
251
  const handleTouchEnd = (event) => {
280
252
  event.preventDefault();
281
- if (event.touches.length < 2) {
282
- lastTouchDistance = null;
283
- }
253
+ event.stopPropagation();
284
254
  if (!isDragging || startX === null) {
285
255
  const touch = event.changedTouches[0];
286
256
  const containerOffsetX = header.node().getBoundingClientRect().left;
@@ -295,11 +265,6 @@ let OxGanttChart = class OxGanttChart extends LitElement {
295
265
  isDragging = false;
296
266
  startX = null;
297
267
  };
298
- const getTouchDistance = (touches) => {
299
- const dx = touches[0].clientX - touches[1].clientX;
300
- const dy = touches[0].clientY - touches[1].clientY;
301
- return Math.sqrt(dx * dx + dy * dy);
302
- };
303
268
  const handleMouseDown = (event) => {
304
269
  isDragging = true;
305
270
  const containerOffsetX = header.node().getBoundingClientRect().left;
@@ -431,6 +396,13 @@ let OxGanttChart = class OxGanttChart extends LitElement {
431
396
  });
432
397
  header.node()?.dispatchEvent(customEvent);
433
398
  }
399
+ clearSelection() {
400
+ const header = d3.select(this.svgHeader);
401
+ const body = d3.select(this.svgBody);
402
+ // 선택한 영역을 나타내는 모든 'selection-rect' 요소를 제거합니다.
403
+ header.selectAll('.selection-rect').remove();
404
+ body.selectAll('.selection-rect').remove();
405
+ }
434
406
  };
435
407
  __decorate([
436
408
  property({ type: String, attribute: 'from-date' })