From 0b6430b1bc25fb06d9f59b7d4b4df9d0077f8109 Mon Sep 17 00:00:00 2001 From: ashwin8902 <120192265+ashwin8902@users.noreply.github.com> Date: Tue, 4 Feb 2025 13:22:09 +0530 Subject: [PATCH] Update bar-helper.ts --- src/helpers/bar-helper.ts | 517 +++++++------------------------------- 1 file changed, 96 insertions(+), 421 deletions(-) diff --git a/src/helpers/bar-helper.ts b/src/helpers/bar-helper.ts index ba5f987c9..3ba1efa48 100644 --- a/src/helpers/bar-helper.ts +++ b/src/helpers/bar-helper.ts @@ -22,36 +22,45 @@ export const convertToBarTasks = ( milestoneBackgroundColor: string, milestoneBackgroundSelectedColor: string ) => { - let barTasks = tasks.map((t, i) => { - return convertToBarTask( - t, - i, - dates, - columnWidth, - rowHeight, - taskHeight, - barCornerRadius, - handleWidth, - rtl, - barProgressColor, - barProgressSelectedColor, - barBackgroundColor, - barBackgroundSelectedColor, - projectProgressColor, - projectProgressSelectedColor, - projectBackgroundColor, - projectBackgroundSelectedColor, - milestoneBackgroundColor, - milestoneBackgroundSelectedColor + // Ensure valid dates before conversion + tasks = tasks.map((t) => ({ + ...t, + start: t.start ? new Date(t.start) : null, + end: t.end ? new Date(t.end) : null, + })); + + let barTasks = tasks + .filter((t) => t.start && t.end) // Remove invalid tasks + .map((t, i) => + convertToBarTask( + t, + i, + dates, + columnWidth, + rowHeight, + taskHeight, + barCornerRadius, + handleWidth, + rtl, + barProgressColor, + barProgressSelectedColor, + barBackgroundColor, + barBackgroundSelectedColor, + projectProgressColor, + projectProgressSelectedColor, + projectBackgroundColor, + projectBackgroundSelectedColor, + milestoneBackgroundColor, + milestoneBackgroundSelectedColor + ) ); - }); - // set dependencies - barTasks = barTasks.map(task => { + // Set dependencies + barTasks = barTasks.map((task) => { const dependencies = task.dependencies || []; for (let j = 0; j < dependencies.length; j++) { const dependence = barTasks.findIndex( - value => value.id === dependencies[j] + (value) => value.id === dependencies[j] ); if (dependence !== -1) barTasks[dependence].barChildren.push(task); } @@ -82,6 +91,11 @@ const convertToBarTask = ( milestoneBackgroundColor: string, milestoneBackgroundSelectedColor: string ): BarTask => { + if (!task.start || !task.end) { + console.error(`Task ${task.id} has invalid dates:`, task); + return null as any; // Skip this task + } + let barTask: BarTask; switch (task.type) { case "milestone": @@ -136,6 +150,49 @@ const convertToBarTask = ( return barTask; }; +const taskXCoordinate = ( + xDate: Date | undefined, + dates: Date[], + columnWidth: number +) => { + if (!xDate || isNaN(xDate.getTime())) { + console.error("Invalid date in taskXCoordinate:", xDate); + return 0; + } + + const index = dates.findIndex((d) => d.getTime() >= xDate.getTime()); + if (index <= 0 || index >= dates.length) { + console.error("Date not found in taskXCoordinate:", xDate, dates); + return 0; + } + + const remainderMillis = xDate.getTime() - dates[index - 1].getTime(); + const percentOfInterval = + remainderMillis / + (dates[index].getTime() - dates[index - 1].getTime()); + + return (index - 1) * columnWidth + percentOfInterval * columnWidth; +}; + +const taskXCoordinateRTL = ( + xDate: Date, + dates: Date[], + columnWidth: number +) => { + let x = taskXCoordinate(xDate, dates, columnWidth); + return x + columnWidth; +}; + +// Ensuring Y-coordinate calculation is valid +const taskYCoordinate = ( + index: number, + rowHeight: number, + taskHeight: number +) => { + return index * rowHeight + (rowHeight - taskHeight) / 2; +}; + +// Convert to Bar Task (Handling Missing Data) const convertToBar = ( task: Task, index: number, @@ -151,6 +208,11 @@ const convertToBar = ( barBackgroundColor: string, barBackgroundSelectedColor: string ): BarTask => { + if (!task.start || !task.end) { + console.error(`Invalid task start/end date for task ${task.id}:`, task); + return null as any; + } + let x1: number; let x2: number; if (rtl) { @@ -160,6 +222,7 @@ const convertToBar = ( x1 = taskXCoordinate(task.start, dates, columnWidth); x2 = taskXCoordinate(task.end, dates, columnWidth); } + let typeInternal: TaskTypeInternal = task.type; if (typeInternal === "task" && x2 - x1 < handleWidth * 2) { typeInternal = "smalltask"; @@ -172,16 +235,10 @@ const convertToBar = ( task.progress, rtl ); + const y = taskYCoordinate(index, rowHeight, taskHeight); const hideChildren = task.type === "project" ? task.hideChildren : undefined; - const styles = { - backgroundColor: barBackgroundColor, - backgroundSelectedColor: barBackgroundSelectedColor, - progressColor: barProgressColor, - progressSelectedColor: barProgressSelectedColor, - ...task.styles, - }; return { ...task, typeInternal, @@ -196,394 +253,12 @@ const convertToBar = ( hideChildren, height: taskHeight, barChildren: [], - styles, - }; -}; - -const convertToMilestone = ( - task: Task, - index: number, - dates: Date[], - columnWidth: number, - rowHeight: number, - taskHeight: number, - barCornerRadius: number, - handleWidth: number, - milestoneBackgroundColor: string, - milestoneBackgroundSelectedColor: string -): BarTask => { - const x = taskXCoordinate(task.start, dates, columnWidth); - const y = taskYCoordinate(index, rowHeight, taskHeight); - - const x1 = x - taskHeight * 0.5; - const x2 = x + taskHeight * 0.5; - - const rotatedHeight = taskHeight / 1.414; - const styles = { - backgroundColor: milestoneBackgroundColor, - backgroundSelectedColor: milestoneBackgroundSelectedColor, - progressColor: "", - progressSelectedColor: "", - ...task.styles, + styles: { + backgroundColor: barBackgroundColor, + backgroundSelectedColor: barBackgroundSelectedColor, + progressColor: barProgressColor, + progressSelectedColor: barProgressSelectedColor, + ...task.styles, + }, }; - return { - ...task, - end: task.start, - x1, - x2, - y, - index, - progressX: 0, - progressWidth: 0, - barCornerRadius, - handleWidth, - typeInternal: task.type, - progress: 0, - height: rotatedHeight, - hideChildren: undefined, - barChildren: [], - styles, - }; -}; - -const taskXCoordinate = (xDate: Date, dates: Date[], columnWidth: number) => { - const index = dates.findIndex(d => d.getTime() >= xDate.getTime()) - 1; - - const remainderMillis = xDate.getTime() - dates[index].getTime(); - const percentOfInterval = - remainderMillis / (dates[index + 1].getTime() - dates[index].getTime()); - const x = index * columnWidth + percentOfInterval * columnWidth; - return x; -}; -const taskXCoordinateRTL = ( - xDate: Date, - dates: Date[], - columnWidth: number -) => { - let x = taskXCoordinate(xDate, dates, columnWidth); - x += columnWidth; - return x; -}; -const taskYCoordinate = ( - index: number, - rowHeight: number, - taskHeight: number -) => { - const y = index * rowHeight + (rowHeight - taskHeight) / 2; - return y; -}; - -export const progressWithByParams = ( - taskX1: number, - taskX2: number, - progress: number, - rtl: boolean -) => { - const progressWidth = (taskX2 - taskX1) * progress * 0.01; - let progressX: number; - if (rtl) { - progressX = taskX2 - progressWidth; - } else { - progressX = taskX1; - } - return [progressWidth, progressX]; -}; - -export const progressByProgressWidth = ( - progressWidth: number, - barTask: BarTask -) => { - const barWidth = barTask.x2 - barTask.x1; - const progressPercent = Math.round((progressWidth * 100) / barWidth); - if (progressPercent >= 100) return 100; - else if (progressPercent <= 0) return 0; - else return progressPercent; -}; - -const progressByX = (x: number, task: BarTask) => { - if (x >= task.x2) return 100; - else if (x <= task.x1) return 0; - else { - const barWidth = task.x2 - task.x1; - const progressPercent = Math.round(((x - task.x1) * 100) / barWidth); - return progressPercent; - } -}; -const progressByXRTL = (x: number, task: BarTask) => { - if (x >= task.x2) return 0; - else if (x <= task.x1) return 100; - else { - const barWidth = task.x2 - task.x1; - const progressPercent = Math.round(((task.x2 - x) * 100) / barWidth); - return progressPercent; - } -}; - -export const getProgressPoint = ( - progressX: number, - taskY: number, - taskHeight: number -) => { - const point = [ - progressX - 5, - taskY + taskHeight, - progressX + 5, - taskY + taskHeight, - progressX, - taskY + taskHeight - 8.66, - ]; - return point.join(","); -}; - -const startByX = (x: number, xStep: number, task: BarTask) => { - if (x >= task.x2 - task.handleWidth * 2) { - x = task.x2 - task.handleWidth * 2; - } - const steps = Math.round((x - task.x1) / xStep); - const additionalXValue = steps * xStep; - const newX = task.x1 + additionalXValue; - return newX; -}; - -const endByX = (x: number, xStep: number, task: BarTask) => { - if (x <= task.x1 + task.handleWidth * 2) { - x = task.x1 + task.handleWidth * 2; - } - const steps = Math.round((x - task.x2) / xStep); - const additionalXValue = steps * xStep; - const newX = task.x2 + additionalXValue; - return newX; -}; - -const moveByX = (x: number, xStep: number, task: BarTask) => { - const steps = Math.round((x - task.x1) / xStep); - const additionalXValue = steps * xStep; - const newX1 = task.x1 + additionalXValue; - const newX2 = newX1 + task.x2 - task.x1; - return [newX1, newX2]; -}; - -const dateByX = ( - x: number, - taskX: number, - taskDate: Date, - xStep: number, - timeStep: number -) => { - let newDate = new Date(((x - taskX) / xStep) * timeStep + taskDate.getTime()); - newDate = new Date( - newDate.getTime() + - (newDate.getTimezoneOffset() - taskDate.getTimezoneOffset()) * 60000 - ); - return newDate; -}; - -/** - * Method handles event in real time(mousemove) and on finish(mouseup) - */ -export const handleTaskBySVGMouseEvent = ( - svgX: number, - action: BarMoveAction, - selectedTask: BarTask, - xStep: number, - timeStep: number, - initEventX1Delta: number, - rtl: boolean -): { isChanged: boolean; changedTask: BarTask } => { - let result: { isChanged: boolean; changedTask: BarTask }; - switch (selectedTask.type) { - case "milestone": - result = handleTaskBySVGMouseEventForMilestone( - svgX, - action, - selectedTask, - xStep, - timeStep, - initEventX1Delta - ); - break; - default: - result = handleTaskBySVGMouseEventForBar( - svgX, - action, - selectedTask, - xStep, - timeStep, - initEventX1Delta, - rtl - ); - break; - } - return result; -}; - -const handleTaskBySVGMouseEventForBar = ( - svgX: number, - action: BarMoveAction, - selectedTask: BarTask, - xStep: number, - timeStep: number, - initEventX1Delta: number, - rtl: boolean -): { isChanged: boolean; changedTask: BarTask } => { - const changedTask: BarTask = { ...selectedTask }; - let isChanged = false; - switch (action) { - case "progress": - if (rtl) { - changedTask.progress = progressByXRTL(svgX, selectedTask); - } else { - changedTask.progress = progressByX(svgX, selectedTask); - } - isChanged = changedTask.progress !== selectedTask.progress; - if (isChanged) { - const [progressWidth, progressX] = progressWithByParams( - changedTask.x1, - changedTask.x2, - changedTask.progress, - rtl - ); - changedTask.progressWidth = progressWidth; - changedTask.progressX = progressX; - } - break; - case "start": { - const newX1 = startByX(svgX, xStep, selectedTask); - changedTask.x1 = newX1; - isChanged = changedTask.x1 !== selectedTask.x1; - if (isChanged) { - if (rtl) { - changedTask.end = dateByX( - newX1, - selectedTask.x1, - selectedTask.end, - xStep, - timeStep - ); - } else { - changedTask.start = dateByX( - newX1, - selectedTask.x1, - selectedTask.start, - xStep, - timeStep - ); - } - const [progressWidth, progressX] = progressWithByParams( - changedTask.x1, - changedTask.x2, - changedTask.progress, - rtl - ); - changedTask.progressWidth = progressWidth; - changedTask.progressX = progressX; - } - break; - } - case "end": { - const newX2 = endByX(svgX, xStep, selectedTask); - changedTask.x2 = newX2; - isChanged = changedTask.x2 !== selectedTask.x2; - if (isChanged) { - if (rtl) { - changedTask.start = dateByX( - newX2, - selectedTask.x2, - selectedTask.start, - xStep, - timeStep - ); - } else { - changedTask.end = dateByX( - newX2, - selectedTask.x2, - selectedTask.end, - xStep, - timeStep - ); - } - const [progressWidth, progressX] = progressWithByParams( - changedTask.x1, - changedTask.x2, - changedTask.progress, - rtl - ); - changedTask.progressWidth = progressWidth; - changedTask.progressX = progressX; - } - break; - } - case "move": { - const [newMoveX1, newMoveX2] = moveByX( - svgX - initEventX1Delta, - xStep, - selectedTask - ); - isChanged = newMoveX1 !== selectedTask.x1; - if (isChanged) { - changedTask.start = dateByX( - newMoveX1, - selectedTask.x1, - selectedTask.start, - xStep, - timeStep - ); - changedTask.end = dateByX( - newMoveX2, - selectedTask.x2, - selectedTask.end, - xStep, - timeStep - ); - changedTask.x1 = newMoveX1; - changedTask.x2 = newMoveX2; - const [progressWidth, progressX] = progressWithByParams( - changedTask.x1, - changedTask.x2, - changedTask.progress, - rtl - ); - changedTask.progressWidth = progressWidth; - changedTask.progressX = progressX; - } - break; - } - } - return { isChanged, changedTask }; -}; - -const handleTaskBySVGMouseEventForMilestone = ( - svgX: number, - action: BarMoveAction, - selectedTask: BarTask, - xStep: number, - timeStep: number, - initEventX1Delta: number -): { isChanged: boolean; changedTask: BarTask } => { - const changedTask: BarTask = { ...selectedTask }; - let isChanged = false; - switch (action) { - case "move": { - const [newMoveX1, newMoveX2] = moveByX( - svgX - initEventX1Delta, - xStep, - selectedTask - ); - isChanged = newMoveX1 !== selectedTask.x1; - if (isChanged) { - changedTask.start = dateByX( - newMoveX1, - selectedTask.x1, - selectedTask.start, - xStep, - timeStep - ); - changedTask.end = changedTask.start; - changedTask.x1 = newMoveX1; - changedTask.x2 = newMoveX2; - } - break; - } - } - return { isChanged, changedTask }; };