gantt-canvas-chart 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * gantt-canvas-chart v1.0.1
2
+ * gantt-canvas-chart v1.1.0
3
3
  * (c) 2025-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -95,6 +95,8 @@ class GanttChart {
95
95
  mainCtx;
96
96
  timelineStart;
97
97
  timelineEnd;
98
+ minDate;
99
+ // private maxDate: Date | null;
98
100
  pixelsPerDay;
99
101
  scrollLeft;
100
102
  scrollTop;
@@ -147,8 +149,8 @@ class GanttChart {
147
149
  offsetTop: 0,
148
150
  offsetLeft: 0,
149
151
  viewFactors: { Day: 80, Week: 20, Month: 15, Year: 6 },
150
- planBorderColor: "#caeed2",
151
- actualBgColor: "#78c78f",
152
+ planBorderColor: "#C1EFCF",
153
+ actualBgColor: "#5AC989",
152
154
  ...config
153
155
  };
154
156
  this.headerCanvas = headerCanvas;
@@ -163,6 +165,7 @@ class GanttChart {
163
165
  this.mainCtx = this.mainCanvas.getContext("2d");
164
166
  this.timelineStart = /* @__PURE__ */ new Date();
165
167
  this.timelineEnd = /* @__PURE__ */ new Date();
168
+ this.minDate = null;
166
169
  this.pixelsPerDay = 40;
167
170
  this.scrollLeft = 0;
168
171
  this.scrollTop = 0;
@@ -178,6 +181,7 @@ class GanttChart {
178
181
  this.boundHandleMouseMove = this.handleMouseMove.bind(this);
179
182
  this.boundHandleMouseLeave = this.handleMouseLeave.bind(this);
180
183
  this.boundHandleScroll = this.handleScroll.bind(this);
184
+ this.scrollToStartDate = this.scrollToStartDate.bind(this);
181
185
  this.init();
182
186
  }
183
187
  init() {
@@ -218,12 +222,16 @@ class GanttChart {
218
222
  this.updateDimensions();
219
223
  this.render();
220
224
  }
221
- setData(newData) {
225
+ setData(newData, newConfig) {
222
226
  this.data = newData;
223
227
  this.buildTaskMap();
224
- this.calculateFullTimeline();
225
- this.updateDimensions();
226
- this.render();
228
+ if (newConfig) {
229
+ this.updateConfig(newConfig);
230
+ } else {
231
+ this.calculateFullTimeline();
232
+ this.updateDimensions();
233
+ this.render();
234
+ }
227
235
  }
228
236
  destroy() {
229
237
  if (this.resizeObserver) {
@@ -254,6 +262,7 @@ class GanttChart {
254
262
  }
255
263
  });
256
264
  }
265
+ this.minDate = minDate;
257
266
  minDate = DateUtils.addDays(minDate, -7);
258
267
  maxDate = DateUtils.addDays(maxDate, 14);
259
268
  switch (this.config.viewMode) {
@@ -289,8 +298,8 @@ class GanttChart {
289
298
  this.viewportWidth = this.container.clientWidth;
290
299
  this.viewportHeight = this.container.clientHeight;
291
300
  this.mainCanvas.style.top = `${this.config.headerHeight}px`;
292
- this.setupCanvas(this.headerCanvas, this.viewportWidth, this.config.headerHeight);
293
- this.setupCanvas(this.mainCanvas, this.viewportWidth, this.viewportHeight - this.config.headerHeight);
301
+ this.headerCtx = this.setupCanvas(this.headerCanvas, this.viewportWidth, this.config.headerHeight);
302
+ this.mainCtx = this.setupCanvas(this.mainCanvas, this.viewportWidth, this.viewportHeight - this.config.headerHeight);
294
303
  this.updateDimensions();
295
304
  this.render();
296
305
  }
@@ -328,6 +337,7 @@ class GanttChart {
328
337
  canvas.style.height = `${height}px`;
329
338
  const ctx = canvas.getContext("2d");
330
339
  ctx.scale(this.devicePixelRatio, this.devicePixelRatio);
340
+ return ctx;
331
341
  }
332
342
  calculateAllTaskPositions() {
333
343
  this.taskPositions.clear();
@@ -383,6 +393,7 @@ class GanttChart {
383
393
  ctx.fillStyle = "#f9f9f9";
384
394
  ctx.fillRect(this.scrollLeft, 0, this.viewportWidth, h);
385
395
  ctx.textBaseline = "middle";
396
+ ctx.textRendering = "optimizeLegibility";
386
397
  let currentDate = new Date(this.visibleDateRange.start);
387
398
  currentDate = this.getIterationStartDate(currentDate);
388
399
  let lastUpperText = "";
@@ -449,15 +460,16 @@ class GanttChart {
449
460
  const unitWidth = this.dateToX(nextDate) - x;
450
461
  if (upperText !== lastUpperText) {
451
462
  ctx.fillStyle = "#333";
452
- ctx.font = "bold 13px sans-serif";
463
+ ctx.font = 'bold 14px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
464
+ ctx.textRendering = "optimizeLegibility";
453
465
  ctx.textAlign = "left";
454
466
  ctx.fillText(upperText, x + 5, h * 0.35);
455
467
  lastUpperText = upperText;
456
468
  }
457
- ctx.fillStyle = "#666";
458
- ctx.font = "12px sans-serif";
469
+ ctx.fillStyle = "#000412";
470
+ ctx.font = '14px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
459
471
  ctx.textAlign = "center";
460
- ctx.fillText(lowerText, x + unitWidth / 2, h * 0.7);
472
+ ctx.fillText(lowerText, Math.round(x + unitWidth / 2), Math.round(h * 0.7));
461
473
  ctx.beginPath();
462
474
  ctx.moveTo(x, h * 0.5);
463
475
  ctx.lineTo(x, h);
@@ -569,7 +581,9 @@ class GanttChart {
569
581
  }
570
582
  drawAllTasks(ctx) {
571
583
  ctx.textBaseline = "middle";
572
- ctx.font = "12px Arial";
584
+ ctx.font = '12px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
585
+ ctx.textRendering = "optimizeSpeed";
586
+ ctx.imageSmoothingEnabled = false;
573
587
  for (let i = 0; i < this.data.length; i++) {
574
588
  const row = this.data[i];
575
589
  const y = i * this.config.rowHeight;
@@ -586,7 +600,7 @@ class GanttChart {
586
600
  }
587
601
  }
588
602
  drawGrid(ctx, startDate, endDate) {
589
- ctx.strokeStyle = "#f0f0f0";
603
+ ctx.strokeStyle = "#e6e6e6";
590
604
  ctx.lineWidth = 1;
591
605
  ctx.beginPath();
592
606
  if (this.config.showRowLines) {
@@ -689,7 +703,7 @@ class GanttChart {
689
703
  const aWidth = (pos.x_actual_end ? pos.x_actual_end : this.dateToX(this.today)) - pos.x_actual_start;
690
704
  pos.x_actual_start += aWidth * offsetX_actual;
691
705
  pos.x_actual_end && (pos.x_actual_end = pos.x_actual_start + aWidth * percent_actual);
692
- ctx.fillRect(pos.x_actual_start, taskY, aWidth * percent_actual, taskHeight);
706
+ ctx.fillRect(Math.round(pos.x_actual_start), Math.round(taskY + 2), Math.round(aWidth * percent_actual), Math.round(taskHeight - 2));
693
707
  }
694
708
  if (this.config.showPlan && pos.x_plan_start && pos.x_plan_end) {
695
709
  ctx.strokeStyle = task.planBorderColor ? task.planBorderColor : this.config.planBorderColor;
@@ -701,19 +715,19 @@ class GanttChart {
701
715
  ctx.lineTo(pos.x_plan_start + width * percent_plan, taskY);
702
716
  ctx.stroke();
703
717
  }
704
- ctx.fillStyle = "#333";
718
+ ctx.fillStyle = "#000";
705
719
  if (this.config.showLeftRemark && task.leftRemark) {
706
720
  ctx.textAlign = "right";
707
- ctx.fillText(task.leftRemark, Math.min(...[pos.x_plan_start, pos.x_actual_start].filter((val) => val !== null && val !== void 0)) - 8, textY);
721
+ ctx.fillText(task.leftRemark, Math.round(Math.min(...[pos.x_plan_start, pos.x_actual_start].filter((val) => val !== null && val !== void 0)) - 8), Math.round(textY));
708
722
  }
709
723
  if (this.config.showRightRemark && task.rightRemark) {
710
724
  ctx.textAlign = "left";
711
- ctx.fillText(task.rightRemark, Math.max(...[pos.x_plan_end, pos.x_actual_end].filter((val) => val !== null && val !== void 0)) + 8, textY);
725
+ ctx.fillText(task.rightRemark, Math.round(Math.max(...[pos.x_plan_end, pos.x_actual_end].filter((val) => val !== null && val !== void 0)) + 8), Math.round(textY));
712
726
  }
713
727
  if (this.config.showCenterRemark && task.centerRemark) {
714
728
  const centerX = pos.x_actual_start + (pos.x_actual_end - pos.x_actual_start) / 2;
715
729
  ctx.textAlign = "center";
716
- ctx.fillText(task.centerRemark, centerX, textY, pos.x_actual_end - pos.x_actual_start);
730
+ ctx.fillText(task.centerRemark, Math.round(centerX), Math.round(textY), Math.round(pos.x_actual_end - pos.x_actual_start));
717
731
  }
718
732
  }
719
733
  getTaskStyles(task) {
@@ -807,6 +821,18 @@ class GanttChart {
807
821
  static getTaskWidthPercent(diffMilliseconds, pixelsPerDay) {
808
822
  return diffMilliseconds * pixelsPerDay / DateUtils.ONE_DAY_MS;
809
823
  }
824
+ /**
825
+ * scroll to specified date position, default to minDate
826
+ *
827
+ * @param date
828
+ */
829
+ scrollToStartDate(date) {
830
+ const startDate = date ? date : this.minDate;
831
+ if (startDate) {
832
+ const xPosition = this.dateToX(startDate);
833
+ this.container.scrollTo({ left: xPosition - 80 });
834
+ }
835
+ }
810
836
  }
811
837
  exports.DateUtils = DateUtils;
812
838
  exports.GanttChart = GanttChart;
package/dist/index.css CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * gantt-canvas-chart v1.0.1
2
+ * gantt-canvas-chart v1.1.0
3
3
  * (c) 2025-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -10,6 +10,7 @@
10
10
  overflow: hidden;
11
11
  position: relative;
12
12
  background: white;
13
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
13
14
  }
14
15
 
15
16
  .__gantt-chart-container {
@@ -18,6 +19,7 @@
18
19
  position: relative;
19
20
  background: #ffffff;
20
21
  height: 100%;
22
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
21
23
  }
22
24
 
23
25
  .__gantt-scroll-dummy {
@@ -37,6 +39,7 @@
37
39
  z-index: 10;
38
40
  background: #f8fafc;
39
41
  border-bottom: 1px solid #e2e8f0;
42
+ text-rendering: optimizeSpeed;
40
43
  }
41
44
 
42
45
  .__gantt-main-canvas {
@@ -44,6 +47,26 @@
44
47
  top: 56px; /* Corresponds to header height */
45
48
  left: 0;
46
49
  z-index: 1;
50
+ text-rendering: optimizeSpeed;
51
+ }
52
+
53
+ /* Add to your CSS file or create a stylesheet */
54
+ .__gantt-chart-container {
55
+ transform: translateZ(0); /* Force hardware acceleration */
56
+ -webkit-font-smoothing: antialiased;
57
+ -moz-osx-font-smoothing: grayscale;
58
+ text-rendering: optimizeLegibility;
59
+ }
60
+
61
+ .__gantt-header-canvas,
62
+ .__gantt-main-canvas {
63
+ image-rendering: -webkit-optimize-contrast;
64
+ image-rendering: crisp-edges;
65
+ shape-rendering: crispEdges;
66
+ /* Add font rendering optimizations */
67
+ -webkit-font-smoothing: antialiased;
68
+ -moz-osx-font-smoothing: grayscale;
69
+ text-rendering: optimizeSpeed;
47
70
  }
48
71
 
49
72
  /* Tooltip */
@@ -33,6 +33,7 @@ export declare class GanttChart {
33
33
  private mainCtx;
34
34
  private timelineStart;
35
35
  private timelineEnd;
36
+ private minDate;
36
37
  private pixelsPerDay;
37
38
  private scrollLeft;
38
39
  private scrollTop;
@@ -54,7 +55,7 @@ export declare class GanttChart {
54
55
  private buildTaskMap;
55
56
  private setupEvents;
56
57
  updateConfig(newConfig: GanttConfig): void;
57
- setData(newData: GanttData): void;
58
+ setData(newData: GanttData, newConfig?: GanttConfig): void;
58
59
  destroy(): void;
59
60
  private calculateFullTimeline;
60
61
  private updatePixelsPerDay;
@@ -88,6 +89,12 @@ export declare class GanttChart {
88
89
  * @returns
89
90
  */
90
91
  static getTaskWidthPercent(diffMilliseconds: number, pixelsPerDay: number): number;
92
+ /**
93
+ * scroll to specified date position, default to minDate
94
+ *
95
+ * @param date
96
+ */
97
+ scrollToStartDate(date?: Date): void;
91
98
  }
92
99
 
93
100
  declare interface GanttConfig {
package/dist/index.es.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * gantt-canvas-chart v1.0.1
2
+ * gantt-canvas-chart v1.1.0
3
3
  * (c) 2025-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -93,6 +93,8 @@ class GanttChart {
93
93
  mainCtx;
94
94
  timelineStart;
95
95
  timelineEnd;
96
+ minDate;
97
+ // private maxDate: Date | null;
96
98
  pixelsPerDay;
97
99
  scrollLeft;
98
100
  scrollTop;
@@ -145,8 +147,8 @@ class GanttChart {
145
147
  offsetTop: 0,
146
148
  offsetLeft: 0,
147
149
  viewFactors: { Day: 80, Week: 20, Month: 15, Year: 6 },
148
- planBorderColor: "#caeed2",
149
- actualBgColor: "#78c78f",
150
+ planBorderColor: "#C1EFCF",
151
+ actualBgColor: "#5AC989",
150
152
  ...config
151
153
  };
152
154
  this.headerCanvas = headerCanvas;
@@ -161,6 +163,7 @@ class GanttChart {
161
163
  this.mainCtx = this.mainCanvas.getContext("2d");
162
164
  this.timelineStart = /* @__PURE__ */ new Date();
163
165
  this.timelineEnd = /* @__PURE__ */ new Date();
166
+ this.minDate = null;
164
167
  this.pixelsPerDay = 40;
165
168
  this.scrollLeft = 0;
166
169
  this.scrollTop = 0;
@@ -176,6 +179,7 @@ class GanttChart {
176
179
  this.boundHandleMouseMove = this.handleMouseMove.bind(this);
177
180
  this.boundHandleMouseLeave = this.handleMouseLeave.bind(this);
178
181
  this.boundHandleScroll = this.handleScroll.bind(this);
182
+ this.scrollToStartDate = this.scrollToStartDate.bind(this);
179
183
  this.init();
180
184
  }
181
185
  init() {
@@ -216,12 +220,16 @@ class GanttChart {
216
220
  this.updateDimensions();
217
221
  this.render();
218
222
  }
219
- setData(newData) {
223
+ setData(newData, newConfig) {
220
224
  this.data = newData;
221
225
  this.buildTaskMap();
222
- this.calculateFullTimeline();
223
- this.updateDimensions();
224
- this.render();
226
+ if (newConfig) {
227
+ this.updateConfig(newConfig);
228
+ } else {
229
+ this.calculateFullTimeline();
230
+ this.updateDimensions();
231
+ this.render();
232
+ }
225
233
  }
226
234
  destroy() {
227
235
  if (this.resizeObserver) {
@@ -252,6 +260,7 @@ class GanttChart {
252
260
  }
253
261
  });
254
262
  }
263
+ this.minDate = minDate;
255
264
  minDate = DateUtils.addDays(minDate, -7);
256
265
  maxDate = DateUtils.addDays(maxDate, 14);
257
266
  switch (this.config.viewMode) {
@@ -287,8 +296,8 @@ class GanttChart {
287
296
  this.viewportWidth = this.container.clientWidth;
288
297
  this.viewportHeight = this.container.clientHeight;
289
298
  this.mainCanvas.style.top = `${this.config.headerHeight}px`;
290
- this.setupCanvas(this.headerCanvas, this.viewportWidth, this.config.headerHeight);
291
- this.setupCanvas(this.mainCanvas, this.viewportWidth, this.viewportHeight - this.config.headerHeight);
299
+ this.headerCtx = this.setupCanvas(this.headerCanvas, this.viewportWidth, this.config.headerHeight);
300
+ this.mainCtx = this.setupCanvas(this.mainCanvas, this.viewportWidth, this.viewportHeight - this.config.headerHeight);
292
301
  this.updateDimensions();
293
302
  this.render();
294
303
  }
@@ -326,6 +335,7 @@ class GanttChart {
326
335
  canvas.style.height = `${height}px`;
327
336
  const ctx = canvas.getContext("2d");
328
337
  ctx.scale(this.devicePixelRatio, this.devicePixelRatio);
338
+ return ctx;
329
339
  }
330
340
  calculateAllTaskPositions() {
331
341
  this.taskPositions.clear();
@@ -381,6 +391,7 @@ class GanttChart {
381
391
  ctx.fillStyle = "#f9f9f9";
382
392
  ctx.fillRect(this.scrollLeft, 0, this.viewportWidth, h);
383
393
  ctx.textBaseline = "middle";
394
+ ctx.textRendering = "optimizeLegibility";
384
395
  let currentDate = new Date(this.visibleDateRange.start);
385
396
  currentDate = this.getIterationStartDate(currentDate);
386
397
  let lastUpperText = "";
@@ -447,15 +458,16 @@ class GanttChart {
447
458
  const unitWidth = this.dateToX(nextDate) - x;
448
459
  if (upperText !== lastUpperText) {
449
460
  ctx.fillStyle = "#333";
450
- ctx.font = "bold 13px sans-serif";
461
+ ctx.font = 'bold 14px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
462
+ ctx.textRendering = "optimizeLegibility";
451
463
  ctx.textAlign = "left";
452
464
  ctx.fillText(upperText, x + 5, h * 0.35);
453
465
  lastUpperText = upperText;
454
466
  }
455
- ctx.fillStyle = "#666";
456
- ctx.font = "12px sans-serif";
467
+ ctx.fillStyle = "#000412";
468
+ ctx.font = '14px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
457
469
  ctx.textAlign = "center";
458
- ctx.fillText(lowerText, x + unitWidth / 2, h * 0.7);
470
+ ctx.fillText(lowerText, Math.round(x + unitWidth / 2), Math.round(h * 0.7));
459
471
  ctx.beginPath();
460
472
  ctx.moveTo(x, h * 0.5);
461
473
  ctx.lineTo(x, h);
@@ -567,7 +579,9 @@ class GanttChart {
567
579
  }
568
580
  drawAllTasks(ctx) {
569
581
  ctx.textBaseline = "middle";
570
- ctx.font = "12px Arial";
582
+ ctx.font = '12px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
583
+ ctx.textRendering = "optimizeSpeed";
584
+ ctx.imageSmoothingEnabled = false;
571
585
  for (let i = 0; i < this.data.length; i++) {
572
586
  const row = this.data[i];
573
587
  const y = i * this.config.rowHeight;
@@ -584,7 +598,7 @@ class GanttChart {
584
598
  }
585
599
  }
586
600
  drawGrid(ctx, startDate, endDate) {
587
- ctx.strokeStyle = "#f0f0f0";
601
+ ctx.strokeStyle = "#e6e6e6";
588
602
  ctx.lineWidth = 1;
589
603
  ctx.beginPath();
590
604
  if (this.config.showRowLines) {
@@ -687,7 +701,7 @@ class GanttChart {
687
701
  const aWidth = (pos.x_actual_end ? pos.x_actual_end : this.dateToX(this.today)) - pos.x_actual_start;
688
702
  pos.x_actual_start += aWidth * offsetX_actual;
689
703
  pos.x_actual_end && (pos.x_actual_end = pos.x_actual_start + aWidth * percent_actual);
690
- ctx.fillRect(pos.x_actual_start, taskY, aWidth * percent_actual, taskHeight);
704
+ ctx.fillRect(Math.round(pos.x_actual_start), Math.round(taskY + 2), Math.round(aWidth * percent_actual), Math.round(taskHeight - 2));
691
705
  }
692
706
  if (this.config.showPlan && pos.x_plan_start && pos.x_plan_end) {
693
707
  ctx.strokeStyle = task.planBorderColor ? task.planBorderColor : this.config.planBorderColor;
@@ -699,19 +713,19 @@ class GanttChart {
699
713
  ctx.lineTo(pos.x_plan_start + width * percent_plan, taskY);
700
714
  ctx.stroke();
701
715
  }
702
- ctx.fillStyle = "#333";
716
+ ctx.fillStyle = "#000";
703
717
  if (this.config.showLeftRemark && task.leftRemark) {
704
718
  ctx.textAlign = "right";
705
- ctx.fillText(task.leftRemark, Math.min(...[pos.x_plan_start, pos.x_actual_start].filter((val) => val !== null && val !== void 0)) - 8, textY);
719
+ ctx.fillText(task.leftRemark, Math.round(Math.min(...[pos.x_plan_start, pos.x_actual_start].filter((val) => val !== null && val !== void 0)) - 8), Math.round(textY));
706
720
  }
707
721
  if (this.config.showRightRemark && task.rightRemark) {
708
722
  ctx.textAlign = "left";
709
- ctx.fillText(task.rightRemark, Math.max(...[pos.x_plan_end, pos.x_actual_end].filter((val) => val !== null && val !== void 0)) + 8, textY);
723
+ ctx.fillText(task.rightRemark, Math.round(Math.max(...[pos.x_plan_end, pos.x_actual_end].filter((val) => val !== null && val !== void 0)) + 8), Math.round(textY));
710
724
  }
711
725
  if (this.config.showCenterRemark && task.centerRemark) {
712
726
  const centerX = pos.x_actual_start + (pos.x_actual_end - pos.x_actual_start) / 2;
713
727
  ctx.textAlign = "center";
714
- ctx.fillText(task.centerRemark, centerX, textY, pos.x_actual_end - pos.x_actual_start);
728
+ ctx.fillText(task.centerRemark, Math.round(centerX), Math.round(textY), Math.round(pos.x_actual_end - pos.x_actual_start));
715
729
  }
716
730
  }
717
731
  getTaskStyles(task) {
@@ -805,6 +819,18 @@ class GanttChart {
805
819
  static getTaskWidthPercent(diffMilliseconds, pixelsPerDay) {
806
820
  return diffMilliseconds * pixelsPerDay / DateUtils.ONE_DAY_MS;
807
821
  }
822
+ /**
823
+ * scroll to specified date position, default to minDate
824
+ *
825
+ * @param date
826
+ */
827
+ scrollToStartDate(date) {
828
+ const startDate = date ? date : this.minDate;
829
+ if (startDate) {
830
+ const xPosition = this.dateToX(startDate);
831
+ this.container.scrollTo({ left: xPosition - 80 });
832
+ }
833
+ }
808
834
  }
809
835
  export {
810
836
  DateUtils,
package/dist/index.umd.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * gantt-canvas-chart v1.0.1
2
+ * gantt-canvas-chart v1.1.0
3
3
  * (c) 2025-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -97,6 +97,8 @@
97
97
  mainCtx;
98
98
  timelineStart;
99
99
  timelineEnd;
100
+ minDate;
101
+ // private maxDate: Date | null;
100
102
  pixelsPerDay;
101
103
  scrollLeft;
102
104
  scrollTop;
@@ -149,8 +151,8 @@
149
151
  offsetTop: 0,
150
152
  offsetLeft: 0,
151
153
  viewFactors: { Day: 80, Week: 20, Month: 15, Year: 6 },
152
- planBorderColor: "#caeed2",
153
- actualBgColor: "#78c78f",
154
+ planBorderColor: "#C1EFCF",
155
+ actualBgColor: "#5AC989",
154
156
  ...config
155
157
  };
156
158
  this.headerCanvas = headerCanvas;
@@ -165,6 +167,7 @@
165
167
  this.mainCtx = this.mainCanvas.getContext("2d");
166
168
  this.timelineStart = /* @__PURE__ */ new Date();
167
169
  this.timelineEnd = /* @__PURE__ */ new Date();
170
+ this.minDate = null;
168
171
  this.pixelsPerDay = 40;
169
172
  this.scrollLeft = 0;
170
173
  this.scrollTop = 0;
@@ -180,6 +183,7 @@
180
183
  this.boundHandleMouseMove = this.handleMouseMove.bind(this);
181
184
  this.boundHandleMouseLeave = this.handleMouseLeave.bind(this);
182
185
  this.boundHandleScroll = this.handleScroll.bind(this);
186
+ this.scrollToStartDate = this.scrollToStartDate.bind(this);
183
187
  this.init();
184
188
  }
185
189
  init() {
@@ -220,12 +224,16 @@
220
224
  this.updateDimensions();
221
225
  this.render();
222
226
  }
223
- setData(newData) {
227
+ setData(newData, newConfig) {
224
228
  this.data = newData;
225
229
  this.buildTaskMap();
226
- this.calculateFullTimeline();
227
- this.updateDimensions();
228
- this.render();
230
+ if (newConfig) {
231
+ this.updateConfig(newConfig);
232
+ } else {
233
+ this.calculateFullTimeline();
234
+ this.updateDimensions();
235
+ this.render();
236
+ }
229
237
  }
230
238
  destroy() {
231
239
  if (this.resizeObserver) {
@@ -256,6 +264,7 @@
256
264
  }
257
265
  });
258
266
  }
267
+ this.minDate = minDate;
259
268
  minDate = DateUtils.addDays(minDate, -7);
260
269
  maxDate = DateUtils.addDays(maxDate, 14);
261
270
  switch (this.config.viewMode) {
@@ -291,8 +300,8 @@
291
300
  this.viewportWidth = this.container.clientWidth;
292
301
  this.viewportHeight = this.container.clientHeight;
293
302
  this.mainCanvas.style.top = `${this.config.headerHeight}px`;
294
- this.setupCanvas(this.headerCanvas, this.viewportWidth, this.config.headerHeight);
295
- this.setupCanvas(this.mainCanvas, this.viewportWidth, this.viewportHeight - this.config.headerHeight);
303
+ this.headerCtx = this.setupCanvas(this.headerCanvas, this.viewportWidth, this.config.headerHeight);
304
+ this.mainCtx = this.setupCanvas(this.mainCanvas, this.viewportWidth, this.viewportHeight - this.config.headerHeight);
296
305
  this.updateDimensions();
297
306
  this.render();
298
307
  }
@@ -330,6 +339,7 @@
330
339
  canvas.style.height = `${height}px`;
331
340
  const ctx = canvas.getContext("2d");
332
341
  ctx.scale(this.devicePixelRatio, this.devicePixelRatio);
342
+ return ctx;
333
343
  }
334
344
  calculateAllTaskPositions() {
335
345
  this.taskPositions.clear();
@@ -385,6 +395,7 @@
385
395
  ctx.fillStyle = "#f9f9f9";
386
396
  ctx.fillRect(this.scrollLeft, 0, this.viewportWidth, h);
387
397
  ctx.textBaseline = "middle";
398
+ ctx.textRendering = "optimizeLegibility";
388
399
  let currentDate = new Date(this.visibleDateRange.start);
389
400
  currentDate = this.getIterationStartDate(currentDate);
390
401
  let lastUpperText = "";
@@ -451,15 +462,16 @@
451
462
  const unitWidth = this.dateToX(nextDate) - x;
452
463
  if (upperText !== lastUpperText) {
453
464
  ctx.fillStyle = "#333";
454
- ctx.font = "bold 13px sans-serif";
465
+ ctx.font = 'bold 14px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
466
+ ctx.textRendering = "optimizeLegibility";
455
467
  ctx.textAlign = "left";
456
468
  ctx.fillText(upperText, x + 5, h * 0.35);
457
469
  lastUpperText = upperText;
458
470
  }
459
- ctx.fillStyle = "#666";
460
- ctx.font = "12px sans-serif";
471
+ ctx.fillStyle = "#000412";
472
+ ctx.font = '14px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
461
473
  ctx.textAlign = "center";
462
- ctx.fillText(lowerText, x + unitWidth / 2, h * 0.7);
474
+ ctx.fillText(lowerText, Math.round(x + unitWidth / 2), Math.round(h * 0.7));
463
475
  ctx.beginPath();
464
476
  ctx.moveTo(x, h * 0.5);
465
477
  ctx.lineTo(x, h);
@@ -571,7 +583,9 @@
571
583
  }
572
584
  drawAllTasks(ctx) {
573
585
  ctx.textBaseline = "middle";
574
- ctx.font = "12px Arial";
586
+ ctx.font = '12px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
587
+ ctx.textRendering = "optimizeSpeed";
588
+ ctx.imageSmoothingEnabled = false;
575
589
  for (let i = 0; i < this.data.length; i++) {
576
590
  const row = this.data[i];
577
591
  const y = i * this.config.rowHeight;
@@ -588,7 +602,7 @@
588
602
  }
589
603
  }
590
604
  drawGrid(ctx, startDate, endDate) {
591
- ctx.strokeStyle = "#f0f0f0";
605
+ ctx.strokeStyle = "#e6e6e6";
592
606
  ctx.lineWidth = 1;
593
607
  ctx.beginPath();
594
608
  if (this.config.showRowLines) {
@@ -691,7 +705,7 @@
691
705
  const aWidth = (pos.x_actual_end ? pos.x_actual_end : this.dateToX(this.today)) - pos.x_actual_start;
692
706
  pos.x_actual_start += aWidth * offsetX_actual;
693
707
  pos.x_actual_end && (pos.x_actual_end = pos.x_actual_start + aWidth * percent_actual);
694
- ctx.fillRect(pos.x_actual_start, taskY, aWidth * percent_actual, taskHeight);
708
+ ctx.fillRect(Math.round(pos.x_actual_start), Math.round(taskY + 2), Math.round(aWidth * percent_actual), Math.round(taskHeight - 2));
695
709
  }
696
710
  if (this.config.showPlan && pos.x_plan_start && pos.x_plan_end) {
697
711
  ctx.strokeStyle = task.planBorderColor ? task.planBorderColor : this.config.planBorderColor;
@@ -703,19 +717,19 @@
703
717
  ctx.lineTo(pos.x_plan_start + width * percent_plan, taskY);
704
718
  ctx.stroke();
705
719
  }
706
- ctx.fillStyle = "#333";
720
+ ctx.fillStyle = "#000";
707
721
  if (this.config.showLeftRemark && task.leftRemark) {
708
722
  ctx.textAlign = "right";
709
- ctx.fillText(task.leftRemark, Math.min(...[pos.x_plan_start, pos.x_actual_start].filter((val) => val !== null && val !== void 0)) - 8, textY);
723
+ ctx.fillText(task.leftRemark, Math.round(Math.min(...[pos.x_plan_start, pos.x_actual_start].filter((val) => val !== null && val !== void 0)) - 8), Math.round(textY));
710
724
  }
711
725
  if (this.config.showRightRemark && task.rightRemark) {
712
726
  ctx.textAlign = "left";
713
- ctx.fillText(task.rightRemark, Math.max(...[pos.x_plan_end, pos.x_actual_end].filter((val) => val !== null && val !== void 0)) + 8, textY);
727
+ ctx.fillText(task.rightRemark, Math.round(Math.max(...[pos.x_plan_end, pos.x_actual_end].filter((val) => val !== null && val !== void 0)) + 8), Math.round(textY));
714
728
  }
715
729
  if (this.config.showCenterRemark && task.centerRemark) {
716
730
  const centerX = pos.x_actual_start + (pos.x_actual_end - pos.x_actual_start) / 2;
717
731
  ctx.textAlign = "center";
718
- ctx.fillText(task.centerRemark, centerX, textY, pos.x_actual_end - pos.x_actual_start);
732
+ ctx.fillText(task.centerRemark, Math.round(centerX), Math.round(textY), Math.round(pos.x_actual_end - pos.x_actual_start));
719
733
  }
720
734
  }
721
735
  getTaskStyles(task) {
@@ -809,6 +823,18 @@
809
823
  static getTaskWidthPercent(diffMilliseconds, pixelsPerDay) {
810
824
  return diffMilliseconds * pixelsPerDay / DateUtils.ONE_DAY_MS;
811
825
  }
826
+ /**
827
+ * scroll to specified date position, default to minDate
828
+ *
829
+ * @param date
830
+ */
831
+ scrollToStartDate(date) {
832
+ const startDate = date ? date : this.minDate;
833
+ if (startDate) {
834
+ const xPosition = this.dateToX(startDate);
835
+ this.container.scrollTo({ left: xPosition - 80 });
836
+ }
837
+ }
812
838
  }
813
839
  exports2.DateUtils = DateUtils;
814
840
  exports2.GanttChart = GanttChart;
package/package.json CHANGED
@@ -1,20 +1,27 @@
1
1
  {
2
2
  "name": "gantt-canvas-chart",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "High performance Gantt chart component based on Canvas, can be applied to any framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.es.js",
7
7
  "module": "dist/index.es.js",
8
- "types": "dist/main.d.ts",
8
+ "types": "dist/index.d.ts",
9
9
  "unpkg": "dist/index.umd.js",
10
10
  "jsdelivr": "dist/index.umd.js",
11
+ "typesVersions": {
12
+ "*": {
13
+ ".": [
14
+ "./dist/index.d.ts"
15
+ ]
16
+ }
17
+ },
11
18
  "exports": {
12
19
  ".": {
13
- "types": "./dist/types/main.d.ts",
20
+ "types": "./dist/index.d.ts",
14
21
  "import": "./dist/index.es.js",
15
22
  "require": "./dist/index.umd.cjs"
16
23
  },
17
- "./styles": "./dist/index.css"
24
+ "./style.css": "./dist/index.css"
18
25
  },
19
26
  "files": [
20
27
  "dist"