Skip to content

Commit

Permalink
fix: gantt chart block left drag flicker (#1854)
Browse files Browse the repository at this point in the history
* fix: left drag flicker

* fix: opposite side manual scroll
  • Loading branch information
aaryan610 authored Aug 14, 2023
1 parent f73239b commit f7a596c
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 42 deletions.
4 changes: 1 addition & 3 deletions apps/app/components/cycles/cycles-list-gantt-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,7 @@ export const CyclesListGanttChartView: FC<Props> = ({ 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[]) =>
Expand Down
116 changes: 83 additions & 33 deletions apps/app/components/gantt-chart/helpers/draggable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,36 @@ export const ChartDraggable: React.FC<Props> = ({

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;

Expand All @@ -44,55 +73,76 @@ export const ChartDraggable: React.FC<Props> = ({
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);

// 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`;
parentDiv.style.marginLeft = `${newMarginLeft}px`;

if (block.position) {
block.position.width = newWidth;
block.position.marginLeft = newMarginLeft;
}
};

const handleMouseUp = () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);

const totalBlockShifts = Math.ceil(
(resizableDiv.clientWidth - blockInitialWidth) / columnWidth
);

handleBlock(totalBlockShifts, "left");
};

document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
};

const handleRightDrag = () => {
if (!currentViewData || !resizableRef.current || !parentDivRef.current || !block.position)
return;

const scrollContainer = document.querySelector("#scroll-container") as HTMLElement;
const appSidebar = document.querySelector("#app-sidebar") as HTMLElement;
const resizableDiv = resizableRef.current;

// manually scroll to left if reached the left end while dragging
if (posFromLeft - appSidebar.clientWidth <= 70) {
if (e.movementX > 0) return;
const columnWidth = currentViewData.data.width;

delWidth = dragDirection === "left" ? -5 : 5;
const blockInitialWidth =
resizableDiv.clientWidth ?? parseInt(block.position.width.toString(), 10);

scrollContainer.scrollBy(-1 * Math.abs(delWidth), 0);
} else delWidth = dragDirection === "left" ? -1 * e.movementX : e.movementX;
let initialWidth = resizableDiv.clientWidth ?? parseInt(block.position.width.toString(), 10);

// manually scroll to right if reached the right end while dragging
if (posFromRight <= 70) {
if (e.movementX < 0) return;
const handleMouseMove = (e: MouseEvent) => {
if (!window) return;

delWidth = dragDirection === "left" ? -5 : 5;
let delWidth = 0;

scrollContainer.scrollBy(Math.abs(delWidth), 0);
} else delWidth = dragDirection === "left" ? -1 * e.movementX : e.movementX;
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 = `${newWidth}px`;
if (block.position) block.position.width = newWidth;

// 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;
}
resizableDiv.style.width = `${Math.max(newWidth, 80)}px`;
if (block.position) block.position.width = Math.max(newWidth, 80);
};

const handleMouseUp = () => {
Expand All @@ -103,7 +153,7 @@ export const ChartDraggable: React.FC<Props> = ({
(resizableDiv.clientWidth - blockInitialWidth) / columnWidth
);

handleBlock(totalBlockShifts, dragDirection);
handleBlock(totalBlockShifts, "right");
};

document.addEventListener("mousemove", handleMouseMove);
Expand All @@ -122,7 +172,7 @@ export const ChartDraggable: React.FC<Props> = ({
{enableLeftDrag && (
<>
<div
onMouseDown={() => 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"
Expand All @@ -138,7 +188,7 @@ export const ChartDraggable: React.FC<Props> = ({
{enableRightDrag && (
<>
<div
onMouseDown={() => 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"
Expand Down
4 changes: 1 addition & 3 deletions apps/app/components/gantt-chart/hooks/block-update.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
10 changes: 7 additions & 3 deletions apps/app/components/modules/modules-list-gantt-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,13 @@ export const ModulesListGanttChartView: FC<Props> = ({ 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[]) =>
Expand Down

1 comment on commit f7a596c

@vercel
Copy link

@vercel vercel bot commented on f7a596c Aug 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

plane-dev – ./apps/app

plane-dev-git-develop-plane.vercel.app
plane-dev-plane.vercel.app
plane-dev.vercel.app

Please sign in to comment.