gantt-task-react-v 1.2.3 → 1.2.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.
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Distances, ViewMode } from "../../types";
2
+ import { Distances, ViewMode, Task } from "../../types";
3
3
  export type GanttTodayProps = {
4
4
  additionalLeftSpace: number;
5
5
  distances: Distances;
@@ -15,5 +15,6 @@ export type GanttTodayProps = {
15
15
  dataDateColor?: string | null;
16
16
  todayLabel?: string;
17
17
  dataDateLabel?: string;
18
+ tasks?: readonly Task[];
18
19
  };
19
20
  export declare const GanttToday: React.NamedExoticComponent<GanttTodayProps>;
@@ -10909,6 +10909,285 @@ const styles$c = {
10909
10909
  ganttToday,
10910
10910
  ganttTodayCircle
10911
10911
  };
10912
+ const getDateByOffset = (startDate, offset2, viewMode) => {
10913
+ switch (viewMode) {
10914
+ case ViewMode.Day:
10915
+ return addDays(startDate, offset2);
10916
+ case ViewMode.HalfDay:
10917
+ return addHours(startDate, offset2 * 12);
10918
+ case ViewMode.QuarterDay:
10919
+ return addHours(startDate, offset2 * 6);
10920
+ case ViewMode.Hour:
10921
+ return addHours(startDate, offset2);
10922
+ case ViewMode.Month:
10923
+ return addMonths(startDate, offset2);
10924
+ case ViewMode.Week:
10925
+ return addWeeks(startDate, offset2);
10926
+ case ViewMode.Year:
10927
+ return addYears(startDate, offset2);
10928
+ default:
10929
+ throw new Error("Unknown view mode");
10930
+ }
10931
+ };
10932
+ const taskXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
10933
+ const index2 = getDatesDiff(xDate, startDate, viewMode);
10934
+ const currentDate = getDateByOffset(startDate, index2, viewMode);
10935
+ const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
10936
+ const remainderMillis = xDate.getTime() - currentDate.getTime();
10937
+ const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
10938
+ return index2 * columnWidth + percentOfInterval * columnWidth;
10939
+ };
10940
+ const taskComparisonXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
10941
+ const index2 = getDatesDiff(xDate, startDate, viewMode);
10942
+ const currentDate = getDateByOffset(startDate, index2, viewMode);
10943
+ const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
10944
+ const remainderMillis = xDate.getTime() - currentDate.getTime();
10945
+ const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
10946
+ return index2 * columnWidth + percentOfInterval * columnWidth;
10947
+ };
10948
+ const progressWithByParams = (taskX1, taskX2, progress, rtl) => {
10949
+ const progressWidth = Math.max((taskX2 - taskX1) * progress * 0.01, 0);
10950
+ let progressX;
10951
+ if (rtl) {
10952
+ progressX = taskX2 - progressWidth;
10953
+ } else {
10954
+ progressX = taskX1;
10955
+ }
10956
+ return [progressWidth, progressX];
10957
+ };
10958
+ const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
10959
+ let newDate = new Date((x - taskX) / xStep * timeStep + taskDate.getTime());
10960
+ newDate = new Date(
10961
+ newDate.getTime() + (newDate.getTimezoneOffset() - taskDate.getTimezoneOffset()) * 6e4
10962
+ );
10963
+ return newDate;
10964
+ };
10965
+ const handleTaskBySVGMouseEvent = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
10966
+ let result;
10967
+ switch (selectedTask.type) {
10968
+ case "milestone":
10969
+ result = handleTaskBySVGMouseEventForMilestone(
10970
+ action,
10971
+ selectedTask,
10972
+ initialCoordinates,
10973
+ coordinates,
10974
+ xStep,
10975
+ timeStep
10976
+ );
10977
+ break;
10978
+ default:
10979
+ result = handleTaskBySVGMouseEventForBar(
10980
+ action,
10981
+ selectedTask,
10982
+ initialCoordinates,
10983
+ coordinates,
10984
+ xStep,
10985
+ timeStep,
10986
+ rtl
10987
+ );
10988
+ break;
10989
+ }
10990
+ return result;
10991
+ };
10992
+ const handleTaskBySVGMouseEventForBar = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
10993
+ const changedTask = { ...selectedTask };
10994
+ let isChanged = false;
10995
+ switch (action) {
10996
+ case "progress":
10997
+ isChanged = initialCoordinates.progressWidth !== coordinates.progressWidth;
10998
+ if (isChanged) {
10999
+ changedTask.progress = Math.round(
11000
+ coordinates.progressWidth * 100 / (coordinates.x2 - coordinates.x1)
11001
+ );
11002
+ }
11003
+ break;
11004
+ case "start": {
11005
+ isChanged = initialCoordinates.x1 !== coordinates.x1;
11006
+ if (isChanged) {
11007
+ if (rtl) {
11008
+ changedTask.end = dateByX(
11009
+ coordinates.x1,
11010
+ initialCoordinates.x1,
11011
+ selectedTask.end,
11012
+ xStep,
11013
+ timeStep
11014
+ );
11015
+ } else {
11016
+ changedTask.start = dateByX(
11017
+ coordinates.x1,
11018
+ initialCoordinates.x1,
11019
+ selectedTask.start,
11020
+ xStep,
11021
+ timeStep
11022
+ );
11023
+ }
11024
+ }
11025
+ break;
11026
+ }
11027
+ case "end": {
11028
+ isChanged = initialCoordinates.x2 !== coordinates.x2;
11029
+ if (isChanged) {
11030
+ if (rtl) {
11031
+ changedTask.start = dateByX(
11032
+ coordinates.x2,
11033
+ initialCoordinates.x2,
11034
+ selectedTask.start,
11035
+ xStep,
11036
+ timeStep
11037
+ );
11038
+ } else {
11039
+ changedTask.end = dateByX(
11040
+ coordinates.x2,
11041
+ initialCoordinates.x2,
11042
+ selectedTask.end,
11043
+ xStep,
11044
+ timeStep
11045
+ );
11046
+ }
11047
+ }
11048
+ break;
11049
+ }
11050
+ case "move": {
11051
+ isChanged = initialCoordinates.x1 !== coordinates.x1;
11052
+ if (isChanged) {
11053
+ if (rtl) {
11054
+ changedTask.end = dateByX(
11055
+ coordinates.x1,
11056
+ initialCoordinates.x1,
11057
+ selectedTask.end,
11058
+ xStep,
11059
+ timeStep
11060
+ );
11061
+ changedTask.start = dateByX(
11062
+ coordinates.x2,
11063
+ initialCoordinates.x2,
11064
+ selectedTask.start,
11065
+ xStep,
11066
+ timeStep
11067
+ );
11068
+ } else {
11069
+ changedTask.start = dateByX(
11070
+ coordinates.x1,
11071
+ initialCoordinates.x1,
11072
+ selectedTask.start,
11073
+ xStep,
11074
+ timeStep
11075
+ );
11076
+ changedTask.end = dateByX(
11077
+ coordinates.x2,
11078
+ initialCoordinates.x2,
11079
+ selectedTask.end,
11080
+ xStep,
11081
+ timeStep
11082
+ );
11083
+ }
11084
+ }
11085
+ break;
11086
+ }
11087
+ }
11088
+ return { isChanged, changedTask };
11089
+ };
11090
+ const handleTaskBySVGMouseEventForMilestone = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep) => {
11091
+ const changedTask = { ...selectedTask };
11092
+ const isChanged = coordinates.x1 !== initialCoordinates.x1;
11093
+ if (isChanged) {
11094
+ switch (action) {
11095
+ case "move": {
11096
+ changedTask.start = dateByX(
11097
+ coordinates.x1,
11098
+ initialCoordinates.x1,
11099
+ selectedTask.start,
11100
+ xStep,
11101
+ timeStep
11102
+ );
11103
+ changedTask.end = changedTask.start;
11104
+ break;
11105
+ }
11106
+ }
11107
+ }
11108
+ return { isChanged, changedTask };
11109
+ };
11110
+ const calculateDataDatePosition = ({
11111
+ dataDate,
11112
+ startDate,
11113
+ viewMode,
11114
+ columnWidth,
11115
+ tasks = [],
11116
+ rtl = false
11117
+ }) => {
11118
+ const tasksStartingOnDataDate = tasks.filter((task) => {
11119
+ if (!task || !task.start)
11120
+ return false;
11121
+ const taskStartDate = new Date(task.start);
11122
+ const dataDateNormalized = new Date(dataDate);
11123
+ switch (viewMode) {
11124
+ case ViewMode.Hour:
11125
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear() && taskStartDate.getMonth() === dataDateNormalized.getMonth() && taskStartDate.getDate() === dataDateNormalized.getDate() && taskStartDate.getHours() === dataDateNormalized.getHours();
11126
+ case ViewMode.QuarterDay:
11127
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear() && taskStartDate.getMonth() === dataDateNormalized.getMonth() && taskStartDate.getDate() === dataDateNormalized.getDate() && Math.floor(taskStartDate.getHours() / 6) === Math.floor(dataDateNormalized.getHours() / 6);
11128
+ case ViewMode.HalfDay:
11129
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear() && taskStartDate.getMonth() === dataDateNormalized.getMonth() && taskStartDate.getDate() === dataDateNormalized.getDate() && Math.floor(taskStartDate.getHours() / 12) === Math.floor(dataDateNormalized.getHours() / 12);
11130
+ case ViewMode.Day:
11131
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear() && taskStartDate.getMonth() === dataDateNormalized.getMonth() && taskStartDate.getDate() === dataDateNormalized.getDate();
11132
+ case ViewMode.Week: {
11133
+ const taskWeekStart = new Date(taskStartDate);
11134
+ taskWeekStart.setDate(taskStartDate.getDate() - taskStartDate.getDay());
11135
+ const dataWeekStart = new Date(dataDateNormalized);
11136
+ dataWeekStart.setDate(
11137
+ dataDateNormalized.getDate() - dataDateNormalized.getDay()
11138
+ );
11139
+ return taskWeekStart.getTime() === dataWeekStart.getTime();
11140
+ }
11141
+ case ViewMode.Month:
11142
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear() && taskStartDate.getMonth() === dataDateNormalized.getMonth();
11143
+ case ViewMode.Year:
11144
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear();
11145
+ default:
11146
+ return false;
11147
+ }
11148
+ });
11149
+ if (tasksStartingOnDataDate.length > 0) {
11150
+ let maxEndPosition = -Infinity;
11151
+ for (const task of tasksStartingOnDataDate) {
11152
+ const taskEndX = taskXCoordinate(
11153
+ task.end,
11154
+ startDate,
11155
+ viewMode,
11156
+ columnWidth
11157
+ );
11158
+ maxEndPosition = Math.max(maxEndPosition, taskEndX);
11159
+ }
11160
+ if (maxEndPosition > -Infinity) {
11161
+ return maxEndPosition;
11162
+ }
11163
+ }
11164
+ const dataIndex = getDatesDiff(dataDate, startDate, viewMode);
11165
+ const extraMultiplier = () => {
11166
+ switch (viewMode) {
11167
+ case ViewMode.Week: {
11168
+ const percent = dataDate.getDay() / 7;
11169
+ return 1 + percent * 0.2;
11170
+ }
11171
+ case ViewMode.Month: {
11172
+ const dayInMonth = dataDate.getDate();
11173
+ const maxDaysInMonth = getDaysInMonth(
11174
+ dataDate.getMonth(),
11175
+ dataDate.getFullYear()
11176
+ );
11177
+ const percent = dayInMonth / maxDaysInMonth;
11178
+ return 1 + percent * 0.5;
11179
+ }
11180
+ case ViewMode.Year: {
11181
+ const percent = dataDate.getMonth() / 12;
11182
+ return 1 + percent * 0.5;
11183
+ }
11184
+ default:
11185
+ return 1;
11186
+ }
11187
+ };
11188
+ const tickX = dataIndex * columnWidth * extraMultiplier();
11189
+ return rtl ? tickX + columnWidth : tickX;
11190
+ };
10912
11191
  const GanttTodayInner = ({
10913
11192
  additionalLeftSpace,
10914
11193
  distances: { columnWidth },
@@ -10923,7 +11202,8 @@ const GanttTodayInner = ({
10923
11202
  todayColor = null,
10924
11203
  dataDateColor = null,
10925
11204
  todayLabel = "Today",
10926
- dataDateLabel = "Data Date"
11205
+ dataDateLabel = "Data Date",
11206
+ tasks = []
10927
11207
  }) => {
10928
11208
  const todayElement = useMemo(() => {
10929
11209
  if (isUnknownDates || !showTodayLine) {
@@ -11006,32 +11286,15 @@ const GanttTodayInner = ({
11006
11286
  if (!showDataDateLine || !dataDate) {
11007
11287
  return null;
11008
11288
  }
11009
- const dataIndex = getDatesDiff(dataDate, startDate, viewMode);
11010
- const extraMultiplier = () => {
11011
- switch (viewMode) {
11012
- case ViewMode.Week: {
11013
- const percent = dataDate.getDay() / 7;
11014
- return 1 + percent * 0.2;
11015
- }
11016
- case ViewMode.Month: {
11017
- const dayInMonth = dataDate.getDate();
11018
- const maxDaysInMonth = getDaysInMonth(
11019
- dataDate.getMonth(),
11020
- dataDate.getFullYear()
11021
- );
11022
- const percent = dayInMonth / maxDaysInMonth;
11023
- return 1 + percent * 0.5;
11024
- }
11025
- case ViewMode.Year: {
11026
- const percent = dataDate.getMonth() / 12;
11027
- return 1 + percent * 0.5;
11028
- }
11029
- default:
11030
- return 1;
11031
- }
11032
- };
11033
- const tickX = dataIndex * columnWidth * extraMultiplier();
11034
- const x = rtl ? tickX + columnWidth : tickX;
11289
+ const tickX = calculateDataDatePosition({
11290
+ dataDate,
11291
+ startDate,
11292
+ viewMode,
11293
+ columnWidth,
11294
+ tasks,
11295
+ rtl
11296
+ });
11297
+ const x = rtl ? tickX : tickX;
11035
11298
  const color = dataDateColor || "var(--gantt-calendar-today-color)";
11036
11299
  return /* @__PURE__ */ jsxs(Fragment, { children: [
11037
11300
  /* @__PURE__ */ jsx(
@@ -11077,7 +11340,8 @@ const GanttTodayInner = ({
11077
11340
  showDataDateLine,
11078
11341
  dataDate,
11079
11342
  dataDateColor,
11080
- dataDateLabel
11343
+ dataDateLabel,
11344
+ tasks
11081
11345
  ]);
11082
11346
  return /* @__PURE__ */ jsxs("g", { className: "today", children: [
11083
11347
  dataDateElement,
@@ -11772,204 +12036,6 @@ const RelationLine = ({
11772
12036
  }
11773
12037
  );
11774
12038
  };
11775
- const getDateByOffset = (startDate, offset2, viewMode) => {
11776
- switch (viewMode) {
11777
- case ViewMode.Day:
11778
- return addDays(startDate, offset2);
11779
- case ViewMode.HalfDay:
11780
- return addHours(startDate, offset2 * 12);
11781
- case ViewMode.QuarterDay:
11782
- return addHours(startDate, offset2 * 6);
11783
- case ViewMode.Hour:
11784
- return addHours(startDate, offset2);
11785
- case ViewMode.Month:
11786
- return addMonths(startDate, offset2);
11787
- case ViewMode.Week:
11788
- return addWeeks(startDate, offset2);
11789
- case ViewMode.Year:
11790
- return addYears(startDate, offset2);
11791
- default:
11792
- throw new Error("Unknown view mode");
11793
- }
11794
- };
11795
- const taskXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
11796
- const index2 = getDatesDiff(xDate, startDate, viewMode);
11797
- const currentDate = getDateByOffset(startDate, index2, viewMode);
11798
- const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
11799
- const remainderMillis = xDate.getTime() - currentDate.getTime();
11800
- const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
11801
- return index2 * columnWidth + percentOfInterval * columnWidth;
11802
- };
11803
- const taskComparisonXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
11804
- const index2 = getDatesDiff(xDate, startDate, viewMode);
11805
- const currentDate = getDateByOffset(startDate, index2, viewMode);
11806
- const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
11807
- const remainderMillis = xDate.getTime() - currentDate.getTime();
11808
- const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
11809
- return index2 * columnWidth + percentOfInterval * columnWidth;
11810
- };
11811
- const progressWithByParams = (taskX1, taskX2, progress, rtl) => {
11812
- const progressWidth = Math.max((taskX2 - taskX1) * progress * 0.01, 0);
11813
- let progressX;
11814
- if (rtl) {
11815
- progressX = taskX2 - progressWidth;
11816
- } else {
11817
- progressX = taskX1;
11818
- }
11819
- return [progressWidth, progressX];
11820
- };
11821
- const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
11822
- let newDate = new Date((x - taskX) / xStep * timeStep + taskDate.getTime());
11823
- newDate = new Date(
11824
- newDate.getTime() + (newDate.getTimezoneOffset() - taskDate.getTimezoneOffset()) * 6e4
11825
- );
11826
- return newDate;
11827
- };
11828
- const handleTaskBySVGMouseEvent = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
11829
- let result;
11830
- switch (selectedTask.type) {
11831
- case "milestone":
11832
- result = handleTaskBySVGMouseEventForMilestone(
11833
- action,
11834
- selectedTask,
11835
- initialCoordinates,
11836
- coordinates,
11837
- xStep,
11838
- timeStep
11839
- );
11840
- break;
11841
- default:
11842
- result = handleTaskBySVGMouseEventForBar(
11843
- action,
11844
- selectedTask,
11845
- initialCoordinates,
11846
- coordinates,
11847
- xStep,
11848
- timeStep,
11849
- rtl
11850
- );
11851
- break;
11852
- }
11853
- return result;
11854
- };
11855
- const handleTaskBySVGMouseEventForBar = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
11856
- const changedTask = { ...selectedTask };
11857
- let isChanged = false;
11858
- switch (action) {
11859
- case "progress":
11860
- isChanged = initialCoordinates.progressWidth !== coordinates.progressWidth;
11861
- if (isChanged) {
11862
- changedTask.progress = Math.round(
11863
- coordinates.progressWidth * 100 / (coordinates.x2 - coordinates.x1)
11864
- );
11865
- }
11866
- break;
11867
- case "start": {
11868
- isChanged = initialCoordinates.x1 !== coordinates.x1;
11869
- if (isChanged) {
11870
- if (rtl) {
11871
- changedTask.end = dateByX(
11872
- coordinates.x1,
11873
- initialCoordinates.x1,
11874
- selectedTask.end,
11875
- xStep,
11876
- timeStep
11877
- );
11878
- } else {
11879
- changedTask.start = dateByX(
11880
- coordinates.x1,
11881
- initialCoordinates.x1,
11882
- selectedTask.start,
11883
- xStep,
11884
- timeStep
11885
- );
11886
- }
11887
- }
11888
- break;
11889
- }
11890
- case "end": {
11891
- isChanged = initialCoordinates.x2 !== coordinates.x2;
11892
- if (isChanged) {
11893
- if (rtl) {
11894
- changedTask.start = dateByX(
11895
- coordinates.x2,
11896
- initialCoordinates.x2,
11897
- selectedTask.start,
11898
- xStep,
11899
- timeStep
11900
- );
11901
- } else {
11902
- changedTask.end = dateByX(
11903
- coordinates.x2,
11904
- initialCoordinates.x2,
11905
- selectedTask.end,
11906
- xStep,
11907
- timeStep
11908
- );
11909
- }
11910
- }
11911
- break;
11912
- }
11913
- case "move": {
11914
- isChanged = initialCoordinates.x1 !== coordinates.x1;
11915
- if (isChanged) {
11916
- if (rtl) {
11917
- changedTask.end = dateByX(
11918
- coordinates.x1,
11919
- initialCoordinates.x1,
11920
- selectedTask.end,
11921
- xStep,
11922
- timeStep
11923
- );
11924
- changedTask.start = dateByX(
11925
- coordinates.x2,
11926
- initialCoordinates.x2,
11927
- selectedTask.start,
11928
- xStep,
11929
- timeStep
11930
- );
11931
- } else {
11932
- changedTask.start = dateByX(
11933
- coordinates.x1,
11934
- initialCoordinates.x1,
11935
- selectedTask.start,
11936
- xStep,
11937
- timeStep
11938
- );
11939
- changedTask.end = dateByX(
11940
- coordinates.x2,
11941
- initialCoordinates.x2,
11942
- selectedTask.end,
11943
- xStep,
11944
- timeStep
11945
- );
11946
- }
11947
- }
11948
- break;
11949
- }
11950
- }
11951
- return { isChanged, changedTask };
11952
- };
11953
- const handleTaskBySVGMouseEventForMilestone = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep) => {
11954
- const changedTask = { ...selectedTask };
11955
- const isChanged = coordinates.x1 !== initialCoordinates.x1;
11956
- if (isChanged) {
11957
- switch (action) {
11958
- case "move": {
11959
- changedTask.start = dateByX(
11960
- coordinates.x1,
11961
- initialCoordinates.x1,
11962
- selectedTask.start,
11963
- xStep,
11964
- timeStep
11965
- );
11966
- changedTask.end = changedTask.start;
11967
- break;
11968
- }
11969
- }
11970
- }
11971
- return { isChanged, changedTask };
11972
- };
11973
12039
  const barWrapper = "_barWrapper_5jhkr_1";
11974
12040
  const barHandle = "_barHandle_5jhkr_11";
11975
12041
  const barHandleImportantVisible = "_barHandleImportantVisible_5jhkr_37";
@@ -20186,7 +20252,8 @@ const Gantt = (props) => {
20186
20252
  todayColor,
20187
20253
  dataDateColor,
20188
20254
  todayLabel,
20189
- dataDateLabel
20255
+ dataDateLabel,
20256
+ tasks: sortedTasks.filter((task) => task.type !== "empty")
20190
20257
  }),
20191
20258
  [
20192
20259
  additionalLeftSpace,
@@ -20202,7 +20269,8 @@ const Gantt = (props) => {
20202
20269
  todayColor,
20203
20270
  dataDateColor,
20204
20271
  todayLabel,
20205
- dataDateLabel
20272
+ dataDateLabel,
20273
+ sortedTasks
20206
20274
  ]
20207
20275
  );
20208
20276
  const calendarProps = useMemo(
@@ -10926,6 +10926,285 @@
10926
10926
  ganttToday,
10927
10927
  ganttTodayCircle
10928
10928
  };
10929
+ const getDateByOffset = (startDate, offset2, viewMode) => {
10930
+ switch (viewMode) {
10931
+ case ViewMode.Day:
10932
+ return addDays(startDate, offset2);
10933
+ case ViewMode.HalfDay:
10934
+ return addHours(startDate, offset2 * 12);
10935
+ case ViewMode.QuarterDay:
10936
+ return addHours(startDate, offset2 * 6);
10937
+ case ViewMode.Hour:
10938
+ return addHours(startDate, offset2);
10939
+ case ViewMode.Month:
10940
+ return addMonths(startDate, offset2);
10941
+ case ViewMode.Week:
10942
+ return addWeeks(startDate, offset2);
10943
+ case ViewMode.Year:
10944
+ return addYears(startDate, offset2);
10945
+ default:
10946
+ throw new Error("Unknown view mode");
10947
+ }
10948
+ };
10949
+ const taskXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
10950
+ const index2 = getDatesDiff(xDate, startDate, viewMode);
10951
+ const currentDate = getDateByOffset(startDate, index2, viewMode);
10952
+ const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
10953
+ const remainderMillis = xDate.getTime() - currentDate.getTime();
10954
+ const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
10955
+ return index2 * columnWidth + percentOfInterval * columnWidth;
10956
+ };
10957
+ const taskComparisonXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
10958
+ const index2 = getDatesDiff(xDate, startDate, viewMode);
10959
+ const currentDate = getDateByOffset(startDate, index2, viewMode);
10960
+ const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
10961
+ const remainderMillis = xDate.getTime() - currentDate.getTime();
10962
+ const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
10963
+ return index2 * columnWidth + percentOfInterval * columnWidth;
10964
+ };
10965
+ const progressWithByParams = (taskX1, taskX2, progress, rtl) => {
10966
+ const progressWidth = Math.max((taskX2 - taskX1) * progress * 0.01, 0);
10967
+ let progressX;
10968
+ if (rtl) {
10969
+ progressX = taskX2 - progressWidth;
10970
+ } else {
10971
+ progressX = taskX1;
10972
+ }
10973
+ return [progressWidth, progressX];
10974
+ };
10975
+ const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
10976
+ let newDate = new Date((x - taskX) / xStep * timeStep + taskDate.getTime());
10977
+ newDate = new Date(
10978
+ newDate.getTime() + (newDate.getTimezoneOffset() - taskDate.getTimezoneOffset()) * 6e4
10979
+ );
10980
+ return newDate;
10981
+ };
10982
+ const handleTaskBySVGMouseEvent = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
10983
+ let result;
10984
+ switch (selectedTask.type) {
10985
+ case "milestone":
10986
+ result = handleTaskBySVGMouseEventForMilestone(
10987
+ action,
10988
+ selectedTask,
10989
+ initialCoordinates,
10990
+ coordinates,
10991
+ xStep,
10992
+ timeStep
10993
+ );
10994
+ break;
10995
+ default:
10996
+ result = handleTaskBySVGMouseEventForBar(
10997
+ action,
10998
+ selectedTask,
10999
+ initialCoordinates,
11000
+ coordinates,
11001
+ xStep,
11002
+ timeStep,
11003
+ rtl
11004
+ );
11005
+ break;
11006
+ }
11007
+ return result;
11008
+ };
11009
+ const handleTaskBySVGMouseEventForBar = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
11010
+ const changedTask = { ...selectedTask };
11011
+ let isChanged = false;
11012
+ switch (action) {
11013
+ case "progress":
11014
+ isChanged = initialCoordinates.progressWidth !== coordinates.progressWidth;
11015
+ if (isChanged) {
11016
+ changedTask.progress = Math.round(
11017
+ coordinates.progressWidth * 100 / (coordinates.x2 - coordinates.x1)
11018
+ );
11019
+ }
11020
+ break;
11021
+ case "start": {
11022
+ isChanged = initialCoordinates.x1 !== coordinates.x1;
11023
+ if (isChanged) {
11024
+ if (rtl) {
11025
+ changedTask.end = dateByX(
11026
+ coordinates.x1,
11027
+ initialCoordinates.x1,
11028
+ selectedTask.end,
11029
+ xStep,
11030
+ timeStep
11031
+ );
11032
+ } else {
11033
+ changedTask.start = dateByX(
11034
+ coordinates.x1,
11035
+ initialCoordinates.x1,
11036
+ selectedTask.start,
11037
+ xStep,
11038
+ timeStep
11039
+ );
11040
+ }
11041
+ }
11042
+ break;
11043
+ }
11044
+ case "end": {
11045
+ isChanged = initialCoordinates.x2 !== coordinates.x2;
11046
+ if (isChanged) {
11047
+ if (rtl) {
11048
+ changedTask.start = dateByX(
11049
+ coordinates.x2,
11050
+ initialCoordinates.x2,
11051
+ selectedTask.start,
11052
+ xStep,
11053
+ timeStep
11054
+ );
11055
+ } else {
11056
+ changedTask.end = dateByX(
11057
+ coordinates.x2,
11058
+ initialCoordinates.x2,
11059
+ selectedTask.end,
11060
+ xStep,
11061
+ timeStep
11062
+ );
11063
+ }
11064
+ }
11065
+ break;
11066
+ }
11067
+ case "move": {
11068
+ isChanged = initialCoordinates.x1 !== coordinates.x1;
11069
+ if (isChanged) {
11070
+ if (rtl) {
11071
+ changedTask.end = dateByX(
11072
+ coordinates.x1,
11073
+ initialCoordinates.x1,
11074
+ selectedTask.end,
11075
+ xStep,
11076
+ timeStep
11077
+ );
11078
+ changedTask.start = dateByX(
11079
+ coordinates.x2,
11080
+ initialCoordinates.x2,
11081
+ selectedTask.start,
11082
+ xStep,
11083
+ timeStep
11084
+ );
11085
+ } else {
11086
+ changedTask.start = dateByX(
11087
+ coordinates.x1,
11088
+ initialCoordinates.x1,
11089
+ selectedTask.start,
11090
+ xStep,
11091
+ timeStep
11092
+ );
11093
+ changedTask.end = dateByX(
11094
+ coordinates.x2,
11095
+ initialCoordinates.x2,
11096
+ selectedTask.end,
11097
+ xStep,
11098
+ timeStep
11099
+ );
11100
+ }
11101
+ }
11102
+ break;
11103
+ }
11104
+ }
11105
+ return { isChanged, changedTask };
11106
+ };
11107
+ const handleTaskBySVGMouseEventForMilestone = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep) => {
11108
+ const changedTask = { ...selectedTask };
11109
+ const isChanged = coordinates.x1 !== initialCoordinates.x1;
11110
+ if (isChanged) {
11111
+ switch (action) {
11112
+ case "move": {
11113
+ changedTask.start = dateByX(
11114
+ coordinates.x1,
11115
+ initialCoordinates.x1,
11116
+ selectedTask.start,
11117
+ xStep,
11118
+ timeStep
11119
+ );
11120
+ changedTask.end = changedTask.start;
11121
+ break;
11122
+ }
11123
+ }
11124
+ }
11125
+ return { isChanged, changedTask };
11126
+ };
11127
+ const calculateDataDatePosition = ({
11128
+ dataDate,
11129
+ startDate,
11130
+ viewMode,
11131
+ columnWidth,
11132
+ tasks = [],
11133
+ rtl = false
11134
+ }) => {
11135
+ const tasksStartingOnDataDate = tasks.filter((task) => {
11136
+ if (!task || !task.start)
11137
+ return false;
11138
+ const taskStartDate = new Date(task.start);
11139
+ const dataDateNormalized = new Date(dataDate);
11140
+ switch (viewMode) {
11141
+ case ViewMode.Hour:
11142
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear() && taskStartDate.getMonth() === dataDateNormalized.getMonth() && taskStartDate.getDate() === dataDateNormalized.getDate() && taskStartDate.getHours() === dataDateNormalized.getHours();
11143
+ case ViewMode.QuarterDay:
11144
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear() && taskStartDate.getMonth() === dataDateNormalized.getMonth() && taskStartDate.getDate() === dataDateNormalized.getDate() && Math.floor(taskStartDate.getHours() / 6) === Math.floor(dataDateNormalized.getHours() / 6);
11145
+ case ViewMode.HalfDay:
11146
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear() && taskStartDate.getMonth() === dataDateNormalized.getMonth() && taskStartDate.getDate() === dataDateNormalized.getDate() && Math.floor(taskStartDate.getHours() / 12) === Math.floor(dataDateNormalized.getHours() / 12);
11147
+ case ViewMode.Day:
11148
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear() && taskStartDate.getMonth() === dataDateNormalized.getMonth() && taskStartDate.getDate() === dataDateNormalized.getDate();
11149
+ case ViewMode.Week: {
11150
+ const taskWeekStart = new Date(taskStartDate);
11151
+ taskWeekStart.setDate(taskStartDate.getDate() - taskStartDate.getDay());
11152
+ const dataWeekStart = new Date(dataDateNormalized);
11153
+ dataWeekStart.setDate(
11154
+ dataDateNormalized.getDate() - dataDateNormalized.getDay()
11155
+ );
11156
+ return taskWeekStart.getTime() === dataWeekStart.getTime();
11157
+ }
11158
+ case ViewMode.Month:
11159
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear() && taskStartDate.getMonth() === dataDateNormalized.getMonth();
11160
+ case ViewMode.Year:
11161
+ return taskStartDate.getFullYear() === dataDateNormalized.getFullYear();
11162
+ default:
11163
+ return false;
11164
+ }
11165
+ });
11166
+ if (tasksStartingOnDataDate.length > 0) {
11167
+ let maxEndPosition = -Infinity;
11168
+ for (const task of tasksStartingOnDataDate) {
11169
+ const taskEndX = taskXCoordinate(
11170
+ task.end,
11171
+ startDate,
11172
+ viewMode,
11173
+ columnWidth
11174
+ );
11175
+ maxEndPosition = Math.max(maxEndPosition, taskEndX);
11176
+ }
11177
+ if (maxEndPosition > -Infinity) {
11178
+ return maxEndPosition;
11179
+ }
11180
+ }
11181
+ const dataIndex = getDatesDiff(dataDate, startDate, viewMode);
11182
+ const extraMultiplier = () => {
11183
+ switch (viewMode) {
11184
+ case ViewMode.Week: {
11185
+ const percent = dataDate.getDay() / 7;
11186
+ return 1 + percent * 0.2;
11187
+ }
11188
+ case ViewMode.Month: {
11189
+ const dayInMonth = dataDate.getDate();
11190
+ const maxDaysInMonth = getDaysInMonth(
11191
+ dataDate.getMonth(),
11192
+ dataDate.getFullYear()
11193
+ );
11194
+ const percent = dayInMonth / maxDaysInMonth;
11195
+ return 1 + percent * 0.5;
11196
+ }
11197
+ case ViewMode.Year: {
11198
+ const percent = dataDate.getMonth() / 12;
11199
+ return 1 + percent * 0.5;
11200
+ }
11201
+ default:
11202
+ return 1;
11203
+ }
11204
+ };
11205
+ const tickX = dataIndex * columnWidth * extraMultiplier();
11206
+ return rtl ? tickX + columnWidth : tickX;
11207
+ };
10929
11208
  const GanttTodayInner = ({
10930
11209
  additionalLeftSpace,
10931
11210
  distances: { columnWidth },
@@ -10940,7 +11219,8 @@
10940
11219
  todayColor = null,
10941
11220
  dataDateColor = null,
10942
11221
  todayLabel = "Today",
10943
- dataDateLabel = "Data Date"
11222
+ dataDateLabel = "Data Date",
11223
+ tasks = []
10944
11224
  }) => {
10945
11225
  const todayElement = React.useMemo(() => {
10946
11226
  if (isUnknownDates || !showTodayLine) {
@@ -11023,32 +11303,15 @@
11023
11303
  if (!showDataDateLine || !dataDate) {
11024
11304
  return null;
11025
11305
  }
11026
- const dataIndex = getDatesDiff(dataDate, startDate, viewMode);
11027
- const extraMultiplier = () => {
11028
- switch (viewMode) {
11029
- case ViewMode.Week: {
11030
- const percent = dataDate.getDay() / 7;
11031
- return 1 + percent * 0.2;
11032
- }
11033
- case ViewMode.Month: {
11034
- const dayInMonth = dataDate.getDate();
11035
- const maxDaysInMonth = getDaysInMonth(
11036
- dataDate.getMonth(),
11037
- dataDate.getFullYear()
11038
- );
11039
- const percent = dayInMonth / maxDaysInMonth;
11040
- return 1 + percent * 0.5;
11041
- }
11042
- case ViewMode.Year: {
11043
- const percent = dataDate.getMonth() / 12;
11044
- return 1 + percent * 0.5;
11045
- }
11046
- default:
11047
- return 1;
11048
- }
11049
- };
11050
- const tickX = dataIndex * columnWidth * extraMultiplier();
11051
- const x = rtl ? tickX + columnWidth : tickX;
11306
+ const tickX = calculateDataDatePosition({
11307
+ dataDate,
11308
+ startDate,
11309
+ viewMode,
11310
+ columnWidth,
11311
+ tasks,
11312
+ rtl
11313
+ });
11314
+ const x = rtl ? tickX : tickX;
11052
11315
  const color = dataDateColor || "var(--gantt-calendar-today-color)";
11053
11316
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11054
11317
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -11094,7 +11357,8 @@
11094
11357
  showDataDateLine,
11095
11358
  dataDate,
11096
11359
  dataDateColor,
11097
- dataDateLabel
11360
+ dataDateLabel,
11361
+ tasks
11098
11362
  ]);
11099
11363
  return /* @__PURE__ */ jsxRuntime.jsxs("g", { className: "today", children: [
11100
11364
  dataDateElement,
@@ -11789,204 +12053,6 @@
11789
12053
  }
11790
12054
  );
11791
12055
  };
11792
- const getDateByOffset = (startDate, offset2, viewMode) => {
11793
- switch (viewMode) {
11794
- case ViewMode.Day:
11795
- return addDays(startDate, offset2);
11796
- case ViewMode.HalfDay:
11797
- return addHours(startDate, offset2 * 12);
11798
- case ViewMode.QuarterDay:
11799
- return addHours(startDate, offset2 * 6);
11800
- case ViewMode.Hour:
11801
- return addHours(startDate, offset2);
11802
- case ViewMode.Month:
11803
- return addMonths(startDate, offset2);
11804
- case ViewMode.Week:
11805
- return addWeeks(startDate, offset2);
11806
- case ViewMode.Year:
11807
- return addYears(startDate, offset2);
11808
- default:
11809
- throw new Error("Unknown view mode");
11810
- }
11811
- };
11812
- const taskXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
11813
- const index2 = getDatesDiff(xDate, startDate, viewMode);
11814
- const currentDate = getDateByOffset(startDate, index2, viewMode);
11815
- const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
11816
- const remainderMillis = xDate.getTime() - currentDate.getTime();
11817
- const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
11818
- return index2 * columnWidth + percentOfInterval * columnWidth;
11819
- };
11820
- const taskComparisonXCoordinate = (xDate, startDate, viewMode, columnWidth) => {
11821
- const index2 = getDatesDiff(xDate, startDate, viewMode);
11822
- const currentDate = getDateByOffset(startDate, index2, viewMode);
11823
- const nextDate = getDateByOffset(startDate, index2 + 1, viewMode);
11824
- const remainderMillis = xDate.getTime() - currentDate.getTime();
11825
- const percentOfInterval = remainderMillis / (nextDate.getTime() - currentDate.getTime());
11826
- return index2 * columnWidth + percentOfInterval * columnWidth;
11827
- };
11828
- const progressWithByParams = (taskX1, taskX2, progress, rtl) => {
11829
- const progressWidth = Math.max((taskX2 - taskX1) * progress * 0.01, 0);
11830
- let progressX;
11831
- if (rtl) {
11832
- progressX = taskX2 - progressWidth;
11833
- } else {
11834
- progressX = taskX1;
11835
- }
11836
- return [progressWidth, progressX];
11837
- };
11838
- const dateByX = (x, taskX, taskDate, xStep, timeStep) => {
11839
- let newDate = new Date((x - taskX) / xStep * timeStep + taskDate.getTime());
11840
- newDate = new Date(
11841
- newDate.getTime() + (newDate.getTimezoneOffset() - taskDate.getTimezoneOffset()) * 6e4
11842
- );
11843
- return newDate;
11844
- };
11845
- const handleTaskBySVGMouseEvent = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
11846
- let result;
11847
- switch (selectedTask.type) {
11848
- case "milestone":
11849
- result = handleTaskBySVGMouseEventForMilestone(
11850
- action,
11851
- selectedTask,
11852
- initialCoordinates,
11853
- coordinates,
11854
- xStep,
11855
- timeStep
11856
- );
11857
- break;
11858
- default:
11859
- result = handleTaskBySVGMouseEventForBar(
11860
- action,
11861
- selectedTask,
11862
- initialCoordinates,
11863
- coordinates,
11864
- xStep,
11865
- timeStep,
11866
- rtl
11867
- );
11868
- break;
11869
- }
11870
- return result;
11871
- };
11872
- const handleTaskBySVGMouseEventForBar = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep, rtl) => {
11873
- const changedTask = { ...selectedTask };
11874
- let isChanged = false;
11875
- switch (action) {
11876
- case "progress":
11877
- isChanged = initialCoordinates.progressWidth !== coordinates.progressWidth;
11878
- if (isChanged) {
11879
- changedTask.progress = Math.round(
11880
- coordinates.progressWidth * 100 / (coordinates.x2 - coordinates.x1)
11881
- );
11882
- }
11883
- break;
11884
- case "start": {
11885
- isChanged = initialCoordinates.x1 !== coordinates.x1;
11886
- if (isChanged) {
11887
- if (rtl) {
11888
- changedTask.end = dateByX(
11889
- coordinates.x1,
11890
- initialCoordinates.x1,
11891
- selectedTask.end,
11892
- xStep,
11893
- timeStep
11894
- );
11895
- } else {
11896
- changedTask.start = dateByX(
11897
- coordinates.x1,
11898
- initialCoordinates.x1,
11899
- selectedTask.start,
11900
- xStep,
11901
- timeStep
11902
- );
11903
- }
11904
- }
11905
- break;
11906
- }
11907
- case "end": {
11908
- isChanged = initialCoordinates.x2 !== coordinates.x2;
11909
- if (isChanged) {
11910
- if (rtl) {
11911
- changedTask.start = dateByX(
11912
- coordinates.x2,
11913
- initialCoordinates.x2,
11914
- selectedTask.start,
11915
- xStep,
11916
- timeStep
11917
- );
11918
- } else {
11919
- changedTask.end = dateByX(
11920
- coordinates.x2,
11921
- initialCoordinates.x2,
11922
- selectedTask.end,
11923
- xStep,
11924
- timeStep
11925
- );
11926
- }
11927
- }
11928
- break;
11929
- }
11930
- case "move": {
11931
- isChanged = initialCoordinates.x1 !== coordinates.x1;
11932
- if (isChanged) {
11933
- if (rtl) {
11934
- changedTask.end = dateByX(
11935
- coordinates.x1,
11936
- initialCoordinates.x1,
11937
- selectedTask.end,
11938
- xStep,
11939
- timeStep
11940
- );
11941
- changedTask.start = dateByX(
11942
- coordinates.x2,
11943
- initialCoordinates.x2,
11944
- selectedTask.start,
11945
- xStep,
11946
- timeStep
11947
- );
11948
- } else {
11949
- changedTask.start = dateByX(
11950
- coordinates.x1,
11951
- initialCoordinates.x1,
11952
- selectedTask.start,
11953
- xStep,
11954
- timeStep
11955
- );
11956
- changedTask.end = dateByX(
11957
- coordinates.x2,
11958
- initialCoordinates.x2,
11959
- selectedTask.end,
11960
- xStep,
11961
- timeStep
11962
- );
11963
- }
11964
- }
11965
- break;
11966
- }
11967
- }
11968
- return { isChanged, changedTask };
11969
- };
11970
- const handleTaskBySVGMouseEventForMilestone = (action, selectedTask, initialCoordinates, coordinates, xStep, timeStep) => {
11971
- const changedTask = { ...selectedTask };
11972
- const isChanged = coordinates.x1 !== initialCoordinates.x1;
11973
- if (isChanged) {
11974
- switch (action) {
11975
- case "move": {
11976
- changedTask.start = dateByX(
11977
- coordinates.x1,
11978
- initialCoordinates.x1,
11979
- selectedTask.start,
11980
- xStep,
11981
- timeStep
11982
- );
11983
- changedTask.end = changedTask.start;
11984
- break;
11985
- }
11986
- }
11987
- }
11988
- return { isChanged, changedTask };
11989
- };
11990
12056
  const barWrapper = "_barWrapper_5jhkr_1";
