gantt-canvas-chart 1.3.0 → 1.3.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.
- package/dist/index.cjs.js +36 -21
- package/dist/index.css +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.es.js +36 -21
- package/dist/index.umd.js +36 -21
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* gantt-canvas-chart v1.3.
|
|
2
|
+
* gantt-canvas-chart v1.3.1
|
|
3
3
|
* (c) 2025-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -196,6 +196,7 @@ class GanttChart {
|
|
|
196
196
|
this.handleScroll = this.handleScroll.bind(this);
|
|
197
197
|
this.horizontalScrollTo = this.horizontalScrollTo.bind(this);
|
|
198
198
|
this.verticalScrollTo = this.verticalScrollTo.bind(this);
|
|
199
|
+
this.handleResize = this.handleResize.bind(this);
|
|
199
200
|
this.init();
|
|
200
201
|
}
|
|
201
202
|
init() {
|
|
@@ -218,7 +219,6 @@ class GanttChart {
|
|
|
218
219
|
}
|
|
219
220
|
setupEvents() {
|
|
220
221
|
this.container.addEventListener("scroll", this.handleScroll);
|
|
221
|
-
this.handleResize = this.handleResize.bind(this);
|
|
222
222
|
if (window.ResizeObserver) {
|
|
223
223
|
this.resizeObserver = new ResizeObserver(this.handleResize);
|
|
224
224
|
setTimeout(() => {
|
|
@@ -260,6 +260,9 @@ class GanttChart {
|
|
|
260
260
|
this.container.removeEventListener("scroll", this.handleScroll);
|
|
261
261
|
this.mainCanvas.removeEventListener("mousemove", this.handleMouseMove);
|
|
262
262
|
this.mainCanvas.removeEventListener("mouseleave", this.handleMouseLeave);
|
|
263
|
+
this.data = [];
|
|
264
|
+
this.taskMap.clear();
|
|
265
|
+
this.taskPositions.clear();
|
|
263
266
|
this.container.remove();
|
|
264
267
|
}
|
|
265
268
|
calculateFullTimeline() {
|
|
@@ -375,13 +378,10 @@ class GanttChart {
|
|
|
375
378
|
try {
|
|
376
379
|
if (this.hasMoreDataLeft && atLeftEdge && scrollLeft < this.lastScrollLeft) {
|
|
377
380
|
await this.loadMoreData("left");
|
|
378
|
-
console.log("left-loadMoreData::", this.data);
|
|
379
381
|
} else if (this.hasMoreDataRight && atRightEdge && scrollLeft > this.lastScrollLeft) {
|
|
380
382
|
await this.loadMoreData("right");
|
|
381
|
-
console.log("right-loadMoreData::", this.data);
|
|
382
383
|
} else if (this.hasMoreDataBottom && atBottomEdge && scrollTop > this.lastScrollTop) {
|
|
383
384
|
await this.loadMoreData("bottom");
|
|
384
|
-
console.log("bottom-loadMoreData::", this.data);
|
|
385
385
|
}
|
|
386
386
|
} finally {
|
|
387
387
|
this.lastScrollLeft = scrollLeft;
|
|
@@ -510,17 +510,39 @@ class GanttChart {
|
|
|
510
510
|
const x_plan_start = this.dateToX(new Date(task.planStart));
|
|
511
511
|
const x_plan_end = this.dateToX(DateUtils.addDays(task.planEnd, 1));
|
|
512
512
|
let x_actual_start = null, x_actual_end = null;
|
|
513
|
+
let offset_x_plan_start = NaN, offset_x_plan_end = NaN;
|
|
514
|
+
let offset_x_actual_start = null, offset_x_actual_end = null;
|
|
515
|
+
let x_plan_width = 0;
|
|
516
|
+
let x_actual_width = 0;
|
|
517
|
+
const [offsetX_actual, percent_actual] = this.config.viewMode === "Day" && task.actualOffsetPercent ? task.actualOffsetPercent : [0, 1];
|
|
518
|
+
const [offsetX, percent_plan] = this.config.viewMode === "Day" && task.planOffsetPercent ? task.planOffsetPercent : [0, 1];
|
|
519
|
+
if (x_plan_start && x_plan_end) {
|
|
520
|
+
x_plan_width = x_plan_end - x_plan_start;
|
|
521
|
+
offset_x_plan_start = x_plan_start + x_plan_width * offsetX;
|
|
522
|
+
x_plan_end && (offset_x_plan_end = offset_x_plan_start + x_plan_width * percent_plan);
|
|
523
|
+
}
|
|
513
524
|
if (task.actualStart) {
|
|
514
525
|
x_actual_start = this.dateToX(new Date(task.actualStart));
|
|
515
526
|
}
|
|
516
527
|
if (task.actualEnd) {
|
|
517
528
|
x_actual_end = this.dateToX(DateUtils.addDays(task.actualEnd, 1));
|
|
518
529
|
}
|
|
530
|
+
if (x_actual_start) {
|
|
531
|
+
x_actual_width = (x_actual_end ? x_actual_end : this.dateToX(this.today)) - x_actual_start;
|
|
532
|
+
offset_x_actual_start = Math.round(x_actual_start + x_actual_width * offsetX_actual);
|
|
533
|
+
x_actual_end && (offset_x_actual_end = offset_x_actual_start + x_actual_width * percent_actual);
|
|
534
|
+
}
|
|
519
535
|
this.taskPositions.set(task.id, {
|
|
520
536
|
x_plan_start,
|
|
521
537
|
x_plan_end,
|
|
522
538
|
x_actual_start,
|
|
523
539
|
x_actual_end,
|
|
540
|
+
offset_x_plan_start,
|
|
541
|
+
offset_x_plan_end,
|
|
542
|
+
offset_x_actual_start,
|
|
543
|
+
offset_x_actual_end,
|
|
544
|
+
x_plan_width,
|
|
545
|
+
x_actual_width,
|
|
524
546
|
y: y + this.config.rowHeight * 0.5,
|
|
525
547
|
row: i
|
|
526
548
|
});
|
|
@@ -765,9 +787,9 @@ class GanttChart {
|
|
|
765
787
|
if (!fromPos) return;
|
|
766
788
|
const fromRowIndex = this.taskMap.get(depId).row;
|
|
767
789
|
const isAdjacent = Math.abs(toRowIndex - fromRowIndex) === 1;
|
|
768
|
-
const fromX = Math.max(fromPos.
|
|
790
|
+
const fromX = Math.max(fromPos.offset_x_plan_end, fromPos.offset_x_actual_end || fromPos.offset_x_plan_end);
|
|
769
791
|
const fromY = fromPos.y;
|
|
770
|
-
const toX = Math.min(toPos.
|
|
792
|
+
const toX = Math.min(toPos.offset_x_plan_start, toPos.offset_x_actual_start || toPos.offset_x_plan_start);
|
|
771
793
|
const toY = toPos.y;
|
|
772
794
|
ctx.beginPath();
|
|
773
795
|
if (isAdjacent) {
|
|
@@ -922,42 +944,35 @@ class GanttChart {
|
|
|
922
944
|
}
|
|
923
945
|
drawTask(ctx, task, y, pos) {
|
|
924
946
|
const offset = 4;
|
|
925
|
-
const width = pos.x_plan_end - pos.x_plan_start;
|
|
926
947
|
const taskY = y + this.config.rowHeight * 0.15 + offset;
|
|
927
948
|
const taskHeight = this.config.rowHeight * 0.7 - offset;
|
|
928
949
|
const textY = y + this.config.rowHeight / 2 + offset;
|
|
929
950
|
const [offsetX_actual, percent_actual] = this.config.viewMode === "Day" && task.actualOffsetPercent ? task.actualOffsetPercent : [0, 1];
|
|
930
|
-
const [offsetX, percent_plan] = this.config.viewMode === "Day" && task.planOffsetPercent ? task.planOffsetPercent : [0, 1];
|
|
931
951
|
if (this.config.showActual && pos.x_actual_start) {
|
|
932
952
|
ctx.fillStyle = task.actualBgColor ? task.actualBgColor : this.config.actualBgColor;
|
|
933
|
-
|
|
934
|
-
pos.x_actual_start += aWidth * offsetX_actual;
|
|
935
|
-
pos.x_actual_end && (pos.x_actual_end = pos.x_actual_start + aWidth * percent_actual);
|
|
936
|
-
ctx.fillRect(Math.round(pos.x_actual_start), Math.round(taskY + 2), Math.round(aWidth * percent_actual), Math.round(taskHeight - 2));
|
|
953
|
+
ctx.fillRect(pos.offset_x_actual_start, Math.round(taskY + 2), Math.round(pos.x_actual_width * percent_actual), Math.round(taskHeight - 2));
|
|
937
954
|
}
|
|
938
955
|
if (this.config.showPlan && pos.x_plan_start && pos.x_plan_end) {
|
|
939
956
|
ctx.strokeStyle = task.planBorderColor ? task.planBorderColor : this.config.planBorderColor;
|
|
940
|
-
pos.x_plan_start += width * offsetX;
|
|
941
|
-
pos.x_plan_end && (pos.x_plan_end = pos.x_plan_start + width * percent_plan);
|
|
942
957
|
ctx.lineWidth = 4;
|
|
943
958
|
ctx.beginPath();
|
|
944
|
-
ctx.moveTo(pos.
|
|
945
|
-
ctx.lineTo(pos.
|
|
959
|
+
ctx.moveTo(pos.offset_x_plan_start + offset / 2, taskY);
|
|
960
|
+
ctx.lineTo(pos.offset_x_plan_end - offset / 2, taskY);
|
|
946
961
|
ctx.stroke();
|
|
947
962
|
}
|
|
948
963
|
ctx.fillStyle = "#000";
|
|
949
964
|
if (this.config.showLeftRemark && task.leftRemark) {
|
|
950
965
|
ctx.textAlign = "right";
|
|
951
|
-
ctx.fillText(task.leftRemark, Math.round(Math.min(...[pos.
|
|
966
|
+
ctx.fillText(task.leftRemark, Math.round(Math.min(...[pos.offset_x_plan_start, pos.offset_x_actual_start].filter((val) => val !== null && val !== void 0)) - 8), Math.round(textY));
|
|
952
967
|
}
|
|
953
968
|
if (this.config.showRightRemark && task.rightRemark) {
|
|
954
969
|
ctx.textAlign = "left";
|
|
955
|
-
ctx.fillText(task.rightRemark, Math.round(Math.max(...[pos.
|
|
970
|
+
ctx.fillText(task.rightRemark, Math.round(Math.max(...[pos.offset_x_plan_end, pos.offset_x_actual_end].filter((val) => val !== null && val !== void 0)) + 8), Math.round(textY));
|
|
956
971
|
}
|
|
957
972
|
if (this.config.showCenterRemark && task.centerRemark) {
|
|
958
|
-
const centerX = pos.
|
|
973
|
+
const centerX = pos.offset_x_actual_start + (pos.offset_x_actual_end - pos.offset_x_actual_start) / 2;
|
|
959
974
|
ctx.textAlign = "center";
|
|
960
|
-
ctx.fillText(task.centerRemark, Math.round(centerX), Math.round(textY), Math.round(pos.
|
|
975
|
+
ctx.fillText(task.centerRemark, Math.round(centerX), Math.round(textY), Math.round(pos.offset_x_actual_end - pos.offset_x_actual_start));
|
|
961
976
|
}
|
|
962
977
|
}
|
|
963
978
|
getTaskStyles(task) {
|
package/dist/index.css
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -187,6 +187,12 @@ export declare interface TaskPosition {
|
|
|
187
187
|
x_plan_end: number;
|
|
188
188
|
x_actual_start: number | null;
|
|
189
189
|
x_actual_end: number | null;
|
|
190
|
+
x_plan_width: number;
|
|
191
|
+
x_actual_width: number;
|
|
192
|
+
offset_x_plan_start: number;
|
|
193
|
+
offset_x_plan_end: number;
|
|
194
|
+
offset_x_actual_start: number | null;
|
|
195
|
+
offset_x_actual_end: number | null;
|
|
190
196
|
y: number;
|
|
191
197
|
row: number;
|
|
192
198
|
}
|
package/dist/index.es.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* gantt-canvas-chart v1.3.
|
|
2
|
+
* gantt-canvas-chart v1.3.1
|
|
3
3
|
* (c) 2025-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -194,6 +194,7 @@ class GanttChart {
|
|
|
194
194
|
this.handleScroll = this.handleScroll.bind(this);
|
|
195
195
|
this.horizontalScrollTo = this.horizontalScrollTo.bind(this);
|
|
196
196
|
this.verticalScrollTo = this.verticalScrollTo.bind(this);
|
|
197
|
+
this.handleResize = this.handleResize.bind(this);
|
|
197
198
|
this.init();
|
|
198
199
|
}
|
|
199
200
|
init() {
|
|
@@ -216,7 +217,6 @@ class GanttChart {
|
|
|
216
217
|
}
|
|
217
218
|
setupEvents() {
|
|
218
219
|
this.container.addEventListener("scroll", this.handleScroll);
|
|
219
|
-
this.handleResize = this.handleResize.bind(this);
|
|
220
220
|
if (window.ResizeObserver) {
|
|
221
221
|
this.resizeObserver = new ResizeObserver(this.handleResize);
|
|
222
222
|
setTimeout(() => {
|
|
@@ -258,6 +258,9 @@ class GanttChart {
|
|
|
258
258
|
this.container.removeEventListener("scroll", this.handleScroll);
|
|
259
259
|
this.mainCanvas.removeEventListener("mousemove", this.handleMouseMove);
|
|
260
260
|
this.mainCanvas.removeEventListener("mouseleave", this.handleMouseLeave);
|
|
261
|
+
this.data = [];
|
|
262
|
+
this.taskMap.clear();
|
|
263
|
+
this.taskPositions.clear();
|
|
261
264
|
this.container.remove();
|
|
262
265
|
}
|
|
263
266
|
calculateFullTimeline() {
|
|
@@ -373,13 +376,10 @@ class GanttChart {
|
|
|
373
376
|
try {
|
|
374
377
|
if (this.hasMoreDataLeft && atLeftEdge && scrollLeft < this.lastScrollLeft) {
|
|
375
378
|
await this.loadMoreData("left");
|
|
376
|
-
console.log("left-loadMoreData::", this.data);
|
|
377
379
|
} else if (this.hasMoreDataRight && atRightEdge && scrollLeft > this.lastScrollLeft) {
|
|
378
380
|
await this.loadMoreData("right");
|
|
379
|
-
console.log("right-loadMoreData::", this.data);
|
|
380
381
|
} else if (this.hasMoreDataBottom && atBottomEdge && scrollTop > this.lastScrollTop) {
|
|
381
382
|
await this.loadMoreData("bottom");
|
|
382
|
-
console.log("bottom-loadMoreData::", this.data);
|
|
383
383
|
}
|
|
384
384
|
} finally {
|
|
385
385
|
this.lastScrollLeft = scrollLeft;
|
|
@@ -508,17 +508,39 @@ class GanttChart {
|
|
|
508
508
|
const x_plan_start = this.dateToX(new Date(task.planStart));
|
|
509
509
|
const x_plan_end = this.dateToX(DateUtils.addDays(task.planEnd, 1));
|
|
510
510
|
let x_actual_start = null, x_actual_end = null;
|
|
511
|
+
let offset_x_plan_start = NaN, offset_x_plan_end = NaN;
|
|
512
|
+
let offset_x_actual_start = null, offset_x_actual_end = null;
|
|
513
|
+
let x_plan_width = 0;
|
|
514
|
+
let x_actual_width = 0;
|
|
515
|
+
const [offsetX_actual, percent_actual] = this.config.viewMode === "Day" && task.actualOffsetPercent ? task.actualOffsetPercent : [0, 1];
|
|
516
|
+
const [offsetX, percent_plan] = this.config.viewMode === "Day" && task.planOffsetPercent ? task.planOffsetPercent : [0, 1];
|
|
517
|
+
if (x_plan_start && x_plan_end) {
|
|
518
|
+
x_plan_width = x_plan_end - x_plan_start;
|
|
519
|
+
offset_x_plan_start = x_plan_start + x_plan_width * offsetX;
|
|
520
|
+
x_plan_end && (offset_x_plan_end = offset_x_plan_start + x_plan_width * percent_plan);
|
|
521
|
+
}
|
|
511
522
|
if (task.actualStart) {
|
|
512
523
|
x_actual_start = this.dateToX(new Date(task.actualStart));
|
|
513
524
|
}
|
|
514
525
|
if (task.actualEnd) {
|
|
515
526
|
x_actual_end = this.dateToX(DateUtils.addDays(task.actualEnd, 1));
|
|
516
527
|
}
|
|
528
|
+
if (x_actual_start) {
|
|
529
|
+
x_actual_width = (x_actual_end ? x_actual_end : this.dateToX(this.today)) - x_actual_start;
|
|
530
|
+
offset_x_actual_start = Math.round(x_actual_start + x_actual_width * offsetX_actual);
|
|
531
|
+
x_actual_end && (offset_x_actual_end = offset_x_actual_start + x_actual_width * percent_actual);
|
|
532
|
+
}
|
|
517
533
|
this.taskPositions.set(task.id, {
|
|
518
534
|
x_plan_start,
|
|
519
535
|
x_plan_end,
|
|
520
536
|
x_actual_start,
|
|
521
537
|
x_actual_end,
|
|
538
|
+
offset_x_plan_start,
|
|
539
|
+
offset_x_plan_end,
|
|
540
|
+
offset_x_actual_start,
|
|
541
|
+
offset_x_actual_end,
|
|
542
|
+
x_plan_width,
|
|
543
|
+
x_actual_width,
|
|
522
544
|
y: y + this.config.rowHeight * 0.5,
|
|
523
545
|
row: i
|
|
524
546
|
});
|
|
@@ -763,9 +785,9 @@ class GanttChart {
|
|
|
763
785
|
if (!fromPos) return;
|
|
764
786
|
const fromRowIndex = this.taskMap.get(depId).row;
|
|
765
787
|
const isAdjacent = Math.abs(toRowIndex - fromRowIndex) === 1;
|
|
766
|
-
const fromX = Math.max(fromPos.
|
|
788
|
+
const fromX = Math.max(fromPos.offset_x_plan_end, fromPos.offset_x_actual_end || fromPos.offset_x_plan_end);
|
|
767
789
|
const fromY = fromPos.y;
|
|
768
|
-
const toX = Math.min(toPos.
|
|
790
|
+
const toX = Math.min(toPos.offset_x_plan_start, toPos.offset_x_actual_start || toPos.offset_x_plan_start);
|
|
769
791
|
const toY = toPos.y;
|
|
770
792
|
ctx.beginPath();
|
|
771
793
|
if (isAdjacent) {
|
|
@@ -920,42 +942,35 @@ class GanttChart {
|
|
|
920
942
|
}
|
|
921
943
|
drawTask(ctx, task, y, pos) {
|
|
922
944
|
const offset = 4;
|
|
923
|
-
const width = pos.x_plan_end - pos.x_plan_start;
|
|
924
945
|
const taskY = y + this.config.rowHeight * 0.15 + offset;
|
|
925
946
|
const taskHeight = this.config.rowHeight * 0.7 - offset;
|
|
926
947
|
const textY = y + this.config.rowHeight / 2 + offset;
|
|
927
948
|
const [offsetX_actual, percent_actual] = this.config.viewMode === "Day" && task.actualOffsetPercent ? task.actualOffsetPercent : [0, 1];
|
|
928
|
-
const [offsetX, percent_plan] = this.config.viewMode === "Day" && task.planOffsetPercent ? task.planOffsetPercent : [0, 1];
|
|
929
949
|
if (this.config.showActual && pos.x_actual_start) {
|
|
930
950
|
ctx.fillStyle = task.actualBgColor ? task.actualBgColor : this.config.actualBgColor;
|
|
931
|
-
|
|
932
|
-
pos.x_actual_start += aWidth * offsetX_actual;
|
|
933
|
-
pos.x_actual_end && (pos.x_actual_end = pos.x_actual_start + aWidth * percent_actual);
|
|
934
|
-
ctx.fillRect(Math.round(pos.x_actual_start), Math.round(taskY + 2), Math.round(aWidth * percent_actual), Math.round(taskHeight - 2));
|
|
951
|
+
ctx.fillRect(pos.offset_x_actual_start, Math.round(taskY + 2), Math.round(pos.x_actual_width * percent_actual), Math.round(taskHeight - 2));
|
|
935
952
|
}
|
|
936
953
|
if (this.config.showPlan && pos.x_plan_start && pos.x_plan_end) {
|
|
937
954
|
ctx.strokeStyle = task.planBorderColor ? task.planBorderColor : this.config.planBorderColor;
|
|
938
|
-
pos.x_plan_start += width * offsetX;
|
|
939
|
-
pos.x_plan_end && (pos.x_plan_end = pos.x_plan_start + width * percent_plan);
|
|
940
955
|
ctx.lineWidth = 4;
|
|
941
956
|
ctx.beginPath();
|
|
942
|
-
ctx.moveTo(pos.
|
|
943
|
-
ctx.lineTo(pos.
|
|
957
|
+
ctx.moveTo(pos.offset_x_plan_start + offset / 2, taskY);
|
|
958
|
+
ctx.lineTo(pos.offset_x_plan_end - offset / 2, taskY);
|
|
944
959
|
ctx.stroke();
|
|
945
960
|
}
|
|
946
961
|
ctx.fillStyle = "#000";
|
|
947
962
|
if (this.config.showLeftRemark && task.leftRemark) {
|
|
948
963
|
ctx.textAlign = "right";
|
|
949
|
-
ctx.fillText(task.leftRemark, Math.round(Math.min(...[pos.
|
|
964
|
+
ctx.fillText(task.leftRemark, Math.round(Math.min(...[pos.offset_x_plan_start, pos.offset_x_actual_start].filter((val) => val !== null && val !== void 0)) - 8), Math.round(textY));
|
|
950
965
|
}
|
|
951
966
|
if (this.config.showRightRemark && task.rightRemark) {
|
|
952
967
|
ctx.textAlign = "left";
|
|
953
|
-
ctx.fillText(task.rightRemark, Math.round(Math.max(...[pos.
|
|
968
|
+
ctx.fillText(task.rightRemark, Math.round(Math.max(...[pos.offset_x_plan_end, pos.offset_x_actual_end].filter((val) => val !== null && val !== void 0)) + 8), Math.round(textY));
|
|
954
969
|
}
|
|
955
970
|
if (this.config.showCenterRemark && task.centerRemark) {
|
|
956
|
-
const centerX = pos.
|
|
971
|
+
const centerX = pos.offset_x_actual_start + (pos.offset_x_actual_end - pos.offset_x_actual_start) / 2;
|
|
957
972
|
ctx.textAlign = "center";
|
|
958
|
-
ctx.fillText(task.centerRemark, Math.round(centerX), Math.round(textY), Math.round(pos.
|
|
973
|
+
ctx.fillText(task.centerRemark, Math.round(centerX), Math.round(textY), Math.round(pos.offset_x_actual_end - pos.offset_x_actual_start));
|
|
959
974
|
}
|
|
960
975
|
}
|
|
961
976
|
getTaskStyles(task) {
|
package/dist/index.umd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* gantt-canvas-chart v1.3.
|
|
2
|
+
* gantt-canvas-chart v1.3.1
|
|
3
3
|
* (c) 2025-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -198,6 +198,7 @@
|
|
|
198
198
|
this.handleScroll = this.handleScroll.bind(this);
|
|
199
199
|
this.horizontalScrollTo = this.horizontalScrollTo.bind(this);
|
|
200
200
|
this.verticalScrollTo = this.verticalScrollTo.bind(this);
|
|
201
|
+
this.handleResize = this.handleResize.bind(this);
|
|
201
202
|
this.init();
|
|
202
203
|
}
|
|
203
204
|
init() {
|
|
@@ -220,7 +221,6 @@
|
|
|
220
221
|
}
|
|
221
222
|
setupEvents() {
|
|
222
223
|
this.container.addEventListener("scroll", this.handleScroll);
|
|
223
|
-
this.handleResize = this.handleResize.bind(this);
|
|
224
224
|
if (window.ResizeObserver) {
|
|
225
225
|
this.resizeObserver = new ResizeObserver(this.handleResize);
|
|
226
226
|
setTimeout(() => {
|
|
@@ -262,6 +262,9 @@
|
|
|
262
262
|
this.container.removeEventListener("scroll", this.handleScroll);
|
|
263
263
|
this.mainCanvas.removeEventListener("mousemove", this.handleMouseMove);
|
|
264
264
|
this.mainCanvas.removeEventListener("mouseleave", this.handleMouseLeave);
|
|
265
|
+
this.data = [];
|
|
266
|
+
this.taskMap.clear();
|
|
267
|
+
this.taskPositions.clear();
|
|
265
268
|
this.container.remove();
|
|
266
269
|
}
|
|
267
270
|
calculateFullTimeline() {
|
|
@@ -377,13 +380,10 @@
|
|
|
377
380
|
try {
|
|
378
381
|
if (this.hasMoreDataLeft && atLeftEdge && scrollLeft < this.lastScrollLeft) {
|
|
379
382
|
await this.loadMoreData("left");
|
|
380
|
-
console.log("left-loadMoreData::", this.data);
|
|
381
383
|
} else if (this.hasMoreDataRight && atRightEdge && scrollLeft > this.lastScrollLeft) {
|
|
382
384
|
await this.loadMoreData("right");
|
|
383
|
-
console.log("right-loadMoreData::", this.data);
|
|
384
385
|
} else if (this.hasMoreDataBottom && atBottomEdge && scrollTop > this.lastScrollTop) {
|
|
385
386
|
await this.loadMoreData("bottom");
|
|
386
|
-
console.log("bottom-loadMoreData::", this.data);
|
|
387
387
|
}
|
|
388
388
|
} finally {
|
|
389
389
|
this.lastScrollLeft = scrollLeft;
|
|
@@ -512,17 +512,39 @@
|
|
|
512
512
|
const x_plan_start = this.dateToX(new Date(task.planStart));
|
|
513
513
|
const x_plan_end = this.dateToX(DateUtils.addDays(task.planEnd, 1));
|
|
514
514
|
let x_actual_start = null, x_actual_end = null;
|
|
515
|
+
let offset_x_plan_start = NaN, offset_x_plan_end = NaN;
|
|
516
|
+
let offset_x_actual_start = null, offset_x_actual_end = null;
|
|
517
|
+
let x_plan_width = 0;
|
|
518
|
+
let x_actual_width = 0;
|
|
519
|
+
const [offsetX_actual, percent_actual] = this.config.viewMode === "Day" && task.actualOffsetPercent ? task.actualOffsetPercent : [0, 1];
|
|
520
|
+
const [offsetX, percent_plan] = this.config.viewMode === "Day" && task.planOffsetPercent ? task.planOffsetPercent : [0, 1];
|
|
521
|
+
if (x_plan_start && x_plan_end) {
|
|
522
|
+
x_plan_width = x_plan_end - x_plan_start;
|
|
523
|
+
offset_x_plan_start = x_plan_start + x_plan_width * offsetX;
|
|
524
|
+
x_plan_end && (offset_x_plan_end = offset_x_plan_start + x_plan_width * percent_plan);
|
|
525
|
+
}
|
|
515
526
|
if (task.actualStart) {
|
|
516
527
|
x_actual_start = this.dateToX(new Date(task.actualStart));
|
|
517
528
|
}
|
|
518
529
|
if (task.actualEnd) {
|
|
519
530
|
x_actual_end = this.dateToX(DateUtils.addDays(task.actualEnd, 1));
|
|
520
531
|
}
|
|
532
|
+
if (x_actual_start) {
|
|
533
|
+
x_actual_width = (x_actual_end ? x_actual_end : this.dateToX(this.today)) - x_actual_start;
|
|
534
|
+
offset_x_actual_start = Math.round(x_actual_start + x_actual_width * offsetX_actual);
|
|
535
|
+
x_actual_end && (offset_x_actual_end = offset_x_actual_start + x_actual_width * percent_actual);
|
|
536
|
+
}
|
|
521
537
|
this.taskPositions.set(task.id, {
|
|
522
538
|
x_plan_start,
|
|
523
539
|
x_plan_end,
|
|
524
540
|
x_actual_start,
|
|
525
541
|
x_actual_end,
|
|
542
|
+
offset_x_plan_start,
|
|
543
|
+
offset_x_plan_end,
|
|
544
|
+
offset_x_actual_start,
|
|
545
|
+
offset_x_actual_end,
|
|
546
|
+
x_plan_width,
|
|
547
|
+
x_actual_width,
|
|
526
548
|
y: y + this.config.rowHeight * 0.5,
|
|
527
549
|
row: i
|
|
528
550
|
});
|
|
@@ -767,9 +789,9 @@
|
|
|
767
789
|
if (!fromPos) return;
|
|
768
790
|
const fromRowIndex = this.taskMap.get(depId).row;
|
|
769
791
|
const isAdjacent = Math.abs(toRowIndex - fromRowIndex) === 1;
|
|
770
|
-
const fromX = Math.max(fromPos.
|
|
792
|
+
const fromX = Math.max(fromPos.offset_x_plan_end, fromPos.offset_x_actual_end || fromPos.offset_x_plan_end);
|
|
771
793
|
const fromY = fromPos.y;
|
|
772
|
-
const toX = Math.min(toPos.
|
|
794
|
+
const toX = Math.min(toPos.offset_x_plan_start, toPos.offset_x_actual_start || toPos.offset_x_plan_start);
|
|
773
795
|
const toY = toPos.y;
|
|
774
796
|
ctx.beginPath();
|
|
775
797
|
if (isAdjacent) {
|
|
@@ -924,42 +946,35 @@
|
|
|
924
946
|
}
|
|
925
947
|
drawTask(ctx, task, y, pos) {
|
|
926
948
|
const offset = 4;
|
|
927
|
-
const width = pos.x_plan_end - pos.x_plan_start;
|
|
928
949
|
const taskY = y + this.config.rowHeight * 0.15 + offset;
|
|
929
950
|
const taskHeight = this.config.rowHeight * 0.7 - offset;
|
|
930
951
|
const textY = y + this.config.rowHeight / 2 + offset;
|
|
931
952
|
const [offsetX_actual, percent_actual] = this.config.viewMode === "Day" && task.actualOffsetPercent ? task.actualOffsetPercent : [0, 1];
|
|
932
|
-
const [offsetX, percent_plan] = this.config.viewMode === "Day" && task.planOffsetPercent ? task.planOffsetPercent : [0, 1];
|
|
933
953
|
if (this.config.showActual && pos.x_actual_start) {
|
|
934
954
|
ctx.fillStyle = task.actualBgColor ? task.actualBgColor : this.config.actualBgColor;
|
|
935
|
-
|
|
936
|
-
pos.x_actual_start += aWidth * offsetX_actual;
|
|
937
|
-
pos.x_actual_end && (pos.x_actual_end = pos.x_actual_start + aWidth * percent_actual);
|
|
938
|
-
ctx.fillRect(Math.round(pos.x_actual_start), Math.round(taskY + 2), Math.round(aWidth * percent_actual), Math.round(taskHeight - 2));
|
|
955
|
+
ctx.fillRect(pos.offset_x_actual_start, Math.round(taskY + 2), Math.round(pos.x_actual_width * percent_actual), Math.round(taskHeight - 2));
|
|
939
956
|
}
|
|
940
957
|
if (this.config.showPlan && pos.x_plan_start && pos.x_plan_end) {
|
|
941
958
|
ctx.strokeStyle = task.planBorderColor ? task.planBorderColor : this.config.planBorderColor;
|
|
942
|
-
pos.x_plan_start += width * offsetX;
|
|
943
|
-
pos.x_plan_end && (pos.x_plan_end = pos.x_plan_start + width * percent_plan);
|
|
944
959
|
ctx.lineWidth = 4;
|
|
945
960
|
ctx.beginPath();
|
|
946
|
-
ctx.moveTo(pos.
|
|
947
|
-
ctx.lineTo(pos.
|
|
961
|
+
ctx.moveTo(pos.offset_x_plan_start + offset / 2, taskY);
|
|
962
|
+
ctx.lineTo(pos.offset_x_plan_end - offset / 2, taskY);
|
|
948
963
|
ctx.stroke();
|
|
949
964
|
}
|
|
950
965
|
ctx.fillStyle = "#000";
|
|
951
966
|
if (this.config.showLeftRemark && task.leftRemark) {
|
|
952
967
|
ctx.textAlign = "right";
|
|
953
|
-
ctx.fillText(task.leftRemark, Math.round(Math.min(...[pos.
|
|
968
|
+
ctx.fillText(task.leftRemark, Math.round(Math.min(...[pos.offset_x_plan_start, pos.offset_x_actual_start].filter((val) => val !== null && val !== void 0)) - 8), Math.round(textY));
|
|
954
969
|
}
|
|
955
970
|
if (this.config.showRightRemark && task.rightRemark) {
|
|
956
971
|
ctx.textAlign = "left";
|
|
957
|
-
ctx.fillText(task.rightRemark, Math.round(Math.max(...[pos.
|
|
972
|
+
ctx.fillText(task.rightRemark, Math.round(Math.max(...[pos.offset_x_plan_end, pos.offset_x_actual_end].filter((val) => val !== null && val !== void 0)) + 8), Math.round(textY));
|
|
958
973
|
}
|
|
959
974
|
if (this.config.showCenterRemark && task.centerRemark) {
|
|
960
|
-
const centerX = pos.
|
|
975
|
+
const centerX = pos.offset_x_actual_start + (pos.offset_x_actual_end - pos.offset_x_actual_start) / 2;
|
|
961
976
|
ctx.textAlign = "center";
|
|
962
|
-
ctx.fillText(task.centerRemark, Math.round(centerX), Math.round(textY), Math.round(pos.
|
|
977
|
+
ctx.fillText(task.centerRemark, Math.round(centerX), Math.round(textY), Math.round(pos.offset_x_actual_end - pos.offset_x_actual_start));
|
|
963
978
|
}
|
|
964
979
|
}
|
|
965
980
|
getTaskStyles(task) {
|