gantt-task-react-v 1.3.2 → 1.3.4

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.
@@ -11835,29 +11835,45 @@
11835
11835
  const currentDate = getDateByOffset(startDate, index2, viewMode);
11836
11836
  const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
11837
11837
  const remainderMillis = xDate.getTime() - currentDate.getTime();
11838
- const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
11839
- return index2 * columnWidth + percentOfInterval * columnWidth;
11838
+ const intervalDuration = nextDate.getTime() - currentDate.getTime();
11839
+ const percentOfInterval = intervalDuration === 0 ? 0 : remainderMillis / intervalDuration;
11840
+ const result = index2 * columnWidth + percentOfInterval * columnWidth;
11841
+ return isNaN(result) || !isFinite(result) ? 0 : result;
11840
11842
  };
11841
11843
  const taskComparisonXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
11842
11844
  const index2 = getDatesDiff(xDate, startDate, viewMode);
11843
11845
  const currentDate = getDateByOffset(startDate, index2, viewMode);
11844
11846
  const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
11845
11847
  const remainderMillis = xDate.getTime() - currentDate.getTime();
11846
- const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
11847
- return index2 * columnWidth + percentOfInterval * columnWidth;
11848
+ const intervalDuration = nextDate.getTime() - currentDate.getTime();
11849
+ const percentOfInterval = intervalDuration === 0 ? 0 : remainderMillis / intervalDuration;
11850
+ const result = index2 * columnWidth + percentOfInterval * columnWidth;
11851
+ return isNaN(result) || !isFinite(result) ? 0 : result;
11848
11852
  };
11849
11853
  const progressWithByParams = (taskX1, taskX2, progress, rtl) => {
11850
- const progressWidth = Math.max((taskX2 - taskX1) * progress * 0.01, 0);
11854
+ const safeTaskX1 = isNaN(taskX1) || !isFinite(taskX1) ? 0 : taskX1;
11855
+ const safeTaskX2 = isNaN(taskX2) || !isFinite(taskX2) ? 0 : taskX2;
11856
+ const safeProgress = isNaN(progress) || !isFinite(progress) ? 0 : progress;
11857
+ const progressWidth = Math.max(
11858
+ (safeTaskX2 - safeTaskX1) * safeProgress * 0.01,
11859
+ 0
11860
+ );
11851
11861
  let progressX;
11852
11862
  if (rtl) {
11853
- progressX = taskX2 - progressWidth;
11863
+ progressX = safeTaskX2 - progressWidth;
11854
11864
  } else {
11855
- progressX = taskX1;
11865
+ progressX = safeTaskX1;
11856
11866
  }
11857
11867
  return [progressWidth, progressX];
11858
11868
  };
11859
11869
  const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
11860
- let newDate = new Date((x - taskX) / xStep * timeStep + taskDate.getTime());
11870
+ const safeX = isNaN(x) || !isFinite(x) ? 0 : x;
11871
+ const safeTaskX = isNaN(taskX) || !isFinite(taskX) ? 0 : taskX;
11872
+ const safeXStep = isNaN(xStep) || !isFinite(xStep) || xStep === 0 ? 1 : xStep;
11873
+ const safeTimeStep = isNaN(timeStep) || !isFinite(timeStep) ? 0 : timeStep;
11874
+ let newDate = new Date(
11875
+ (safeX - safeTaskX) / safeXStep * safeTimeStep + taskDate.getTime()
11876
+ );
11861
11877
  newDate = new Date(
11862
11878
  newDate.getTime() + (newDate.getTimezoneOffset() - taskDate.getTimezoneOffset()) * 6e4
11863
11879
  );
@@ -13109,15 +13125,22 @@
13109
13125
  x2: taskX2,
13110
13126
  comparisonDates
13111
13127
  } = getTaskCoordinates2(task);
