gantt-canvas-chart 1.5.4 → 1.6.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 +64 -19
- package/dist/index.css +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.es.js +64 -19
- package/dist/index.umd.js +64 -19
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* gantt-canvas-chart v1.
|
|
2
|
+
* gantt-canvas-chart v1.6.1
|
|
3
3
|
* (c) 2025-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -9,24 +9,35 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
9
9
|
class DateUtils {
|
|
10
10
|
static ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
11
11
|
static format(date, format = "yyyy-MM-dd") {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
"
|
|
12
|
+
let fmt = format;
|
|
13
|
+
let ret;
|
|
14
|
+
const opt = {
|
|
15
|
+
"Y+": `${date.getFullYear()}`,
|
|
16
|
+
// 年
|
|
17
|
+
"y+": `${date.getFullYear()}`,
|
|
18
|
+
// 年
|
|
19
|
+
"M+": `${date.getMonth() + 1}`,
|
|
20
|
+
// 月
|
|
21
|
+
"D+": `${date.getDate()}`,
|
|
22
|
+
// 日
|
|
23
|
+
"d+": `${date.getDate()}`,
|
|
24
|
+
// 日
|
|
25
|
+
"h+": `${date.getHours()}`,
|
|
26
|
+
// 时
|
|
27
|
+
"m+": `${date.getMinutes()}`,
|
|
28
|
+
// 分
|
|
29
|
+
"s+": `${date.getSeconds()}`,
|
|
30
|
+
// 秒
|
|
18
31
|
"q+": Math.floor((date.getMonth() + 3) / 3),
|
|
19
32
|
W: ["日", "一", "二", "三", "四", "五", "六"][date.getDay()]
|
|
20
33
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
);
|
|
29
|
-
return format;
|
|
34
|
+
for (const k in opt) {
|
|
35
|
+
ret = new RegExp("(" + k + ")").exec(fmt);
|
|
36
|
+
if (ret) {
|
|
37
|
+
fmt = fmt.replace(ret[1], ret[1].length === 1 ? opt[k] : opt[k].padStart(ret[1].length, "0"));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return fmt;
|
|
30
41
|
}
|
|
31
42
|
static addDays(date, days) {
|
|
32
43
|
const r = new Date(date);
|
|
@@ -146,6 +157,7 @@ class GanttChart {
|
|
|
146
157
|
resizeObserver;
|
|
147
158
|
taskPositions;
|
|
148
159
|
taskMap;
|
|
160
|
+
holidaysMap;
|
|
149
161
|
isLoadingData = false;
|
|
150
162
|
hasMoreDataLeft = true;
|
|
151
163
|
hasMoreDataRight = true;
|
|
@@ -194,6 +206,9 @@ class GanttChart {
|
|
|
194
206
|
tooltipFormat: null,
|
|
195
207
|
tooltipColor: "black",
|
|
196
208
|
todayColor: "#ff4d4f",
|
|
209
|
+
weekendBgColor: "#f7f7f7",
|
|
210
|
+
holidays: [],
|
|
211
|
+
dateSeparator: "/",
|
|
197
212
|
offsetTop: 0,
|
|
198
213
|
offsetLeft: 0,
|
|
199
214
|
scrollEdgeThresholds: 10,
|
|
@@ -232,6 +247,7 @@ class GanttChart {
|
|
|
232
247
|
this.totalHeight = 0;
|
|
233
248
|
this.taskPositions = /* @__PURE__ */ new Map();
|
|
234
249
|
this.taskMap = /* @__PURE__ */ new Map();
|
|
250
|
+
this.holidaysMap = /* @__PURE__ */ new Map();
|
|
235
251
|
this.handleMouseMove = this.handleMouseMove.bind(this);
|
|
236
252
|
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
|
237
253
|
this.handleScroll = this.handleScroll.bind(this);
|
|
@@ -241,6 +257,9 @@ class GanttChart {
|
|
|
241
257
|
this.init();
|
|
242
258
|
}
|
|
243
259
|
init() {
|
|
260
|
+
if (this.config.holidays.length > 0) {
|
|
261
|
+
this.buildHolidaysMap();
|
|
262
|
+
}
|
|
244
263
|
this.buildTaskMap();
|
|
245
264
|
this.updatePixelsPerDay();
|
|
246
265
|
this.calculateFullTimeline();
|
|
@@ -289,10 +308,26 @@ class GanttChart {
|
|
|
289
308
|
this.updatePixelsPerDay();
|
|
290
309
|
this.calculateFullTimeline();
|
|
291
310
|
}
|
|
311
|
+
if (this.config.holidays.length !== this.holidaysMap.size) {
|
|
312
|
+
this.buildHolidaysMap();
|
|
313
|
+
}
|
|
292
314
|
this.updateLoadMoreConf();
|
|
293
315
|
this.updateDimensions();
|
|
294
316
|
this.render();
|
|
295
317
|
}
|
|
318
|
+
buildHolidaysMap() {
|
|
319
|
+
this.holidaysMap.clear();
|
|
320
|
+
const separator = this.config.dateSeparator;
|
|
321
|
+
if (this.config.holidays && this.config.holidays.length > 0 && this.config.holidays[0].includes(separator)) {
|
|
322
|
+
this.config.holidays.forEach((holiday) => {
|
|
323
|
+
this.holidaysMap.set(holiday, true);
|
|
324
|
+
});
|
|
325
|
+
} else {
|
|
326
|
+
this.config.holidays.forEach((holiday) => {
|
|
327
|
+
this.holidaysMap.set(DateUtils.format(new Date(holiday), `yyyy${separator}MM${separator}dd`), true);
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
296
331
|
setData(newData, newConfig) {
|
|
297
332
|
this.data = newData;
|
|
298
333
|
this.buildTaskMap();
|
|
@@ -307,6 +342,7 @@ class GanttChart {
|
|
|
307
342
|
destroy() {
|
|
308
343
|
if (this.resizeObserver) {
|
|
309
344
|
this.resizeObserver.disconnect();
|
|
345
|
+
this.resizeObserver = null;
|
|
310
346
|
}
|
|
311
347
|
this.container.removeEventListener("scroll", this.handleScroll);
|
|
312
348
|
this.mainCanvas.removeEventListener("mousemove", this.handleMouseMove);
|
|
@@ -314,6 +350,8 @@ class GanttChart {
|
|
|
314
350
|
this.data = [];
|
|
315
351
|
this.taskMap.clear();
|
|
316
352
|
this.taskPositions.clear();
|
|
353
|
+
this.holidaysMap.clear();
|
|
354
|
+
this.config.holidays = [];
|
|
317
355
|
this.container.remove();
|
|
318
356
|
}
|
|
319
357
|
calculateFullTimeline() {
|
|
@@ -730,7 +768,7 @@ class GanttChart {
|
|
|
730
768
|
}
|
|
731
769
|
const groupedBlocks = this.groupConsecutiveBlocks(visibleBlocks);
|
|
732
770
|
ctx.fillStyle = "#333";
|
|
733
|
-
ctx.font = "bold
|
|
771
|
+
ctx.font = "bold 12px Roboto,PingFang SC,Noto Sans SC,Microsoft YaHei UI,Microsoft YaHei,Segoe UI,Helvetica Neue,Helvetica,Arial,sans-serif";
|
|
734
772
|
ctx.textAlign = "left";
|
|
735
773
|
groupedBlocks.forEach((group) => {
|
|
736
774
|
const visibleStart = Math.max(group.startX, this.scrollLeft);
|
|
@@ -739,7 +777,7 @@ class GanttChart {
|
|
|
739
777
|
ctx.fillStyle = this.config.headerBgColor;
|
|
740
778
|
ctx.fillRect(Math.round(visibleStart), 0, Math.round(visibleEnd - visibleStart), Math.round(h * 0.5));
|
|
741
779
|
ctx.fillStyle = "#333";
|
|
742
|
-
ctx.fillText(group.text, Math.round(visibleStart + 5), Math.round(group.yPos));
|
|
780
|
+
ctx.fillText(group.text, Math.round(visibleStart + 5), Math.round(group.yPos - 3));
|
|
743
781
|
}
|
|
744
782
|
});
|
|
745
783
|
while (currentDateForLower <= this.visibleDateRange.end) {
|
|
@@ -778,7 +816,7 @@ class GanttChart {
|
|
|
778
816
|
}
|
|
779
817
|
const unitWidth = this.dateToX(nextDate) - x;
|
|
780
818
|
ctx.fillStyle = "#000412";
|
|
781
|
-
ctx.font = "
|
|
819
|
+
ctx.font = "12px Roboto,PingFang SC,Noto Sans SC,Microsoft YaHei UI,Microsoft YaHei,Segoe UI,Helvetica Neue,Helvetica,Arial,sans-serif";
|
|
782
820
|
ctx.textAlign = "center";
|
|
783
821
|
ctx.fillText(lowerText, Math.round(x + unitWidth / 2), Math.round(h * 0.7));
|
|
784
822
|
ctx.beginPath();
|
|
@@ -930,6 +968,7 @@ class GanttChart {
|
|
|
930
968
|
}
|
|
931
969
|
// In the drawGrid method
|
|
932
970
|
drawGrid(ctx, startDate, endDate) {
|
|
971
|
+
const separator = this.config.dateSeparator;
|
|
933
972
|
ctx.strokeStyle = "#e6e6e6";
|
|
934
973
|
ctx.lineWidth = 1;
|
|
935
974
|
ctx.beginPath();
|
|
@@ -989,6 +1028,12 @@ class GanttChart {
|
|
|
989
1028
|
const x = this.snap(this.dateToX(currentDate));
|
|
990
1029
|
ctx.moveTo(x, this.scrollTop);
|
|
991
1030
|
ctx.lineTo(x, this.scrollTop + this.viewportHeight);
|
|
1031
|
+
if (this.config.viewMode === "Day") {
|
|
1032
|
+
if ([0, 6].includes(currentDate.getDay()) || this.holidaysMap.has(DateUtils.format(currentDate, `yyyy${separator}MM${separator}dd`))) {
|
|
1033
|
+
ctx.fillStyle = this.config.weekendBgColor;
|
|
1034
|
+
ctx.fillRect(x + 1, this.scrollTop, Math.round(this.pixelsPerDay - 1), Math.round(this.scrollTop + this.viewportHeight));
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
992
1037
|
switch (this.config.viewMode) {
|
|
993
1038
|
case "Day":
|
|
994
1039
|
nextDate = DateUtils.addDays(currentDate, 1);
|
package/dist/index.css
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -85,6 +85,7 @@ export declare class GanttChart {
|
|
|
85
85
|
row: number;
|
|
86
86
|
task: Task;
|
|
87
87
|
}>;
|
|
88
|
+
holidaysMap: Map<string, boolean>;
|
|
88
89
|
private isLoadingData;
|
|
89
90
|
private hasMoreDataLeft;
|
|
90
91
|
private hasMoreDataRight;
|
|
@@ -99,6 +100,7 @@ export declare class GanttChart {
|
|
|
99
100
|
private buildTaskMap;
|
|
100
101
|
private setupEvents;
|
|
101
102
|
updateConfig(newConfig: GanttConfig): void;
|
|
103
|
+
private buildHolidaysMap;
|
|
102
104
|
setData(newData: GanttData, newConfig?: GanttConfig): void;
|
|
103
105
|
destroy(): void;
|
|
104
106
|
private calculateFullTimeline;
|
|
@@ -180,6 +182,9 @@ export declare interface GanttConfig {
|
|
|
180
182
|
showTooltip?: boolean;
|
|
181
183
|
tooltipColor?: 'black' | 'white';
|
|
182
184
|
todayColor?: string;
|
|
185
|
+
weekendBgColor?: string;
|
|
186
|
+
holidays?: string[];
|
|
187
|
+
dateSeparator?: string;
|
|
183
188
|
offsetTop?: number;
|
|
184
189
|
offsetLeft?: number;
|
|
185
190
|
scrollEdgeThresholds?: number;
|
package/dist/index.es.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* gantt-canvas-chart v1.
|
|
2
|
+
* gantt-canvas-chart v1.6.1
|
|
3
3
|
* (c) 2025-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -7,24 +7,35 @@
|
|
|
7
7
|
class DateUtils {
|
|
8
8
|
static ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
9
9
|
static format(date, format = "yyyy-MM-dd") {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
"
|
|
10
|
+
let fmt = format;
|
|
11
|
+
let ret;
|
|
12
|
+
const opt = {
|
|
13
|
+
"Y+": `${date.getFullYear()}`,
|
|
14
|
+
// 年
|
|
15
|
+
"y+": `${date.getFullYear()}`,
|
|
16
|
+
// 年
|
|
17
|
+
"M+": `${date.getMonth() + 1}`,
|
|
18
|
+
// 月
|
|
19
|
+
"D+": `${date.getDate()}`,
|
|
20
|
+
// 日
|
|
21
|
+
"d+": `${date.getDate()}`,
|
|
22
|
+
// 日
|
|
23
|
+
"h+": `${date.getHours()}`,
|
|
24
|
+
// 时
|
|
25
|
+
"m+": `${date.getMinutes()}`,
|
|
26
|
+
// 分
|
|
27
|
+
"s+": `${date.getSeconds()}`,
|
|
28
|
+
// 秒
|
|
16
29
|
"q+": Math.floor((date.getMonth() + 3) / 3),
|
|
17
30
|
W: ["日", "一", "二", "三", "四", "五", "六"][date.getDay()]
|
|
18
31
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
);
|
|
27
|
-
return format;
|
|
32
|
+
for (const k in opt) {
|
|
33
|
+
ret = new RegExp("(" + k + ")").exec(fmt);
|
|
34
|
+
if (ret) {
|
|
35
|
+
fmt = fmt.replace(ret[1], ret[1].length === 1 ? opt[k] : opt[k].padStart(ret[1].length, "0"));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return fmt;
|
|
28
39
|
}
|
|
29
40
|
static addDays(date, days) {
|
|
30
41
|
const r = new Date(date);
|
|
@@ -144,6 +155,7 @@ class GanttChart {
|
|
|
144
155
|
resizeObserver;
|
|
145
156
|
taskPositions;
|
|
146
157
|
taskMap;
|
|
158
|
+
holidaysMap;
|
|
147
159
|
isLoadingData = false;
|
|
148
160
|
hasMoreDataLeft = true;
|
|
149
161
|
hasMoreDataRight = true;
|
|
@@ -192,6 +204,9 @@ class GanttChart {
|
|
|
192
204
|
tooltipFormat: null,
|
|
193
205
|
tooltipColor: "black",
|
|
194
206
|
todayColor: "#ff4d4f",
|
|
207
|
+
weekendBgColor: "#f7f7f7",
|
|
208
|
+
holidays: [],
|
|
209
|
+
dateSeparator: "/",
|
|
195
210
|
offsetTop: 0,
|
|
196
211
|
offsetLeft: 0,
|
|
197
212
|
scrollEdgeThresholds: 10,
|
|
@@ -230,6 +245,7 @@ class GanttChart {
|
|
|
230
245
|
this.totalHeight = 0;
|
|
231
246
|
this.taskPositions = /* @__PURE__ */ new Map();
|
|
232
247
|
this.taskMap = /* @__PURE__ */ new Map();
|
|
248
|
+
this.holidaysMap = /* @__PURE__ */ new Map();
|
|
233
249
|
this.handleMouseMove = this.handleMouseMove.bind(this);
|
|
234
250
|
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
|
235
251
|
this.handleScroll = this.handleScroll.bind(this);
|
|
@@ -239,6 +255,9 @@ class GanttChart {
|
|
|
239
255
|
this.init();
|
|
240
256
|
}
|
|
241
257
|
init() {
|
|
258
|
+
if (this.config.holidays.length > 0) {
|
|
259
|
+
this.buildHolidaysMap();
|
|
260
|
+
}
|
|
242
261
|
this.buildTaskMap();
|
|
243
262
|
this.updatePixelsPerDay();
|
|
244
263
|
this.calculateFullTimeline();
|
|
@@ -287,10 +306,26 @@ class GanttChart {
|
|
|
287
306
|
this.updatePixelsPerDay();
|
|
288
307
|
this.calculateFullTimeline();
|
|
289
308
|
}
|
|
309
|
+
if (this.config.holidays.length !== this.holidaysMap.size) {
|
|
310
|
+
this.buildHolidaysMap();
|
|
311
|
+
}
|
|
290
312
|
this.updateLoadMoreConf();
|
|
291
313
|
this.updateDimensions();
|
|
292
314
|
this.render();
|
|
293
315
|
}
|
|
316
|
+
buildHolidaysMap() {
|
|
317
|
+
this.holidaysMap.clear();
|
|
318
|
+
const separator = this.config.dateSeparator;
|
|
319
|
+
if (this.config.holidays && this.config.holidays.length > 0 && this.config.holidays[0].includes(separator)) {
|
|
320
|
+
this.config.holidays.forEach((holiday) => {
|
|
321
|
+
this.holidaysMap.set(holiday, true);
|
|
322
|
+
});
|
|
323
|
+
} else {
|
|
324
|
+
this.config.holidays.forEach((holiday) => {
|
|
325
|
+
this.holidaysMap.set(DateUtils.format(new Date(holiday), `yyyy${separator}MM${separator}dd`), true);
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
294
329
|
setData(newData, newConfig) {
|
|
295
330
|
this.data = newData;
|
|
296
331
|
this.buildTaskMap();
|
|
@@ -305,6 +340,7 @@ class GanttChart {
|
|
|
305
340
|
destroy() {
|
|
306
341
|
if (this.resizeObserver) {
|
|
307
342
|
this.resizeObserver.disconnect();
|
|
343
|
+
this.resizeObserver = null;
|
|
308
344
|
}
|
|
309
345
|
this.container.removeEventListener("scroll", this.handleScroll);
|
|
310
346
|
this.mainCanvas.removeEventListener("mousemove", this.handleMouseMove);
|
|
@@ -312,6 +348,8 @@ class GanttChart {
|
|
|
312
348
|
this.data = [];
|
|
313
349
|
this.taskMap.clear();
|
|
314
350
|
this.taskPositions.clear();
|
|
351
|
+
this.holidaysMap.clear();
|
|
352
|
+
this.config.holidays = [];
|
|
315
353
|
this.container.remove();
|
|
316
354
|
}
|
|
317
355
|
calculateFullTimeline() {
|
|
@@ -728,7 +766,7 @@ class GanttChart {
|
|
|
728
766
|
}
|
|
729
767
|
const groupedBlocks = this.groupConsecutiveBlocks(visibleBlocks);
|
|
730
768
|
ctx.fillStyle = "#333";
|
|
731
|
-
ctx.font = "bold
|
|
769
|
+
ctx.font = "bold 12px Roboto,PingFang SC,Noto Sans SC,Microsoft YaHei UI,Microsoft YaHei,Segoe UI,Helvetica Neue,Helvetica,Arial,sans-serif";
|
|
732
770
|
ctx.textAlign = "left";
|
|
733
771
|
groupedBlocks.forEach((group) => {
|
|
734
772
|
const visibleStart = Math.max(group.startX, this.scrollLeft);
|
|
@@ -737,7 +775,7 @@ class GanttChart {
|
|
|
737
775
|
ctx.fillStyle = this.config.headerBgColor;
|
|
738
776
|
ctx.fillRect(Math.round(visibleStart), 0, Math.round(visibleEnd - visibleStart), Math.round(h * 0.5));
|
|
739
777
|
ctx.fillStyle = "#333";
|
|
740
|
-
ctx.fillText(group.text, Math.round(visibleStart + 5), Math.round(group.yPos));
|
|
778
|
+
ctx.fillText(group.text, Math.round(visibleStart + 5), Math.round(group.yPos - 3));
|
|
741
779
|
}
|
|
742
780
|
});
|
|
743
781
|
while (currentDateForLower <= this.visibleDateRange.end) {
|
|
@@ -776,7 +814,7 @@ class GanttChart {
|
|
|
776
814
|
}
|
|
777
815
|
const unitWidth = this.dateToX(nextDate) - x;
|
|
778
816
|
ctx.fillStyle = "#000412";
|
|
779
|
-
ctx.font = "
|
|
817
|
+
ctx.font = "12px Roboto,PingFang SC,Noto Sans SC,Microsoft YaHei UI,Microsoft YaHei,Segoe UI,Helvetica Neue,Helvetica,Arial,sans-serif";
|
|
780
818
|
ctx.textAlign = "center";
|
|
781
819
|
ctx.fillText(lowerText, Math.round(x + unitWidth / 2), Math.round(h * 0.7));
|
|
782
820
|
ctx.beginPath();
|
|
@@ -928,6 +966,7 @@ class GanttChart {
|
|
|
928
966
|
}
|
|
929
967
|
// In the drawGrid method
|
|
930
968
|
drawGrid(ctx, startDate, endDate) {
|
|
969
|
+
const separator = this.config.dateSeparator;
|
|
931
970
|
ctx.strokeStyle = "#e6e6e6";
|
|
932
971
|
ctx.lineWidth = 1;
|
|
933
972
|
ctx.beginPath();
|
|
@@ -987,6 +1026,12 @@ class GanttChart {
|
|
|
987
1026
|
const x = this.snap(this.dateToX(currentDate));
|
|
988
1027
|
ctx.moveTo(x, this.scrollTop);
|
|
989
1028
|
ctx.lineTo(x, this.scrollTop + this.viewportHeight);
|
|
1029
|
+
if (this.config.viewMode === "Day") {
|
|
1030
|
+
if ([0, 6].includes(currentDate.getDay()) || this.holidaysMap.has(DateUtils.format(currentDate, `yyyy${separator}MM${separator}dd`))) {
|
|
1031
|
+
ctx.fillStyle = this.config.weekendBgColor;
|
|
1032
|
+
ctx.fillRect(x + 1, this.scrollTop, Math.round(this.pixelsPerDay - 1), Math.round(this.scrollTop + this.viewportHeight));
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
990
1035
|
switch (this.config.viewMode) {
|
|
991
1036
|
case "Day":
|
|
992
1037
|
nextDate = DateUtils.addDays(currentDate, 1);
|
package/dist/index.umd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* gantt-canvas-chart v1.
|
|
2
|
+
* gantt-canvas-chart v1.6.1
|
|
3
3
|
* (c) 2025-present chandq
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -11,24 +11,35 @@
|
|
|
11
11
|
class DateUtils {
|
|
12
12
|
static ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
13
13
|
static format(date, format = "yyyy-MM-dd") {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
"
|
|
14
|
+
let fmt = format;
|
|
15
|
+
let ret;
|
|
16
|
+
const opt = {
|
|
17
|
+
"Y+": `${date.getFullYear()}`,
|
|
18
|
+
// 年
|
|
19
|
+
"y+": `${date.getFullYear()}`,
|
|
20
|
+
// 年
|
|
21
|
+
"M+": `${date.getMonth() + 1}`,
|
|
22
|
+
// 月
|
|
23
|
+
"D+": `${date.getDate()}`,
|
|
24
|
+
// 日
|
|
25
|
+
"d+": `${date.getDate()}`,
|
|
26
|
+
// 日
|
|
27
|
+
"h+": `${date.getHours()}`,
|
|
28
|
+
// 时
|
|
29
|
+
"m+": `${date.getMinutes()}`,
|
|
30
|
+
// 分
|
|
31
|
+
"s+": `${date.getSeconds()}`,
|
|
32
|
+
// 秒
|
|
20
33
|
"q+": Math.floor((date.getMonth() + 3) / 3),
|
|
21
34
|
W: ["日", "一", "二", "三", "四", "五", "六"][date.getDay()]
|
|
22
35
|
};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
);
|
|
31
|
-
return format;
|
|
36
|
+
for (const k in opt) {
|
|
37
|
+
ret = new RegExp("(" + k + ")").exec(fmt);
|
|
38
|
+
if (ret) {
|
|
39
|
+
fmt = fmt.replace(ret[1], ret[1].length === 1 ? opt[k] : opt[k].padStart(ret[1].length, "0"));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return fmt;
|
|
32
43
|
}
|
|
33
44
|
static addDays(date, days) {
|
|
34
45
|
const r = new Date(date);
|
|
@@ -148,6 +159,7 @@
|
|
|
148
159
|
resizeObserver;
|
|
149
160
|
taskPositions;
|
|
150
161
|
taskMap;
|
|
162
|
+
holidaysMap;
|
|
151
163
|
isLoadingData = false;
|
|
152
164
|
hasMoreDataLeft = true;
|
|
153
165
|
hasMoreDataRight = true;
|
|
@@ -196,6 +208,9 @@
|
|
|
196
208
|
tooltipFormat: null,
|
|
197
209
|
tooltipColor: "black",
|
|
198
210
|
todayColor: "#ff4d4f",
|
|
211
|
+
weekendBgColor: "#f7f7f7",
|
|
212
|
+
holidays: [],
|
|
213
|
+
dateSeparator: "/",
|
|
199
214
|
offsetTop: 0,
|
|
200
215
|
offsetLeft: 0,
|
|
201
216
|
scrollEdgeThresholds: 10,
|
|
@@ -234,6 +249,7 @@
|
|
|
234
249
|
this.totalHeight = 0;
|
|
235
250
|
this.taskPositions = /* @__PURE__ */ new Map();
|
|
236
251
|
this.taskMap = /* @__PURE__ */ new Map();
|
|
252
|
+
this.holidaysMap = /* @__PURE__ */ new Map();
|
|
237
253
|
this.handleMouseMove = this.handleMouseMove.bind(this);
|
|
238
254
|
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
|
239
255
|
this.handleScroll = this.handleScroll.bind(this);
|
|
@@ -243,6 +259,9 @@
|
|
|
243
259
|
this.init();
|
|
244
260
|
}
|
|
245
261
|
init() {
|
|
262
|
+
if (this.config.holidays.length > 0) {
|
|
263
|
+
this.buildHolidaysMap();
|
|
264
|
+
}
|
|
246
265
|
this.buildTaskMap();
|
|
247
266
|
this.updatePixelsPerDay();
|
|
248
267
|
this.calculateFullTimeline();
|
|
@@ -291,10 +310,26 @@
|
|
|
291
310
|
this.updatePixelsPerDay();
|
|
292
311
|
this.calculateFullTimeline();
|
|
293
312
|
}
|
|
313
|
+
if (this.config.holidays.length !== this.holidaysMap.size) {
|
|
314
|
+
this.buildHolidaysMap();
|
|
315
|
+
}
|
|
294
316
|
this.updateLoadMoreConf();
|
|
295
317
|
this.updateDimensions();
|
|
296
318
|
this.render();
|
|
297
319
|
}
|
|
320
|
+
buildHolidaysMap() {
|
|
321
|
+
this.holidaysMap.clear();
|
|
322
|
+
const separator = this.config.dateSeparator;
|
|
323
|
+
if (this.config.holidays && this.config.holidays.length > 0 && this.config.holidays[0].includes(separator)) {
|
|
324
|
+
this.config.holidays.forEach((holiday) => {
|
|
325
|
+
this.holidaysMap.set(holiday, true);
|
|
326
|
+
});
|
|
327
|
+
} else {
|
|
328
|
+
this.config.holidays.forEach((holiday) => {
|
|
329
|
+
this.holidaysMap.set(DateUtils.format(new Date(holiday), `yyyy${separator}MM${separator}dd`), true);
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
298
333
|
setData(newData, newConfig) {
|
|
299
334
|
this.data = newData;
|
|
300
335
|
this.buildTaskMap();
|
|
@@ -309,6 +344,7 @@
|
|
|
309
344
|
destroy() {
|
|
310
345
|
if (this.resizeObserver) {
|
|
311
346
|
this.resizeObserver.disconnect();
|
|
347
|
+
this.resizeObserver = null;
|
|
312
348
|
}
|
|
313
349
|
this.container.removeEventListener("scroll", this.handleScroll);
|
|
314
350
|
this.mainCanvas.removeEventListener("mousemove", this.handleMouseMove);
|
|
@@ -316,6 +352,8 @@
|
|
|
316
352
|
this.data = [];
|
|
317
353
|
this.taskMap.clear();
|
|
318
354
|
this.taskPositions.clear();
|
|
355
|
+
this.holidaysMap.clear();
|
|
356
|
+
this.config.holidays = [];
|
|
319
357
|
this.container.remove();
|
|
320
358
|
}
|
|
321
359
|
calculateFullTimeline() {
|
|
@@ -732,7 +770,7 @@
|
|
|
732
770
|
}
|
|
733
771
|
const groupedBlocks = this.groupConsecutiveBlocks(visibleBlocks);
|
|
734
772
|
ctx.fillStyle = "#333";
|
|
735
|
-
ctx.font = "bold
|
|
773
|
+
ctx.font = "bold 12px Roboto,PingFang SC,Noto Sans SC,Microsoft YaHei UI,Microsoft YaHei,Segoe UI,Helvetica Neue,Helvetica,Arial,sans-serif";
|
|
736
774
|
ctx.textAlign = "left";
|
|
737
775
|
groupedBlocks.forEach((group) => {
|
|
738
776
|
const visibleStart = Math.max(group.startX, this.scrollLeft);
|
|
@@ -741,7 +779,7 @@
|
|
|
741
779
|
ctx.fillStyle = this.config.headerBgColor;
|
|
742
780
|
ctx.fillRect(Math.round(visibleStart), 0, Math.round(visibleEnd - visibleStart), Math.round(h * 0.5));
|
|
743
781
|
ctx.fillStyle = "#333";
|
|
744
|
-
ctx.fillText(group.text, Math.round(visibleStart + 5), Math.round(group.yPos));
|
|
782
|
+
ctx.fillText(group.text, Math.round(visibleStart + 5), Math.round(group.yPos - 3));
|
|
745
783
|
}
|
|
746
784
|
});
|
|
747
785
|
while (currentDateForLower <= this.visibleDateRange.end) {
|
|
@@ -780,7 +818,7 @@
|
|
|
780
818
|
}
|
|
781
819
|
const unitWidth = this.dateToX(nextDate) - x;
|
|
782
820
|
ctx.fillStyle = "#000412";
|
|
783
|
-
ctx.font = "
|
|
821
|
+
ctx.font = "12px Roboto,PingFang SC,Noto Sans SC,Microsoft YaHei UI,Microsoft YaHei,Segoe UI,Helvetica Neue,Helvetica,Arial,sans-serif";
|
|
784
822
|
ctx.textAlign = "center";
|
|
785
823
|
ctx.fillText(lowerText, Math.round(x + unitWidth / 2), Math.round(h * 0.7));
|
|
786
824
|
ctx.beginPath();
|
|
@@ -932,6 +970,7 @@
|
|
|
932
970
|
}
|
|
933
971
|
// In the drawGrid method
|
|
934
972
|
drawGrid(ctx, startDate, endDate) {
|
|
973
|
+
const separator = this.config.dateSeparator;
|
|
935
974
|
ctx.strokeStyle = "#e6e6e6";
|
|
936
975
|
ctx.lineWidth = 1;
|
|
937
976
|
ctx.beginPath();
|
|
@@ -991,6 +1030,12 @@
|
|
|
991
1030
|
const x = this.snap(this.dateToX(currentDate));
|
|
992
1031
|
ctx.moveTo(x, this.scrollTop);
|
|
993
1032
|
ctx.lineTo(x, this.scrollTop + this.viewportHeight);
|
|
1033
|
+
if (this.config.viewMode === "Day") {
|
|
1034
|
+
if ([0, 6].includes(currentDate.getDay()) || this.holidaysMap.has(DateUtils.format(currentDate, `yyyy${separator}MM${separator}dd`))) {
|
|
1035
|
+
ctx.fillStyle = this.config.weekendBgColor;
|
|
1036
|
+
ctx.fillRect(x + 1, this.scrollTop, Math.round(this.pixelsPerDay - 1), Math.round(this.scrollTop + this.viewportHeight));
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
994
1039
|
switch (this.config.viewMode) {
|
|
995
1040
|
case "Day":
|
|
996
1041
|
nextDate = DateUtils.addDays(currentDate, 1);
|