From f7a596c1137776e9b0f1a88ca4da4dd3326269e9 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Mon, 14 Aug 2023 14:27:02 +0530 Subject: [PATCH] fix: gantt chart block left drag flicker (#1854) * fix: left drag flicker * fix: opposite side manual scroll --- .../cycles/cycles-list-gantt-chart.tsx | 4 +- .../gantt-chart/helpers/draggable.tsx | 128 ++++++++++++------ .../gantt-chart/hooks/block-update.tsx | 4 +- .../modules/modules-list-gantt-chart.tsx | 10 +- 4 files changed, 98 insertions(+), 48 deletions(-) diff --git a/apps/app/components/cycles/cycles-list-gantt-chart.tsx b/apps/app/components/cycles/cycles-list-gantt-chart.tsx index ea66f0929..c5d60015c 100644 --- a/apps/app/components/cycles/cycles-list-gantt-chart.tsx +++ b/apps/app/components/cycles/cycles-list-gantt-chart.tsx @@ -65,9 +65,7 @@ export const CyclesListGanttChartView: FC = ({ cycles, mutateCycles }) => if (newPayload.sort_order && payload.sort_order) newPayload.sort_order = payload.sort_order.newSortOrder; - cyclesService - .patchCycle(workspaceSlug.toString(), cycle.project, cycle.id, newPayload, user) - .finally(() => mutateCycles()); + cyclesService.patchCycle(workspaceSlug.toString(), cycle.project, cycle.id, newPayload, user); }; const blockFormat = (blocks: ICycle[]) => diff --git a/apps/app/components/gantt-chart/helpers/draggable.tsx b/apps/app/components/gantt-chart/helpers/draggable.tsx index 8a85a0dd3..320f4355f 100644 --- a/apps/app/components/gantt-chart/helpers/draggable.tsx +++ b/apps/app/components/gantt-chart/helpers/draggable.tsx @@ -31,7 +31,36 @@ export const ChartDraggable: React.FC = ({ const { currentViewData } = useChart(); - const handleDrag = (dragDirection: "left" | "right") => { + const checkScrollEnd = (e: MouseEvent): number => { + let delWidth = 0; + + const scrollContainer = document.querySelector("#scroll-container") as HTMLElement; + const appSidebar = document.querySelector("#app-sidebar") as HTMLElement; + + const posFromLeft = e.clientX; + // manually scroll to left if reached the left end while dragging + if (posFromLeft - appSidebar.clientWidth <= 70) { + if (e.movementX > 0) return 0; + + delWidth = -5; + + scrollContainer.scrollBy(delWidth, 0); + } else delWidth = e.movementX; + + // manually scroll to right if reached the right end while dragging + const posFromRight = window.innerWidth - e.clientX; + if (posFromRight <= 70) { + if (e.movementX < 0) return 0; + + delWidth = 5; + + scrollContainer.scrollBy(delWidth, 0); + } else delWidth = e.movementX; + + return delWidth; + }; + + const handleLeftDrag = () => { if (!currentViewData || !resizableRef.current || !parentDivRef.current || !block.position) return; @@ -44,54 +73,30 @@ export const ChartDraggable: React.FC = ({ resizableDiv.clientWidth ?? parseInt(block.position.width.toString(), 10); let initialWidth = resizableDiv.clientWidth ?? parseInt(block.position.width.toString(), 10); - let initialMarginLeft = block?.position?.marginLeft; + let initialMarginLeft = parseInt(parentDiv.style.marginLeft); const handleMouseMove = (e: MouseEvent) => { if (!window) return; let delWidth = 0; - const posFromLeft = e.clientX; - const posFromRight = window.innerWidth - e.clientX; + delWidth = checkScrollEnd(e); - const scrollContainer = document.querySelector("#scroll-container") as HTMLElement; - const appSidebar = document.querySelector("#app-sidebar") as HTMLElement; - - // manually scroll to left if reached the left end while dragging - if (posFromLeft - appSidebar.clientWidth <= 70) { - if (e.movementX > 0) return; - - delWidth = dragDirection === "left" ? -5 : 5; - - scrollContainer.scrollBy(-1 * Math.abs(delWidth), 0); - } else delWidth = dragDirection === "left" ? -1 * e.movementX : e.movementX; - - // manually scroll to right if reached the right end while dragging - if (posFromRight <= 70) { - if (e.movementX < 0) return; - - delWidth = dragDirection === "left" ? -5 : 5; - - scrollContainer.scrollBy(Math.abs(delWidth), 0); - } else delWidth = dragDirection === "left" ? -1 * e.movementX : e.movementX; - - // calculate new width and update the initialMarginLeft using += - const newWidth = Math.round((initialWidth += delWidth) / columnWidth) * columnWidth; + // calculate new width and update the initialMarginLeft using -= + const newWidth = Math.round((initialWidth -= delWidth) / columnWidth) * columnWidth; + // calculate new marginLeft and update the initial marginLeft to the newly calculated one + const newMarginLeft = initialMarginLeft - (newWidth - (block.position?.width ?? 0)); + initialMarginLeft = newMarginLeft; // block needs to be at least 1 column wide if (newWidth < columnWidth) return; resizableDiv.style.width = `${newWidth}px`; - if (block.position) block.position.width = newWidth; + parentDiv.style.marginLeft = `${newMarginLeft}px`; - // update the margin left of the block if dragging from the left end - if (dragDirection === "left") { - // calculate new marginLeft and update the initial marginLeft using -= - const newMarginLeft = - Math.round((initialMarginLeft -= delWidth) / columnWidth) * columnWidth; - - parentDiv.style.marginLeft = `${newMarginLeft}px`; - if (block.position) block.position.marginLeft = newMarginLeft; + if (block.position) { + block.position.width = newWidth; + block.position.marginLeft = newMarginLeft; } }; @@ -103,7 +108,52 @@ export const ChartDraggable: React.FC = ({ (resizableDiv.clientWidth - blockInitialWidth) / columnWidth ); - handleBlock(totalBlockShifts, dragDirection); + handleBlock(totalBlockShifts, "left"); + }; + + document.addEventListener("mousemove", handleMouseMove); + document.addEventListener("mouseup", handleMouseUp); + }; + + const handleRightDrag = () => { + if (!currentViewData || !resizableRef.current || !parentDivRef.current || !block.position) + return; + + const resizableDiv = resizableRef.current; + + const columnWidth = currentViewData.data.width; + + const blockInitialWidth = + resizableDiv.clientWidth ?? parseInt(block.position.width.toString(), 10); + + let initialWidth = resizableDiv.clientWidth ?? parseInt(block.position.width.toString(), 10); + + const handleMouseMove = (e: MouseEvent) => { + if (!window) return; + + let delWidth = 0; + + delWidth = checkScrollEnd(e); + + // calculate new width and update the initialMarginLeft using += + const newWidth = Math.round((initialWidth += delWidth) / columnWidth) * columnWidth; + + // block needs to be at least 1 column wide + if (newWidth < columnWidth) return; + + resizableDiv.style.width = `${Math.max(newWidth, 80)}px`; + if (block.position) block.position.width = Math.max(newWidth, 80); + }; + + const handleMouseUp = () => { + document.removeEventListener("mousemove", handleMouseMove); + document.removeEventListener("mouseup", handleMouseUp); + + const totalBlockShifts = Math.ceil( + (resizableDiv.clientWidth - blockInitialWidth) / columnWidth + ); + + handleBlock(totalBlockShifts, "right"); }; document.addEventListener("mousemove", handleMouseMove); @@ -122,7 +172,7 @@ export const ChartDraggable: React.FC = ({ {enableLeftDrag && ( <>
handleDrag("left")} + onMouseDown={handleLeftDrag} onMouseEnter={() => setIsLeftResizing(true)} onMouseLeave={() => setIsLeftResizing(false)} className="absolute top-1/2 -left-2.5 -translate-y-1/2 z-[1] w-6 h-10 bg-brand-backdrop rounded-md cursor-col-resize" @@ -138,7 +188,7 @@ export const ChartDraggable: React.FC = ({ {enableRightDrag && ( <>
handleDrag("right")} + onMouseDown={handleRightDrag} onMouseEnter={() => setIsRightResizing(true)} onMouseLeave={() => setIsRightResizing(false)} className="absolute top-1/2 -right-2.5 -translate-y-1/2 z-[1] w-6 h-6 bg-brand-backdrop rounded-md cursor-col-resize" diff --git a/apps/app/components/gantt-chart/hooks/block-update.tsx b/apps/app/components/gantt-chart/hooks/block-update.tsx index d9d808b38..5d183305b 100644 --- a/apps/app/components/gantt-chart/hooks/block-update.tsx +++ b/apps/app/components/gantt-chart/hooks/block-update.tsx @@ -37,7 +37,5 @@ export const updateGanttIssue = ( if (newPayload.sort_order && payload.sort_order) newPayload.sort_order = payload.sort_order.newSortOrder; - issuesService - .patchIssue(workspaceSlug, issue.project, issue.id, newPayload, user) - .finally(() => mutate()); + issuesService.patchIssue(workspaceSlug, issue.project, issue.id, newPayload, user); }; diff --git a/apps/app/components/modules/modules-list-gantt-chart.tsx b/apps/app/components/modules/modules-list-gantt-chart.tsx index 2dd482d8b..64ceccd1a 100644 --- a/apps/app/components/modules/modules-list-gantt-chart.tsx +++ b/apps/app/components/modules/modules-list-gantt-chart.tsx @@ -69,9 +69,13 @@ export const ModulesListGanttChartView: FC = ({ modules, mutateModules }) if (newPayload.sort_order && payload.sort_order) newPayload.sort_order = payload.sort_order.newSortOrder; - modulesService - .patchModule(workspaceSlug.toString(), module.project, module.id, newPayload, user) - .finally(() => mutateModules()); + modulesService.patchModule( + workspaceSlug.toString(), + module.project, + module.id, + newPayload, + user + ); }; const blockFormat = (blocks: IModule[]) =>