13128
+ const safeContainerX = isNaN(containerX) || !isFinite(containerX) ? 0 : containerX;
13129
+ const safeContainerWidth = isNaN(containerWidth) || !isFinite(containerWidth) ? 0 : Math.max(containerWidth, 0);
13130
+ const safeWidth = isNaN(width) || !isFinite(width) ? 10 : Math.max(width, 1);
13131
+ const safeLevelY = isNaN(levelY) || !isFinite(levelY) ? 0 : levelY;
13132
+ const safeProgressWidth = isNaN(progressWidth) || !isFinite(progressWidth) ? 0 : Math.max(progressWidth, 0);
13133
+ const safeInnerX1 = isNaN(innerX1) || !isFinite(innerX1) ? 0 : innerX1;
13134
+ const safeInnerX2 = isNaN(innerX2) || !isFinite(innerX2) ? safeInnerX1 + safeWidth : innerX2;
13112
13135
  tasksRes.push(
13113
13136
  /* @__PURE__ */ jsxRuntime.jsx(
13114
13137
  "svg",
13115
13138
  {
13116
13139
  id: task.id,
13117
13140
  className: `${styles$4.TaskItemWrapper} TaskItemWrapper`,
13118
- x: Math.max(containerX + (additionalLeftSpace || 0), 0),
13119
- y: levelY,
13120
- width: Math.max(containerWidth, 0),
13141
+ x: Math.max(safeContainerX + (additionalLeftSpace || 0), 0),
13142
+ y: safeLevelY,
13143
+ width: Math.max(safeContainerWidth, 0),
13121
13144
  height: fullRowHeight,
13122
13145
  children: /* @__PURE__ */ jsxRuntime.jsx(
13123
13146
  TaskItem,
@@ -13125,14 +13148,14 @@
13125
13148
  movingAction: taskBarMovingAction(task),
13126
13149
  allowMoveTaskBar,
13127
13150
  hasChildren: checkHasChildren(task, childTasksMap),
13128
- progressWidth,
13129
- progressX: rtl ? innerX2 : innerX1,
13151
+ progressWidth: safeProgressWidth,
13152
+ progressX: rtl ? safeInnerX2 : safeInnerX1,
13130
13153
  onSelectTaskOnMouseDown: selectTaskOnMouseDown,
13131
13154
  task,
13132
13155
  taskYOffset,
13133
- width,
13134
- x1: innerX1,
13135
- x2: innerX2,
13156
+ width: safeWidth,
13157
+ x1: safeInnerX1,
13158
+ x2: safeInnerX2,
13136
13159
  distances,
13137
13160
  taskHeight,
13138
13161
  taskHalfHeight,
@@ -13162,16 +13185,20 @@
13162
13185
  )
13163
13186
  );
13164
13187
  if (task.comparisonDates && comparisonDates) {
13188
+ const safeComparisonX = isNaN(comparisonDates.x) || !isFinite(comparisonDates.x) ? 0 : comparisonDates.x;
13189
+ const safeComparisonY = isNaN(comparisonDates.y) || !isFinite(comparisonDates.y) ? safeLevelY : comparisonDates.y;
13190
+ const safeComparisonWidth = isNaN(comparisonDates.width) || !isFinite(comparisonDates.width) ? 10 : Math.max(comparisonDates.width, 1);
13191
+ const safeComparisonHeight = isNaN(comparisonDates.height) || !isFinite(comparisonDates.height) ? 4 : Math.max(comparisonDates.height, 1);
13165
13192
  tasksRes.push(
13166
13193
  /* @__PURE__ */ jsxRuntime.jsx(
13167
13194
  "svg",
13168
13195
  {
13169
13196
  id: task.id + "_comparison",
13170
13197
  className: "TaskItemWrapperComparison",
13171
- x: Math.max(comparisonDates.x + (additionalLeftSpace || 0), 0),
13172
- y: comparisonDates.y,
13173
- width: comparisonDates.width,
13174
- height: comparisonDates.height * 2,
13198
+ x: Math.max(safeComparisonX + (additionalLeftSpace || 0), 0),
13199
+ y: safeComparisonY,
13200
+ width: safeComparisonWidth,
13201
+ height: safeComparisonHeight * 2,
13175
13202
  children: /* @__PURE__ */ jsxRuntime.jsx(
13176
13203
  BarComparison,
13177
13204
  {
@@ -13180,8 +13207,8 @@
13180
13207
  isWarning: !!task.comparisonDates.end && task.comparisonDates.end.getTime() >= task.end.getTime(),
13181
13208
  isCritical: task.comparisonDates.start.getTime() > task.start.getTime(),
13182
13209
  barCornerRadius: distances.barCornerRadius,
13183
- height: comparisonDates.height,
13184
- width: comparisonDates.width,
13210
+ height: safeComparisonHeight,
13211
+ width: safeComparisonWidth,
13185
13212
  borderHeight: distances.barComparisonTaskBorderHeight,
13186
13213
  yOffset: distances.barComparisonTaskYOffset,
13187
13214
  task,
@@ -13224,15 +13251,24 @@
13224
13251
  addedDependenciesAtTask[source.id] = true;
13225
13252
  const isCritical2 = criticalPathForTask ? criticalPathForTask.has(source.id) : false;
13226
13253
  const { x1: fromX1, x2: fromX2 } = getTaskCoordinates2(source);
13227
- const containerX2 = Math.min(fromX1, taskX1) - DELTA_RELATION_WIDTH;
13228
- const containerWidth2 = Math.max(fromX2, taskX2) - containerX2 + DELTA_RELATION_WIDTH;
13254
+ const safeFromX1 = isNaN(fromX1) || !isFinite(fromX1) ? 0 : fromX1;
13255
+ const safeFromX2 = isNaN(fromX2) || !isFinite(fromX2) ? safeFromX1 + 10 : fromX2;
13256
+ const safeTaskX1 = isNaN(taskX1) || !isFinite(taskX1) ? 0 : taskX1;
13257
+ const safeTaskX2 = isNaN(taskX2) || !isFinite(taskX2) ? safeTaskX1 + 10 : taskX2;
13258
+ const containerX2 = Math.min(safeFromX1, safeTaskX1) - DELTA_RELATION_WIDTH;
13259
+ const containerWidth2 = Math.max(safeFromX2, safeTaskX2) - containerX2 + DELTA_RELATION_WIDTH;
13260
+ const safeArrowContainerX = isNaN(containerX2) || !isFinite(containerX2) ? 0 : containerX2;
13261
+ const safeArrowContainerWidth = isNaN(containerWidth2) || !isFinite(containerWidth2) ? 100 : Math.max(containerWidth2, 0);
13229
13262
  arrowsRes.push(
13230
13263
  /* @__PURE__ */ jsxRuntime.jsx(
13231
13264
  "svg",
13232
13265
  {
13233
- x: Math.max(containerX2 + (additionalLeftSpace || 0), 0),
13266
+ x: Math.max(
13267
+ safeArrowContainerX + (additionalLeftSpace || 0),
13268
+ 0
13269
+ ),
13234
13270
  y: containerY,
13235
- width: containerWidth2,
13271
+ width: safeArrowContainerWidth,
13236
13272
  height: containerHeight,
13237
13273
  children: /* @__PURE__ */ jsxRuntime.jsx(
13238
13274
  Arrow,
@@ -13240,13 +13276,13 @@
13240
13276
  distances,
13241
13277
  taskFrom: source,
13242
13278
  targetFrom: sourceTarget,
13243
- fromX1: fromX1 - containerX2,
13244
- fromX2: fromX2 - containerX2,
13279
+ fromX1: safeFromX1 - safeArrowContainerX,
13280
+ fromX2: safeFromX2 - safeArrowContainerX,
13245
13281
  fromY: innerFromY,
13246
13282
  taskTo: task,
13247
13283
  targetTo: ownTarget,
13248
- toX1: taskX1 - containerX2,
13249
- toX2: taskX2 - containerX2,
13284
+ toX1: safeTaskX1 - safeArrowContainerX,
13285
+ toX2: safeTaskX2 - safeArrowContainerX,
13250
13286
  toY: innerToY,
13251
13287
  fullRowHeight,
13252
13288
  taskHeight,
@@ -13289,15 +13325,24 @@
13289
13325
  const criticalPathForTask = criticalPathOnLevel ? criticalPathOnLevel.dependencies.get(dependent.id) : void 0;
13290
13326
  const isCritical2 = criticalPathForTask ? criticalPathForTask.has(task.id) : false;
13291
13327
  const { x1: toX1, x2: toX2 } = getTaskCoordinates2(dependent);
13292
- const containerX2 = Math.min(toX1, taskX1) - DELTA_RELATION_WIDTH;
13293
- const containerWidth2 = Math.max(toX2, taskX2) - containerX2 + DELTA_RELATION_WIDTH;
13328
+ const safeToX1 = isNaN(toX1) || !isFinite(toX1) ? 0 : toX1;
13329
+ const safeToX2 = isNaN(toX2) || !isFinite(toX2) ? safeToX1 + 10 : toX2;
13330
+ const safeTaskX1 = isNaN(taskX1) || !isFinite(taskX1) ? 0 : taskX1;
13331
+ const safeTaskX2 = isNaN(taskX2) || !isFinite(taskX2) ? safeTaskX1 + 10 : taskX2;
13332
+ const containerX2 = Math.min(safeToX1, safeTaskX1) - DELTA_RELATION_WIDTH;
13333
+ const containerWidth2 = Math.max(safeToX2, safeTaskX2) - containerX2 + DELTA_RELATION_WIDTH;
13334
+ const safeArrowContainerX = isNaN(containerX2) || !isFinite(containerX2) ? 0 : containerX2;
13335
+ const safeArrowContainerWidth = isNaN(containerWidth2) || !isFinite(containerWidth2) ? 100 : Math.max(containerWidth2, 0);
13294
13336
  arrowsRes.push(
13295
13337
  /* @__PURE__ */ jsxRuntime.jsx(
13296
13338
  "svg",
13297
13339
  {
13298
- x: Math.max(containerX2 + (additionalLeftSpace || 0), 0),
13340
+ x: Math.max(
13341
+ safeArrowContainerX + (additionalLeftSpace || 0),
13342
+ 0
13343
+ ),
13299
13344
  y: containerY,
13300
- width: containerWidth2,
13345
+ width: safeArrowContainerWidth,
13301
13346
  height: containerHeight,
13302
13347
  children: /* @__PURE__ */ jsxRuntime.jsx(
13303
13348
  Arrow,
@@ -13305,13 +13350,13 @@
13305
13350
  distances,
13306
13351
  taskFrom: task,
13307
13352
  targetFrom: ownTarget,
13308
- fromX1: taskX1 - containerX2,
13309
- fromX2: taskX2 - containerX2,
13353
+ fromX1: safeTaskX1 - safeArrowContainerX,
13354
+ fromX2: safeTaskX2 - safeArrowContainerX,
13310
13355
  fromY: innerFromY,
13311
13356
  taskTo: dependent,
13312
13357
  targetTo: dependentTarget,
13313
- toX1: toX1 - containerX2,
13314
- toX2: toX2 - containerX2,
13358
+ toX1: safeToX1 - safeArrowContainerX,
13359
+ toX2: safeToX2 - safeArrowContainerX,
13315
13360
  toY: innerToY,
13316
13361
  fullRowHeight,
13317
13362
  taskHeight,
@@ -13789,21 +13834,26 @@
13789
13834
  if (typeof rowIndex !== "number") {
13790
13835
  throw new Error(`Row index for task ${id} is not found`);
13791
13836
  }
13792
- const x1 = rtl ? svgWidth - taskXCoordinate(task.end, startDate, viewMode, columnWidth) : taskXCoordinate(task.start, startDate, viewMode, columnWidth);
13793
- const x2 = rtl ? svgWidth - taskXCoordinate(task.start, startDate, viewMode, columnWidth) : taskXCoordinate(task.end, startDate, viewMode, columnWidth);
13837
+ let x1 = rtl ? svgWidth - taskXCoordinate(task.end, startDate, viewMode, columnWidth) : taskXCoordinate(task.start, startDate, viewMode, columnWidth);
13838
+ let x2 = rtl ? svgWidth - taskXCoordinate(task.start, startDate, viewMode, columnWidth) : taskXCoordinate(task.end, startDate, viewMode, columnWidth);
13839
+ x1 = isNaN(x1) || !isFinite(x1) ? 0 : x1;
13840
+ x2 = isNaN(x2) || !isFinite(x2) ? Math.max(x1, 10) : x2;
13794
13841
  const levelY = rowIndex * fullRowHeight + rowHeight * (comparisonLevel - 1);
13795
13842
  const y = levelY + taskYOffset;
13796
13843
  const [progressWidth, progressX] = type === "milestone" ? [0, x1] : progressWithByParams(x1, x2, progress, rtl);
13797
13844
  const taskX1 = type === "milestone" ? x1 - taskHeight * 0.5 : x1;
13798
13845
  const taskX2 = type === "milestone" ? x2 + taskHeight * 0.5 : x2;
13799
- const taskWidth = type === "milestone" ? taskHeight : Math.max(taskX2 - taskX1, 10);
13800
- const containerX = taskX1 - columnWidth;
13801
- const containerWidth = svgWidth - containerX;
13846
+ let taskWidth = type === "milestone" ? taskHeight : Math.max(taskX2 - taskX1, 10);
13847
+ taskWidth = isNaN(taskWidth) || !isFinite(taskWidth) ? 10 : Math.max(taskWidth, 1);
13848
+ let containerX = taskX1 - columnWidth;
13849
+ containerX = isNaN(containerX) || !isFinite(containerX) ? 0 : containerX;
13850
+ let containerWidth = svgWidth - containerX;
13851
+ containerWidth = isNaN(containerWidth) || !isFinite(containerWidth) ? svgWidth : Math.max(containerWidth, 0);
13802
13852
  const innerX1 = columnWidth;
13803
13853
  const innerX2 = columnWidth + taskWidth;
13804
13854
  let comparisonDates;
13805
13855
  if (task.comparisonDates) {
13806
- const cx1 = rtl ? svgWidth - taskComparisonXCoordinate(
13856
+ let cx1 = rtl ? svgWidth - taskComparisonXCoordinate(
13807
13857
  task.comparisonDates.end || task.end,
13808
13858
  startDate,
13809
13859
  viewMode,
@@ -13814,7 +13864,7 @@
13814
13864
  viewMode,
13815
13865
  columnWidth
13816
13866
  );
13817
- const cx2 = rtl ? svgWidth - taskComparisonXCoordinate(
13867
+ let cx2 = rtl ? svgWidth - taskComparisonXCoordinate(
13818
13868
  task.comparisonDates.start,
13819
13869
  startDate,
13820
13870
  viewMode,
@@ -13825,10 +13875,13 @@
13825
13875
  viewMode,
13826
13876
  columnWidth
13827
13877
  );
13878
+ cx1 = isNaN(cx1) || !isFinite(cx1) ? x1 : cx1;
13879
+ cx2 = isNaN(cx2) || !isFinite(cx2) ? x2 : cx2;
13828
13880
  comparisonDates = {
13829
13881
  x: cx1,
13830
13882
  y: y + taskHeight,
13831
- width: Math.max(cx2 - cx1, 0),
13883
+ width: Math.max(cx2 - cx1, 1),
13884
+ // Ensure minimum width of 1px for visibility
13832
13885
  height: barComparisonTaskHeight
13833
13886
  };
13834
13887
  }
@@ -17503,308 +17556,6 @@
17503
17556
  scrollToRightStep
17504
17557
  ];
17505
17558
  };
17506
- const usePerformanceMonitor = (enabled = true) => {
17507
- const metricsRef = React.useRef([]);
17508
- const benchmarksRef = React.useRef(/* @__PURE__ */ new Map());
17509
- const frameTimesRef = React.useRef([]);
17510
- const lastFrameTimeRef = React.useRef(performance.now());
17511
- const updateFPS = React.useCallback(() => {
17512
- if (!enabled)
17513
- return;
17514
- const now = performance.now();
17515
- const deltaTime = now - lastFrameTimeRef.current;
17516
- lastFrameTimeRef.current = now;
17517
- frameTimesRef.current.push(deltaTime);
17518
- if (frameTimesRef.current.length > 60) {
17519
- frameTimesRef.current.shift();
17520
- }
17521
- }, [enabled]);
17522
- const getFPS = React.useCallback(() => {
17523
- if (frameTimesRef.current.length === 0)
17524
- return 0;
17525
- const avgFrameTime = frameTimesRef.current.reduce((sum, time) => sum + time, 0) / frameTimesRef.current.length;
17526
- return Math.round(1e3 / avgFrameTime);
17527
- }, []);
17528
- const startMeasurement = React.useCallback(
17529
- (name, metadata) => {
17530
- if (!enabled)
17531
- return;
17532
- performance.mark(`${name}-start`);
17533
- benchmarksRef.current.set(name, {
17534
- name,
17535
- startTime: performance.now(),
17536
- metadata
17537
- });
17538
- },
17539
- [enabled]
17540
- );
17541
- const endMeasurement = React.useCallback(
17542
- (name) => {
17543
- if (!enabled)
17544
- return 0;
17545
- const benchmark = benchmarksRef.current.get(name);
17546
- if (!benchmark) {
17547
- console.warn(`No benchmark found for ${name}`);
17548
- return 0;
17549
- }
17550
- const endTime = performance.now();
17551
- const duration = endTime - benchmark.startTime;
17552
- performance.mark(`${name}-end`);
17553
- performance.measure(name, `${name}-start`, `${name}-end`);
17554
- benchmark.endTime = endTime;
17555
- benchmark.duration = duration;
17556
- return duration;
17557
- },
17558
- [enabled]
17559
- );
17560
- const measureFunction = React.useCallback(
17561
- (name, fn, metadata) => {
17562
- return (...args) => {
17563
- if (!enabled)
17564
- return fn(...args);
17565
- startMeasurement(name, metadata);
17566
- try {
17567
- const result = fn(...args);
17568
- return result;
17569
- } finally {
17570
- endMeasurement(name);
17571
- }
17572
- };
17573
- },
17574
- [enabled, startMeasurement, endMeasurement]
17575
- );
17576
- const measureAsyncFunction = React.useCallback(
17577
- (name, fn, metadata) => {
17578
- return async (...args) => {
17579
- if (!enabled)
17580
- return fn(...args);
17581
- startMeasurement(name, metadata);
17582
- try {
17583
- const result = await fn(...args);
17584
- return result;
17585
- } finally {
17586
- endMeasurement(name);
17587
- }
17588
- };
17589
- },
17590
- [enabled, startMeasurement, endMeasurement]
17591
- );
17592
- const getPerformanceReport = React.useCallback(() => {
17593
- const entries = performance.getEntriesByType(
17594
- "measure"
17595
- );
17596
- const report = {};
17597
- entries.forEach((entry) => {
17598
- if (!report[entry.name]) {
17599
- report[entry.name] = {
17600
- count: 0,
17601
- totalTime: 0,
17602
- avgTime: 0,
17603
- maxTime: 0,
17604
- minTime: Infinity
17605
- };
17606
- }
17607
- const stat = report[entry.name];
17608
- stat.count++;
17609
- stat.totalTime += entry.duration;
17610
- stat.maxTime = Math.max(stat.maxTime, entry.duration);
17611
- stat.minTime = Math.min(stat.minTime, entry.duration);
17612
- stat.avgTime = stat.totalTime / stat.count;
17613
- });
17614
- return {
17615
- measurements: report,
17616
- fps: getFPS(),
17617
- currentMetrics: metricsRef.current[metricsRef.current.length - 1],
17618
- allMetrics: [...metricsRef.current]
17619
- };
17620
- }, [getFPS]);
17621
- const addMetrics = React.useCallback(
17622
- (metrics) => {
17623
- if (!enabled)
17624
- return;
17625
- const fullMetrics = {
17626
- ...metrics,
17627
- timestamp: Date.now()
17628
- };
17629
- metricsRef.current.push(fullMetrics);
17630
- if (metricsRef.current.length > 100) {
17631
- metricsRef.current.shift();
17632
- }
17633
- },
17634
- [enabled]
17635
- );
17636
- const clearMeasurements = React.useCallback(() => {
17637
- performance.clearMarks();
17638
- performance.clearMeasures();
17639
- benchmarksRef.current.clear();
17640
- metricsRef.current.length = 0;
17641
- frameTimesRef.current.length = 0;
17642
- }, []);
17643
- const getMemoryUsage = React.useCallback(() => {
17644
- if ("memory" in performance) {
17645
- const memory = performance.memory;
17646
- return memory ? memory.usedJSHeapSize : 0;
17647
- }
17648
- return 0;
17649
- }, []);
17650
- return {
17651
- startMeasurement,
17652
- endMeasurement,
17653
- measureFunction,
17654
- measureAsyncFunction,
17655
- getPerformanceReport,
17656
- addMetrics,
17657
- clearMeasurements,
17658
- updateFPS,
17659
- getFPS,
17660
- getMemoryUsage,
17661
- enabled
17662
- };
17663
- };
17664
- const useAdaptivePerformance = (thresholds) => {
17665
- const { getFPS, getPerformanceReport } = usePerformanceMonitor();
17666
- const performanceLevelRef = React.useRef("high");
17667
- const updatePerformanceLevel = React.useCallback(() => {
17668
- var _a;
17669
- const fps = getFPS();
17670
- const report = getPerformanceReport();
17671
- const renderTime = ((_a = report.measurements["render"]) == null ? void 0 : _a.avgTime) || 0;
17672
- if (fps < thresholds.fpsThreshold * 0.5 || renderTime > thresholds.renderTimeThreshold * 2) {
17673
- performanceLevelRef.current = "low";
17674
- } else if (fps < thresholds.fpsThreshold || renderTime > thresholds.renderTimeThreshold) {
17675
- performanceLevelRef.current = "medium";
17676
- } else {
17677
- performanceLevelRef.current = "high";
17678
- }
17679
- return performanceLevelRef.current;
17680
- }, [getFPS, getPerformanceReport, thresholds]);
17681
- const getQualitySettings = React.useCallback(() => {
17682
- const level = performanceLevelRef.current;
17683
- switch (level) {
17684
- case "low":
17685
- return {
17686
- enableAnimations: false,
17687
- renderQuality: "low",
17688
- maxVisibleTasks: 100,
17689
- updateFrequency: 500
17690
- // ms
17691
- };
17692
- case "medium":
17693
- return {
17694
- enableAnimations: true,
17695
- renderQuality: "medium",
17696
- maxVisibleTasks: 500,
17697
- updateFrequency: 100
17698
- };
17699
- case "high":
17700
- default:
17701
- return {
17702
- enableAnimations: true,
17703
- renderQuality: "high",
17704
- maxVisibleTasks: 1e3,
17705
- updateFrequency: 16
17706
- // 60fps
17707
- };
17708
- }
17709
- }, []);
17710
- return {
17711
- performanceLevel: performanceLevelRef.current,
17712
- updatePerformanceLevel,
17713
- getQualitySettings
17714
- };
17715
- };
17716
- const useIncrementalCoordinates = (visibleTasks, visibleTasksMirror, taskToRowIndexMap, startDate, viewMode, rtl, fullRowHeight, taskHeight, taskYOffset, distances, svgWidth, renderedRowIndexes, renderedColumnIndexes) => {
17717
- const cacheRef = React.useRef({
17718
- coordinates: /* @__PURE__ */ new Map(),
17719
- lastUpdateParams: null
17720
- });
17721
- return React.useMemo(() => {
17722
- const cache = cacheRef.current;
17723
- const currentParams = {
17724
- startDate,
17725
- viewMode,
17726
- rtl,
17727
- fullRowHeight,
17728
- taskHeight,
17729
- taskYOffset,
17730
- svgWidth,
17731
- distances
17732
- };
17733
- const needsFullRecalc = !cache.lastUpdateParams || cache.lastUpdateParams.startDate.getTime() !== startDate.getTime() || cache.lastUpdateParams.viewMode !== viewMode || cache.lastUpdateParams.rtl !== rtl || cache.lastUpdateParams.fullRowHeight !== fullRowHeight || cache.lastUpdateParams.taskHeight !== taskHeight || cache.lastUpdateParams.taskYOffset !== taskYOffset || cache.lastUpdateParams.svgWidth !== svgWidth || JSON.stringify(cache.lastUpdateParams.distances) !== JSON.stringify(distances);
17734
- if (needsFullRecalc) {
17735
- cache.coordinates.clear();
17736
- }
17737
- const tasksToCalculate = /* @__PURE__ */ new Set();
17738
- if (renderedRowIndexes && renderedColumnIndexes) {
17739
- const [startRow, endRow] = renderedRowIndexes;
17740
- const rowBuffer = Math.max(5, Math.ceil((endRow - startRow) * 0.5));
17741
- const bufferedStartRow = Math.max(0, startRow - rowBuffer);
17742
- const bufferedEndRow = endRow + rowBuffer;
17743
- visibleTasks.forEach((task, index2) => {
17744
- if (task.type === "empty" || !visibleTasksMirror[task.id])
17745
- return;
17746
- if (index2 >= bufferedStartRow && index2 <= bufferedEndRow) {
17747
- tasksToCalculate.add(task.id);
17748
- }
17749
- });
17750
- } else {
17751
- visibleTasks.forEach((task) => {
17752
- if (task.type !== "empty" && visibleTasksMirror[task.id]) {
17753
- tasksToCalculate.add(task.id);
17754
- }
17755
- });
17756
- }
17757
- if (!needsFullRecalc) {
17758
- for (const [taskId] of cache.coordinates) {
17759
- if (!tasksToCalculate.has(taskId)) {
17760
- cache.coordinates.delete(taskId);
17761
- }
17762
- }
17763
- }
17764
- const res = /* @__PURE__ */ new Map();
17765
- visibleTasks.forEach((task) => {
17766
- if (task.type === "empty" || !tasksToCalculate.has(task.id))
17767
- return;
17768
- const { id, comparisonLevel = 1 } = task;
17769
- const cacheKey = `${id}_${comparisonLevel}`;
17770
- let taskCoordinates = cache.coordinates.get(cacheKey);
17771
- if (!taskCoordinates || needsFullRecalc) {
17772
- taskCoordinates = countTaskCoordinates(
17773
- task,
17774
- taskToRowIndexMap,
17775
- startDate,
17776
- viewMode,
17777
- rtl,
17778
- fullRowHeight,
17779
- taskHeight,
17780
- taskYOffset,
17781
- distances,
17782
- svgWidth
17783
- );
17784
- cache.coordinates.set(cacheKey, taskCoordinates);
17785
- }
17786
- const resByLevel = res.get(comparisonLevel) || /* @__PURE__ */ new Map();
17787
- resByLevel.set(id, taskCoordinates);
17788
- res.set(comparisonLevel, resByLevel);
17789
- });
17790
- cache.lastUpdateParams = currentParams;
17791
- return res;
17792
- }, [
17793
- visibleTasks,
17794
- visibleTasksMirror,
17795
- taskToRowIndexMap,
17796
- startDate,
17797
- viewMode,
17798
- rtl,
17799
- fullRowHeight,
17800
- taskHeight,
17801
- taskYOffset,
17802
- distances,
17803
- svgWidth,
17804
- renderedRowIndexes,
17805
- renderedColumnIndexes
17806
- ]);
17807
- };
17808
17559
  const fillMinAndMaxChildsMap = (resOnLevel, task, childTasksOnLevel) => {
17809
17560
  const childs = childTasksOnLevel.get(task.id);
17810
17561
  if (!childs || childs.length === 0) {
@@ -19424,11 +19175,6 @@
19424
19175
  () => getChildsAndRoots(sortedTasks, null),
19425
19176
  [sortedTasks]
19426
19177
  );
19427
- const adaptiveSettings = useAdaptivePerformance({
19428
- fpsThreshold: 30,
19429
- renderTimeThreshold: 16
19430
- // 60fps = 16ms per frame
19431
- });
19432
19178
  const minAndMaxChildsMap = React.useMemo(
19433
19179
  () => getMinAndMaxChildsMap(rootTasksMap, childTasksMap),
19434
19180
  [rootTasksMap, childTasksMap]
@@ -19602,7 +19348,7 @@
19602
19348
  svgWidth
19603
19349
  ]
19604
19350
  );
19605
- const originalMapTaskToCoordinates = React.useMemo(
19351
+ const mapTaskToCoordinates = React.useMemo(
19606
19352
  () => getMapTaskToCoordinates(
19607
19353
  sortedTasks,
19608
19354
  visibleTasksMirror,
@@ -19630,24 +19376,6 @@
19630
19376
  visibleTasksMirror
19631
19377
  ]
19632
19378
  );
19633
- const optimizedMapTaskToCoordinates = useIncrementalCoordinates(
19634
- visibleTasks,
19635
- visibleTasksMirror,
19636
- taskToRowIndexMap,
19637
- startDate,
19638
- viewMode,
19639
- rtl,
19640
- fullRowHeight,
19641
- taskHeight,
19642
- taskYOffset,
19643
- distances,
19644
- svgWidth,
19645
- null,
19646
- // renderedRowIndexes - can be integrated later with virtualization
19647
- null
19648
- // renderedColumnIndexes - can be integrated later with virtualization
19649
- );
19650
- const mapTaskToCoordinates = adaptiveSettings.performanceLevel === "high" ? optimizedMapTaskToCoordinates : originalMapTaskToCoordinates;
19651
19379
  const scrollToTask = React.useCallback(
19652
19380
  (task) => {
19653
19381
  const { x1 } = getTaskCoordinates(task, mapTaskToCoordinates);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gantt-task-react-v",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "Interactive Gantt Chart for React with TypeScript.",
5
5
  "author": "aguilanbon",
6
6
  "homepage": "https://github.com/aguilanbon/gantt-task-react-v",
@@ -1,17 +0,0 @@
1
- import { Distances, MapTaskToCoordinates, TaskCoordinates, RenderTask, TaskToRowIndexMap, ViewMode } from "../types";
2
- import type { OptimizedListParams } from "./use-optimized-list";
3
- /**
4
- * Optimized hook for calculating task coordinates incrementally
5
- * Only recalculates coordinates for visible tasks and caches results
6
- */
7
- export declare const useIncrementalCoordinates: (visibleTasks: readonly RenderTask[], visibleTasksMirror: Readonly<Record<string, true>>, taskToRowIndexMap: TaskToRowIndexMap, startDate: Date, viewMode: ViewMode, rtl: boolean, fullRowHeight: number, taskHeight: number, taskYOffset: number, distances: Distances, svgWidth: number, renderedRowIndexes: OptimizedListParams | null, renderedColumnIndexes: OptimizedListParams | null) => MapTaskToCoordinates;
8
- /**
9
- * Hook for getting coordinates of tasks in a specific range only
10
- * Useful for virtual scrolling scenarios
11
- */
12
- export declare const useRangedCoordinates: (tasks: readonly RenderTask[], taskToRowIndexMap: TaskToRowIndexMap, startDate: Date, viewMode: ViewMode, rtl: boolean, fullRowHeight: number, taskHeight: number, taskYOffset: number, distances: Distances, svgWidth: number, startIndex: number, endIndex: number, comparisonLevel?: number) => Map<string, TaskCoordinates>;
13
- /**
14
- * Hook for smart coordinate invalidation
15
- * Tracks which tasks need coordinate recalculation based on their dependencies
16
- */
17
- export declare const useCoordinateInvalidation: (tasks: readonly RenderTask[], changedTaskIds: Set<string>) => Set<string>;