305 lines
7.3 KiB
TypeScript
305 lines
7.3 KiB
TypeScript
import { Task } from "../types/public-types";
|
|
import { BarTask } from "../types/bar-task";
|
|
|
|
export const convertToBarTasks = (
|
|
tasks: Task[],
|
|
dates: Date[],
|
|
columnWidth: number,
|
|
rowHeight: number,
|
|
barFill: number,
|
|
headerHeight: number,
|
|
barCornerRadius: number,
|
|
handleWidth: number,
|
|
barProgressColor: string,
|
|
barProgressSelectedColor: string,
|
|
barBackgroundColor: string,
|
|
barBackgroundSelectedColor: string
|
|
) => {
|
|
const dateDelta =
|
|
dates[1].getTime() -
|
|
dates[0].getTime() -
|
|
dates[1].getTimezoneOffset() * 60 * 1000 +
|
|
dates[0].getTimezoneOffset() * 60 * 1000;
|
|
const taskHeight = (rowHeight * barFill) / 100;
|
|
|
|
let barTasks = tasks.map((t, i) => {
|
|
return convertToBarTask(
|
|
t,
|
|
i,
|
|
dates,
|
|
dateDelta,
|
|
columnWidth,
|
|
rowHeight,
|
|
taskHeight,
|
|
headerHeight,
|
|
barCornerRadius,
|
|
handleWidth,
|
|
barProgressColor,
|
|
barProgressSelectedColor,
|
|
barBackgroundColor,
|
|
barBackgroundSelectedColor
|
|
);
|
|
});
|
|
|
|
// set dependencies
|
|
barTasks = barTasks.map((task, i) => {
|
|
const dependencies = task.dependencies || [];
|
|
for (let j = 0; j < dependencies.length; j++) {
|
|
const dependence = barTasks.findIndex(
|
|
value => value.id === dependencies[j]
|
|
);
|
|
if (dependence !== -1) barTasks[dependence].barChildren.push(i);
|
|
}
|
|
return task;
|
|
});
|
|
|
|
return barTasks;
|
|
};
|
|
|
|
export const convertToBarTask = (
|
|
task: Task,
|
|
index: number,
|
|
dates: Date[],
|
|
dateDelta: number,
|
|
columnWidth: number,
|
|
rowHeight: number,
|
|
taskHeight: number,
|
|
headerHeight: number,
|
|
barCornerRadius: number,
|
|
handleWidth: number,
|
|
barProgressColor: string,
|
|
barProgressSelectedColor: string,
|
|
barBackgroundColor: string,
|
|
barBackgroundSelectedColor: string
|
|
): BarTask => {
|
|
const x1 = taskXCoordinate(task.start, dates, dateDelta, columnWidth);
|
|
const x2 = taskXCoordinate(task.end, dates, dateDelta, columnWidth);
|
|
const y = taskYCoordinate(index, rowHeight, taskHeight, headerHeight);
|
|
|
|
const styles = {
|
|
backgroundColor: barBackgroundColor,
|
|
backgroundSelectedColor: barBackgroundSelectedColor,
|
|
progressColor: barProgressColor,
|
|
progressSelectedColor: barProgressSelectedColor,
|
|
...task.styles,
|
|
};
|
|
return {
|
|
...task,
|
|
x1,
|
|
x2,
|
|
y,
|
|
index,
|
|
barCornerRadius,
|
|
handleWidth,
|
|
height: taskHeight,
|
|
barChildren: [],
|
|
styles,
|
|
};
|
|
};
|
|
|
|
export const taskXCoordinate = (
|
|
xDate: Date,
|
|
dates: Date[],
|
|
dateDelta: number,
|
|
columnWidth: number
|
|
) => {
|
|
const index = ~~(
|
|
(xDate.getTime() -
|
|
dates[0].getTime() +
|
|
xDate.getTimezoneOffset() -
|
|
dates[0].getTimezoneOffset()) /
|
|
dateDelta
|
|
);
|
|
const x = Math.round(
|
|
(index +
|
|
(xDate.getTime() -
|
|
dates[index].getTime() -
|
|
xDate.getTimezoneOffset() * 60 * 1000 +
|
|
dates[index].getTimezoneOffset() * 60 * 1000) /
|
|
dateDelta) *
|
|
columnWidth
|
|
);
|
|
return x;
|
|
};
|
|
|
|
export const taskYCoordinate = (
|
|
index: number,
|
|
rowHeight: number,
|
|
taskHeight: number,
|
|
headerHeight: number
|
|
) => {
|
|
const y = index * rowHeight + headerHeight + (rowHeight - taskHeight) / 2;
|
|
return y;
|
|
};
|
|
|
|
export const progressWithByParams = (
|
|
taskX1: number,
|
|
taskX2: number,
|
|
progress: number
|
|
) => {
|
|
return (taskX2 - taskX1) * progress * 0.01;
|
|
};
|
|
|
|
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;
|
|
}
|
|
};
|
|
|
|
export 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;
|
|
}
|
|
};
|
|
|
|
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(",");
|
|
};
|
|
|
|
export 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;
|
|
};
|
|
|
|
export 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;
|
|
};
|
|
|
|
export 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];
|
|
};
|
|
|
|
export 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;
|
|
};
|
|
|
|
export type BarMoveAction = "progress" | "end" | "start" | "move" | "";
|
|
|
|
/**
|
|
* 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
|
|
) => {
|
|
const changedTask: BarTask = { ...selectedTask };
|
|
let isChanged = false;
|
|
switch (action) {
|
|
case "progress":
|
|
changedTask.progress = progressByX(svgX, selectedTask);
|
|
isChanged = changedTask.progress !== selectedTask.progress;
|
|
break;
|
|
case "start": {
|
|
const newX1 = startByX(svgX, xStep, selectedTask);
|
|
changedTask.x1 = newX1;
|
|
isChanged = changedTask.x1 !== selectedTask.x1;
|
|
if (isChanged) {
|
|
changedTask.start = dateByX(
|
|
newX1,
|
|
selectedTask.x1,
|
|
selectedTask.start,
|
|
xStep,
|
|
timeStep
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
case "end": {
|
|
const newX2 = endByX(svgX, xStep, selectedTask);
|
|
changedTask.x2 = newX2;
|
|
isChanged = changedTask.x2 !== selectedTask.x2;
|
|
if (isChanged) {
|
|
changedTask.end = dateByX(
|
|
newX2,
|
|
selectedTask.x2,
|
|
selectedTask.end,
|
|
xStep,
|
|
timeStep
|
|
);
|
|
}
|
|
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;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return { isChanged, changedTask };
|
|
};
|