diff --git a/example/src/App.tsx b/example/src/App.tsx index e2717d6..a15fd19 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -64,17 +64,20 @@ const App = () => { isChecked={isChecked} />

Gantt With Unlimited Height

- +
+ +

Gantt With Limited Height

= ({ projectBackgroundSelectedColor = "#f7bb53", milestoneBackgroundColor = "#f1c453", milestoneBackgroundSelectedColor = "#f29e4c", + rtl = false, handleWidth = 8, timeStep = 300000, arrowColor = "grey", @@ -83,7 +84,10 @@ export const Gantt: React.FunctionComponent = ({ // task change events useEffect(() => { const [startDate, endDate] = ganttDateRange(tasks, viewMode); - const newDates = seedDates(startDate, endDate, viewMode); + let newDates = seedDates(startDate, endDate, viewMode); + if (rtl) { + newDates = newDates.reverse(); + } setDateSetup({ dates: newDates, viewMode }); setBarTasks( convertToBarTasks( @@ -94,6 +98,7 @@ export const Gantt: React.FunctionComponent = ({ taskHeight, barCornerRadius, handleWidth, + rtl, barProgressColor, barProgressSelectedColor, barBackgroundColor, @@ -124,6 +129,7 @@ export const Gantt: React.FunctionComponent = ({ projectBackgroundSelectedColor, milestoneBackgroundColor, milestoneBackgroundSelectedColor, + rtl, ]); useEffect(() => { @@ -344,6 +350,7 @@ export const Gantt: React.FunctionComponent = ({ fontSize, arrowIndent, svgWidth, + rtl, setGanttEvent, setFailedTask, setSelectedTask: handleSelectedTask, @@ -415,6 +422,7 @@ export const Gantt: React.FunctionComponent = ({ svgWidth={svgWidth} taskListWidth={taskListWidth} scroll={scrollX} + rtl={rtl} onScroll={handleScrollX} /> diff --git a/src/components/gantt/task-gantt-content.tsx b/src/components/gantt/task-gantt-content.tsx index f316b8e..bc0814c 100644 --- a/src/components/gantt/task-gantt-content.tsx +++ b/src/components/gantt/task-gantt-content.tsx @@ -26,6 +26,7 @@ export type TaskGanttContentProps = { arrowIndent: number; fontSize: string; fontFamily: string; + rtl: boolean; setGanttEvent: (value: GanttEvent) => void; setFailedTask: (value: BarTask | null) => void; setSelectedTask: (taskId: string) => void; @@ -45,6 +46,7 @@ export const TaskGanttContent: React.FC = ({ arrowIndent, fontFamily, fontSize, + rtl, setGanttEvent, setFailedTask, setSelectedTask, @@ -85,7 +87,8 @@ export const TaskGanttContent: React.FC = ({ ganttEvent.changedTask, xStep, timeStep, - initEventX1Delta + initEventX1Delta, + rtl ); if (isChanged) { setGanttEvent({ action: ganttEvent.action, changedTask }); @@ -108,7 +111,8 @@ export const TaskGanttContent: React.FC = ({ changedTask, xStep, timeStep, - initEventX1Delta + initEventX1Delta, + rtl ); const isNotLikeOriginal = diff --git a/src/components/other/horizontal-scroll.tsx b/src/components/other/horizontal-scroll.tsx index 1f5668e..3a179dd 100644 --- a/src/components/other/horizontal-scroll.tsx +++ b/src/components/other/horizontal-scroll.tsx @@ -5,8 +5,9 @@ export const HorizontalScroll: React.FC<{ scroll: number; svgWidth: number; taskListWidth: number; + rtl: boolean; onScroll: (event: SyntheticEvent) => void; -}> = ({ scroll, svgWidth, taskListWidth, onScroll }) => { +}> = ({ scroll, svgWidth, taskListWidth, rtl, onScroll }) => { const scrollRef = useRef(null); useEffect(() => { @@ -17,7 +18,11 @@ export const HorizontalScroll: React.FC<{ return (
= ({ width, height, isSelected, + progressX, progressWidth, barCornerRadius, styles, @@ -49,7 +52,7 @@ export const BarDisplay: React.FC = ({ className={style.barBackground} /> = ({ onEventStart, isSelected, }) => { - const progressWidth = progressWithByParams(task.x1, task.x2, task.progress); const progressPoint = getProgressPoint( - progressWidth + task.x1, + task.progressWidth + task.x1, task.y, task.height ); @@ -28,7 +24,8 @@ export const BarSmall: React.FC = ({ y={task.y} width={task.x2 - task.x1} height={task.height} - progressWidth={progressWidth} + progressX={task.progressX} + progressWidth={task.progressWidth} barCornerRadius={task.barCornerRadius} styles={task.styles} isSelected={isSelected} diff --git a/src/components/task-item/bar/bar.tsx b/src/components/task-item/bar/bar.tsx index 2796a5c..6a50ee7 100644 --- a/src/components/task-item/bar/bar.tsx +++ b/src/components/task-item/bar/bar.tsx @@ -1,8 +1,5 @@ import React from "react"; -import { - progressWithByParams, - getProgressPoint, -} from "../../../helpers/bar-helper"; +import { getProgressPoint } from "../../../helpers/bar-helper"; import { BarDisplay } from "./bar-display"; import { BarDateHandle } from "./bar-date-handle"; import { BarProgressHandle } from "./bar-progress-handle"; @@ -16,9 +13,8 @@ export const Bar: React.FC = ({ onEventStart, isSelected, }) => { - const progressWidth = progressWithByParams(task.x1, task.x2, task.progress); const progressPoint = getProgressPoint( - progressWidth + task.x1, + task.progressWidth + task.x1, task.y, task.height ); @@ -30,7 +26,8 @@ export const Bar: React.FC = ({ y={task.y} width={task.x2 - task.x1} height={task.height} - progressWidth={progressWidth} + progressX={task.progressX} + progressWidth={task.progressWidth} barCornerRadius={task.barCornerRadius} styles={task.styles} isSelected={isSelected} diff --git a/src/components/task-item/project/project.tsx b/src/components/task-item/project/project.tsx index 21bddb3..5a47ba9 100644 --- a/src/components/task-item/project/project.tsx +++ b/src/components/task-item/project/project.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { progressWithByParams } from "../../../helpers/bar-helper"; import { TaskItemProps } from "../task-item"; import styles from "./project.module.css"; @@ -10,7 +9,6 @@ export const Project: React.FC = ({ task, isSelected }) => { const processColor = isSelected ? task.styles.progressSelectedColor : task.styles.progressColor; - const progressWidth = progressWithByParams(task.x1, task.x2, task.progress); const projectWith = task.x2 - task.x1; const projectLeftTriangle = [ @@ -43,8 +41,8 @@ export const Project: React.FC = ({ task, isSelected }) => { className={styles.projectBackground} /> { - const x1 = taskXCoordinate(task.start, dates, dateDelta, columnWidth); - let x2 = taskXCoordinate(task.end, dates, dateDelta, columnWidth); + let x1: number; + let x2: number; + if (rtl) { + x2 = taskXCoordinate(task.start, dates, dateDelta, columnWidth); + x1 = taskXCoordinate(task.end, dates, dateDelta, columnWidth); + } else { + x1 = taskXCoordinate(task.start, dates, dateDelta, columnWidth); + x2 = taskXCoordinate(task.end, dates, dateDelta, columnWidth); + } + let typeInternal: TaskTypeInternal = task.type; + if (typeInternal === "task" && x2 - x1 < handleWidth * 2) { + typeInternal = "smalltask"; + x2 = x1 + handleWidth * 2; + } + + const progressWidth = progressWithByParams(x1, x2, task.progress); + let progressX: number; + if (rtl) { + progressX = x2 - progressWidth; + } else { + progressX = x1; + } + const y = taskYCoordinate(index, rowHeight, taskHeight); const styles = { @@ -167,11 +194,6 @@ const convertToBar = ( progressSelectedColor: barProgressSelectedColor, ...task.styles, }; - let typeInternal: TaskTypeInternal = task.type; - if (typeInternal === "task" && x2 - x1 < handleWidth * 2) { - typeInternal = "smalltask"; - x2 = x1 + handleWidth * 2; - } return { ...task, typeInternal, @@ -179,6 +201,8 @@ const convertToBar = ( x2, y, index, + progressX, + progressWidth, barCornerRadius, handleWidth, height: taskHeight, @@ -199,7 +223,7 @@ const convertToMilestone = ( handleWidth: number, milestoneBackgroundColor: string, milestoneBackgroundSelectedColor: string -) => { +): BarTask => { const x = taskXCoordinate(task.start, dates, dateDelta, columnWidth); const y = taskYCoordinate(index, rowHeight, taskHeight); @@ -221,6 +245,8 @@ const convertToMilestone = ( x2, y, index, + progressX: 0, + progressWidth: 0, barCornerRadius, handleWidth, typeInternal: task.type, @@ -281,9 +307,7 @@ export const progressByProgressWidth = ( const progressPercent = Math.round((progressWidth * 100) / barWidth); if (progressPercent >= 100) return 100; else if (progressPercent <= 0) return 0; - else { - return progressPercent; - } + else return progressPercent; }; const progressByX = (x: number, task: BarTask) => { @@ -364,7 +388,8 @@ export const handleTaskBySVGMouseEvent = ( selectedTask: BarTask, xStep: number, timeStep: number, - initEventX1Delta: number + initEventX1Delta: number, + rtl: boolean ): { isChanged: boolean; changedTask: BarTask } => { let result: { isChanged: boolean; changedTask: BarTask }; switch (selectedTask.type) { @@ -385,7 +410,8 @@ export const handleTaskBySVGMouseEvent = ( selectedTask, xStep, timeStep, - initEventX1Delta + initEventX1Delta, + rtl ); break; } @@ -398,7 +424,8 @@ const handleTaskBySVGMouseEventForBar = ( selectedTask: BarTask, xStep: number, timeStep: number, - initEventX1Delta: number + initEventX1Delta: number, + rtl: boolean ): { isChanged: boolean; changedTask: BarTask } => { const changedTask: BarTask = { ...selectedTask }; let isChanged = false; @@ -406,6 +433,18 @@ const handleTaskBySVGMouseEventForBar = ( case "progress": changedTask.progress = progressByX(svgX, selectedTask); isChanged = changedTask.progress !== selectedTask.progress; + if (isChanged) { + changedTask.progressWidth = progressWithByParams( + changedTask.x1, + changedTask.x2, + changedTask.progress + ); + if (rtl) { + changedTask.progressX = changedTask.x2 - changedTask.progressWidth; + } else { + changedTask.progressX = changedTask.x1; + } + } break; case "start": { const newX1 = startByX(svgX, xStep, selectedTask); diff --git a/src/types/bar-task.ts b/src/types/bar-task.ts index 1b45371..4f3f783 100644 --- a/src/types/bar-task.ts +++ b/src/types/bar-task.ts @@ -7,6 +7,8 @@ export interface BarTask extends Task { x2: number; y: number; height: number; + progressX: number; + progressWidth: number; barCornerRadius: number; handleWidth: number; barChildren: number[]; diff --git a/src/types/public-types.ts b/src/types/public-types.ts index c4428fe..f51b88c 100644 --- a/src/types/public-types.ts +++ b/src/types/public-types.ts @@ -65,6 +65,7 @@ export interface DisplayOption { * Specifies the month name language. Able formats: ISO 639-2, Java Locale */ locale?: string; + rtl?: boolean; } export interface StylingOption {