11991
12057
  const barHandle = "_barHandle_5jhkr_11";
11992
12058
  const barHandleImportantVisible = "_barHandleImportantVisible_5jhkr_37";
@@ -20203,7 +20269,8 @@
20203
20269
  todayColor,
20204
20270
  dataDateColor,
20205
20271
  todayLabel,
20206
- dataDateLabel
20272
+ dataDateLabel,
20273
+ tasks: sortedTasks.filter((task) => task.type !== "empty")
20207
20274
  }),
20208
20275
  [
20209
20276
  additionalLeftSpace,
@@ -20219,7 +20286,8 @@
20219
20286
  todayColor,
20220
20287
  dataDateColor,
20221
20288
  todayLabel,
20222
- dataDateLabel
20289
+ dataDateLabel,
20290
+ sortedTasks
20223
20291
  ]
20224
20292
  );
20225
20293
  const calendarProps = React.useMemo(
@@ -0,0 +1,14 @@
1
+ import { Task, ViewMode } from "../types";
2
+ export interface DataDatePositionOptions {
3
+ dataDate: Date;
4
+ startDate: Date;
5
+ viewMode: ViewMode;
6
+ columnWidth: number;
7
+ tasks?: readonly Task[];
8
+ rtl?: boolean;
9
+ }
10
+ /**
11
+ * Calculate enhanced data date line position that considers tasks starting on the same date
12
+ * When tasks start exactly on the data date, positions the line at the end of those task bars
13
+ */
14
+ export declare const calculateDataDatePosition: ({ dataDate, startDate, viewMode, columnWidth, tasks, rtl, }: DataDatePositionOptions) => number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gantt-task-react-v",
3
- "version": "1.2.3",
3
+ "version": "1.2.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",