[WEB-2442] fix: Timeline Improvements and bug fixes (#5922)

* improve auto scroller logic

* fix drag indicator visibility on for blocks

* modify timeline store logic and improve timeline scrolling logic

* fix width of block while dragging with left handle

* fix block arrow direction while block is out of viewport
This commit is contained in:
rahulramesha 2024-10-29 13:42:14 +05:30 committed by GitHub
parent a88a39fb1e
commit 724adeff5c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 128 additions and 60 deletions

View file

@ -9,7 +9,7 @@ import { getDateFromPositionOnGantt, getItemPositionWidth } from "@/components/g
// helpers // helpers
import { renderFormattedPayloadDate } from "@/helpers/date-time.helper"; import { renderFormattedPayloadDate } from "@/helpers/date-time.helper";
// store // store
import { CoreRootStore } from "@/store/root.store"; import { RootStore } from "@/plane-web/store/root.store";
// types // types
type BlockData = { type BlockData = {
@ -38,6 +38,7 @@ export interface IBaseTimelineStore {
updateCurrentViewData: (data: ChartDataType | undefined) => void; updateCurrentViewData: (data: ChartDataType | undefined) => void;
updateActiveBlockId: (blockId: string | null) => void; updateActiveBlockId: (blockId: string | null) => void;
updateRenderView: (data: any) => void; updateRenderView: (data: any) => void;
updateAllBlocksOnChartChangeWhileDragging: (addedWidth: number) => void;
getUpdatedPositionAfterDrag: (id: string, ignoreDependencies?: boolean) => IBlockUpdateDependencyData[]; getUpdatedPositionAfterDrag: (id: string, ignoreDependencies?: boolean) => IBlockUpdateDependencyData[];
updateBlockPosition: (id: string, deltaLeft: number, deltaWidth: number, ignoreDependencies?: boolean) => void; updateBlockPosition: (id: string, deltaLeft: number, deltaWidth: number, ignoreDependencies?: boolean) => void;
getNumberOfDaysFromPosition: (position: number | undefined) => number | undefined; getNumberOfDaysFromPosition: (position: number | undefined) => number | undefined;
@ -57,9 +58,9 @@ export class BaseTimeLineStore implements IBaseTimelineStore {
activeBlockId: string | null = null; activeBlockId: string | null = null;
renderView: any = []; renderView: any = [];
rootStore: CoreRootStore; rootStore: RootStore;
constructor(_rootStore: CoreRootStore) { constructor(_rootStore: RootStore) {
makeObservable(this, { makeObservable(this, {
// observables // observables
blocksMap: observable, blocksMap: observable,
@ -232,6 +233,24 @@ export class BaseTimeLineStore implements IBaseTimelineStore {
return getDateFromPositionOnGantt(position, this.currentViewData, offsetDays); return getDateFromPositionOnGantt(position, this.currentViewData, offsetDays);
}); });
/**
* Adds width on Chart position change while the blocks are being dragged
* @param addedWidth
*/
updateAllBlocksOnChartChangeWhileDragging = action((addedWidth: number) => {
if (!this.blockIds || !this.isDragging) return;
runInAction(() => {
this.blockIds?.forEach((blockId) => {
const currBlock = this.blocksMap[blockId];
if (!currBlock || !currBlock.position) return;
currBlock.position.marginLeft += addedWidth;
});
});
});
/** /**
* returns updates dates of blocks post drag. * returns updates dates of blocks post drag.
* @param id * @param id

View file

@ -48,7 +48,7 @@ export const BlockRow: React.FC<Props> = observer((props) => {
(entries) => { (entries) => {
entries.forEach((entry) => { entries.forEach((entry) => {
setIsHidden(!entry.isIntersecting); setIsHidden(!entry.isIntersecting);
setIsBlockHiddenOnLeft(entry.boundingClientRect.left < 0); setIsBlockHiddenOnLeft(entry.boundingClientRect.right < (entry.rootBounds?.left ?? 0));
}); });
}, },
{ {

View file

@ -98,11 +98,11 @@ export const GanttChartMainContent: React.FC<Props> = observer((props) => {
const onScroll = (e: React.UIEvent<HTMLDivElement, UIEvent>) => { const onScroll = (e: React.UIEvent<HTMLDivElement, UIEvent>) => {
const { clientWidth, scrollLeft, scrollWidth } = e.currentTarget; const { clientWidth, scrollLeft, scrollWidth } = e.currentTarget;
const approxRangeLeft = scrollLeft >= clientWidth + 1000 ? 1000 : scrollLeft - clientWidth; const approxRangeLeft = scrollLeft;
const approxRangeRight = scrollWidth - (scrollLeft + clientWidth); const approxRangeRight = scrollWidth - (scrollLeft + clientWidth);
if (approxRangeRight < 1000) updateCurrentViewRenderPayload("right", currentView); if (approxRangeRight < clientWidth) updateCurrentViewRenderPayload("right", currentView);
if (approxRangeLeft < 1000) updateCurrentViewRenderPayload("left", currentView); if (approxRangeLeft < clientWidth) updateCurrentViewRenderPayload("left", currentView);
}; };
const CHART_VIEW_COMPONENTS: { const CHART_VIEW_COMPONENTS: {

View file

@ -10,7 +10,15 @@ import { useTimeLineChartStore } from "@/hooks/use-timeline-chart";
import { SIDEBAR_WIDTH } from "../constants"; import { SIDEBAR_WIDTH } from "../constants";
import { currentViewDataWithView } from "../data"; import { currentViewDataWithView } from "../data";
import { ChartDataType, IBlockUpdateData, IBlockUpdateDependencyData, TGanttViews } from "../types"; import { ChartDataType, IBlockUpdateData, IBlockUpdateDependencyData, TGanttViews } from "../types";
import { getNumberOfDaysBetweenTwoDates, IMonthBlock, IMonthView, IWeekBlock, timelineViewHelpers } from "../views"; import {
getNumberOfDaysBetweenTwoDates,
IMonthBlock,
IMonthView,
IWeekBlock,
monthView,
quarterView,
weekView,
} from "../views";
type ChartViewRootProps = { type ChartViewRootProps = {
border: boolean; border: boolean;
@ -35,6 +43,12 @@ type ChartViewRootProps = {
showToday: boolean; showToday: boolean;
}; };
const timelineViewHelpers = {
week: weekView,
month: monthView,
quarter: quarterView,
};
export const ChartViewRoot: FC<ChartViewRootProps> = observer((props) => { export const ChartViewRoot: FC<ChartViewRootProps> = observer((props) => {
const { const {
border, border,
@ -62,8 +76,15 @@ export const ChartViewRoot: FC<ChartViewRootProps> = observer((props) => {
const [itemsContainerWidth, setItemsContainerWidth] = useState(0); const [itemsContainerWidth, setItemsContainerWidth] = useState(0);
const [fullScreenMode, setFullScreenMode] = useState(false); const [fullScreenMode, setFullScreenMode] = useState(false);
// hooks // hooks
const { currentView, currentViewData, renderView, updateCurrentView, updateCurrentViewData, updateRenderView } = const {
useTimeLineChartStore(); currentView,
currentViewData,
renderView,
updateCurrentView,
updateCurrentViewData,
updateRenderView,
updateAllBlocksOnChartChangeWhileDragging,
} = useTimeLineChartStore();
const updateCurrentViewRenderPayload = (side: null | "left" | "right", view: TGanttViews) => { const updateCurrentViewRenderPayload = (side: null | "left" | "right", view: TGanttViews) => {
const selectedCurrentView: TGanttViews = view; const selectedCurrentView: TGanttViews = view;
@ -89,6 +110,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = observer((props) => {
updateCurrentView(selectedCurrentView); updateCurrentView(selectedCurrentView);
updateRenderView(mergeRenderPayloads(currentRender.payload, renderView)); updateRenderView(mergeRenderPayloads(currentRender.payload, renderView));
updatingCurrentLeftScrollPosition(currentRender.scrollWidth); updatingCurrentLeftScrollPosition(currentRender.scrollWidth);
updateAllBlocksOnChartChangeWhileDragging(currentRender.scrollWidth);
setItemsContainerWidth(itemsContainerWidth + currentRender.scrollWidth); setItemsContainerWidth(itemsContainerWidth + currentRender.scrollWidth);
} else if (side === "right") { } else if (side === "right") {
updateCurrentView(view); updateCurrentView(view);

View file

@ -90,7 +90,7 @@ export const VIEWS_LIST: ChartDataType[] = [
startDate: new Date(), startDate: new Date(),
currentDate: new Date(), currentDate: new Date(),
endDate: new Date(), endDate: new Date(),
approxFilterRange: 18, // it will preview week starting dates all months data and there is 3 months limitation for preview ex: title (2, 9, 16, 23, 30) approxFilterRange: 24, // it will preview week starting dates all months data and there is 3 months limitation for preview ex: title (2, 9, 16, 23, 30)
dayWidth: 5, dayWidth: 5,
}, },
}, },

View file

@ -50,9 +50,9 @@ export const LeftResizable = observer((props: LeftResizableProps) => {
/> />
<div <div
className={cn( className={cn(
"absolute left-1 top-1/2 -translate-y-1/2 h-7 w-1 z-[5] rounded-sm bg-custom-background-100 transition-all duration-300", "absolute left-1 top-1/2 -translate-y-1/2 h-7 w-1 z-[5] rounded-sm bg-custom-background-100 transition-all duration-300 opacity-0 group-hover:opacity-100",
{ {
"-left-1.5": isLeftResizing, "-left-1.5 opacity-100": isLeftResizing,
} }
)} )}
/> />

View file

@ -48,9 +48,9 @@ export const RightResizable = observer((props: RightResizableProps) => {
/> />
<div <div
className={cn( className={cn(
"absolute right-1 top-1/2 -translate-y-1/2 h-7 w-1 z-[5] rounded-sm bg-custom-background-100 transition-all duration-300", "absolute right-1 top-1/2 -translate-y-1/2 h-7 w-1 z-[5] rounded-sm bg-custom-background-100 transition-all duration-300 opacity-0 group-hover:opacity-100",
{ {
"-right-1.5": isRightResizing, "-right-1.5 opacity-100": isRightResizing,
} }
)} )}
/> />

View file

@ -66,13 +66,16 @@ export const useGanttResizable = (
let width = initialPositionRef.current.width; let width = initialPositionRef.current.width;
let marginLeft = initialPositionRef.current.marginLeft; let marginLeft = initialPositionRef.current.marginLeft;
const blockRight = initialPositionRef.current.width + initialPositionRef.current.marginLeft;
if (dragDirection === "left") { if (dragDirection === "left") {
// calculate new marginLeft and update the initial marginLeft to the newly calculated one // calculate new marginLeft and update the initial marginLeft to the newly calculated one
marginLeft = Math.round(mouseX / dayWidth) * dayWidth; marginLeft = Math.round(mouseX / dayWidth) * dayWidth;
// get Dimensions from dom's style
const prevMarginLeft = parseFloat(resizableDiv.style.transform.slice(11, -3));
const prevWidth = parseFloat(resizableDiv.style.width.slice(0, -2));
// calculate new width // calculate new width
width = blockRight - marginLeft; const marginDelta = prevMarginLeft - marginLeft;
width = prevWidth + marginDelta;
} else if (dragDirection === "right") { } else if (dragDirection === "right") {
// calculate new width and update the initialMarginLeft using += // calculate new width and update the initialMarginLeft using +=
width = Math.round(mouseX / dayWidth) * dayWidth - marginLeft; width = Math.round(mouseX / dayWidth) * dayWidth - marginLeft;

View file

@ -113,9 +113,3 @@ export const getItemPositionWidth = (chartData: ChartDataType, itemData: IGanttB
return { marginLeft: scrollPosition, width: scrollWidth }; return { marginLeft: scrollPosition, width: scrollWidth };
}; };
export const timelineViewHelpers = {
week: weekView,
month: monthView,
quarter: quarterView,
};

View file

@ -3,7 +3,7 @@ import uniqBy from "lodash/uniqBy";
// //
import { months } from "../data"; import { months } from "../data";
import { ChartDataType } from "../types"; import { ChartDataType } from "../types";
import { getNumberOfDaysInMonth } from "./helpers"; import { getNumberOfDaysBetweenTwoDates, getNumberOfDaysInMonth } from "./helpers";
import { getWeeksBetweenTwoDates, IWeekBlock } from "./week-view"; import { getWeeksBetweenTwoDates, IWeekBlock } from "./week-view";
export interface IMonthBlock { export interface IMonthBlock {
@ -38,6 +38,9 @@ const generateMonthChart = (monthPayload: ChartDataType, side: null | "left" | "
let minusDate: Date = new Date(); let minusDate: Date = new Date();
let plusDate: Date = new Date(); let plusDate: Date = new Date();
let startDate = new Date();
let endDate = new Date();
// if side is null generate months on both side of current date // if side is null generate months on both side of current date
if (side === null) { if (side === null) {
const currentDate = renderState.data.currentDate; const currentDate = renderState.data.currentDate;
@ -47,12 +50,14 @@ const generateMonthChart = (monthPayload: ChartDataType, side: null | "left" | "
if (minusDate && plusDate) filteredDates = getMonthsViewBetweenTwoDates(minusDate, plusDate); if (minusDate && plusDate) filteredDates = getMonthsViewBetweenTwoDates(minusDate, plusDate);
startDate = filteredDates.weeks[0]?.startDate;
endDate = filteredDates.weeks[filteredDates.weeks.length - 1]?.endDate;
renderState = { renderState = {
...renderState, ...renderState,
data: { data: {
...renderState.data, ...renderState.data,
startDate: filteredDates.weeks[0]?.startDate, startDate,
endDate: filteredDates.weeks[filteredDates.weeks.length - 1]?.endDate, endDate,
}, },
}; };
} }
@ -65,9 +70,11 @@ const generateMonthChart = (monthPayload: ChartDataType, side: null | "left" | "
if (minusDate && plusDate) filteredDates = getMonthsViewBetweenTwoDates(minusDate, plusDate); if (minusDate && plusDate) filteredDates = getMonthsViewBetweenTwoDates(minusDate, plusDate);
startDate = filteredDates.weeks[0]?.startDate;
endDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() - 1);
renderState = { renderState = {
...renderState, ...renderState,
data: { ...renderState.data, startDate: filteredDates.weeks[0].startDate }, data: { ...renderState.data, startDate },
}; };
} }
// When side is right, generate more months on the right side of the end date // When side is right, generate more months on the right side of the end date
@ -79,13 +86,16 @@ const generateMonthChart = (monthPayload: ChartDataType, side: null | "left" | "
if (minusDate && plusDate) filteredDates = getMonthsViewBetweenTwoDates(minusDate, plusDate); if (minusDate && plusDate) filteredDates = getMonthsViewBetweenTwoDates(minusDate, plusDate);
startDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() + 1);
endDate = filteredDates.weeks[filteredDates.weeks.length - 1]?.endDate;
renderState = { renderState = {
...renderState, ...renderState,
data: { ...renderState.data, endDate: filteredDates.weeks[filteredDates.weeks.length - 1]?.endDate }, data: { ...renderState.data, endDate: filteredDates.weeks[filteredDates.weeks.length - 1]?.endDate },
}; };
} }
const scrollWidth = filteredDates.weeks.length * monthPayload.data.dayWidth * 7; const days = Math.abs(getNumberOfDaysBetweenTwoDates(startDate, endDate)) + 1;
const scrollWidth = days * monthPayload.data.dayWidth;
return { state: renderState, payload: filteredDates, scrollWidth: scrollWidth }; return { state: renderState, payload: filteredDates, scrollWidth: scrollWidth };
}; };

View file

@ -27,6 +27,9 @@ const generateQuarterChart = (quarterPayload: ChartDataType, side: null | "left"
let minusDate: Date = new Date(); let minusDate: Date = new Date();
let plusDate: Date = new Date(); let plusDate: Date = new Date();
let startDate = new Date();
let endDate = new Date();
// if side is null generate months on both side of current date // if side is null generate months on both side of current date
if (side === null) { if (side === null) {
const currentDate = renderState.data.currentDate; const currentDate = renderState.data.currentDate;
@ -38,12 +41,15 @@ const generateQuarterChart = (quarterPayload: ChartDataType, side: null | "left"
const startMonthBlock = filteredDates[0]; const startMonthBlock = filteredDates[0];
const endMonthBlock = filteredDates[filteredDates.length - 1]; const endMonthBlock = filteredDates[filteredDates.length - 1];
startDate = new Date(startMonthBlock.year, startMonthBlock.month, 1);
endDate = new Date(endMonthBlock.year, endMonthBlock.month + 1, 0);
renderState = { renderState = {
...renderState, ...renderState,
data: { data: {
...renderState.data, ...renderState.data,
startDate: new Date(startMonthBlock.year, startMonthBlock.month, 1), startDate,
endDate: new Date(endMonthBlock.year, endMonthBlock.month + 1, 0), endDate,
}, },
}; };
} }
@ -51,15 +57,17 @@ const generateQuarterChart = (quarterPayload: ChartDataType, side: null | "left"
else if (side === "left") { else if (side === "left") {
const currentDate = renderState.data.startDate; const currentDate = renderState.data.startDate;
minusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - range, 1); minusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - range / 2, 1);
plusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1); plusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1);
if (minusDate && plusDate) filteredDates = getMonthsBetweenTwoDates(minusDate, plusDate); if (minusDate && plusDate) filteredDates = getMonthsBetweenTwoDates(minusDate, plusDate);
const startMonthBlock = filteredDates[0]; const startMonthBlock = filteredDates[0];
startDate = new Date(startMonthBlock.year, startMonthBlock.month, 1);
endDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() - 1);
renderState = { renderState = {
...renderState, ...renderState,
data: { ...renderState.data, startDate: new Date(startMonthBlock.year, startMonthBlock.month, 1) }, data: { ...renderState.data, startDate },
}; };
} }
// When side is right, generate more months on the right side of the end date // When side is right, generate more months on the right side of the end date
@ -67,24 +75,20 @@ const generateQuarterChart = (quarterPayload: ChartDataType, side: null | "left"
const currentDate = renderState.data.endDate; const currentDate = renderState.data.endDate;
minusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1); minusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1);
plusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + range, 1); plusDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + range / 2, 1);
if (minusDate && plusDate) filteredDates = getMonthsBetweenTwoDates(minusDate, plusDate); if (minusDate && plusDate) filteredDates = getMonthsBetweenTwoDates(minusDate, plusDate);
const endMonthBlock = filteredDates[filteredDates.length - 1]; const endMonthBlock = filteredDates[filteredDates.length - 1];
startDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() + 1);
endDate = new Date(endMonthBlock.year, endMonthBlock.month + 1, 0);
renderState = { renderState = {
...renderState, ...renderState,
data: { ...renderState.data, endDate: new Date(endMonthBlock.year, endMonthBlock.month + 1, 0) }, data: { ...renderState.data, endDate },
}; };
} }
const startMonthBlock = filteredDates[0]; const days = Math.abs(getNumberOfDaysBetweenTwoDates(startDate, endDate)) + 1;
const endMonthBlock = filteredDates[filteredDates.length - 1];
const startDate = new Date(startMonthBlock.year, startMonthBlock.month, 1);
const endDate = new Date(endMonthBlock.year, endMonthBlock.month + 1, 0);
const days = Math.abs(getNumberOfDaysBetweenTwoDates(startDate, endDate));
const scrollWidth = days * quarterPayload.data.dayWidth; const scrollWidth = days * quarterPayload.data.dayWidth;
return { state: renderState, payload: filteredDates, scrollWidth: scrollWidth }; return { state: renderState, payload: filteredDates, scrollWidth: scrollWidth };

View file

@ -1,7 +1,7 @@
// //
import { weeks, months } from "../data"; import { weeks, months } from "../data";
import { ChartDataType } from "../types"; import { ChartDataType } from "../types";
import { getWeekNumberByDate } from "./helpers"; import { getNumberOfDaysBetweenTwoDates, getWeekNumberByDate } from "./helpers";
export interface IDayBlock { export interface IDayBlock {
date: Date; date: Date;
day: number; day: number;
@ -46,6 +46,9 @@ const generateWeekChart = (weekPayload: ChartDataType, side: null | "left" | "ri
let minusDate: Date = new Date(); let minusDate: Date = new Date();
let plusDate: Date = new Date(); let plusDate: Date = new Date();
let startDate = new Date();
let endDate = new Date();
// if side is null generate weeks on both side of current date // if side is null generate weeks on both side of current date
if (side === null) { if (side === null) {
const currentDate = renderState.data.currentDate; const currentDate = renderState.data.currentDate;
@ -55,12 +58,14 @@ const generateWeekChart = (weekPayload: ChartDataType, side: null | "left" | "ri
if (minusDate && plusDate) filteredDates = getWeeksBetweenTwoDates(minusDate, plusDate); if (minusDate && plusDate) filteredDates = getWeeksBetweenTwoDates(minusDate, plusDate);
startDate = filteredDates[0].startDate;
endDate = filteredDates[filteredDates.length - 1].endDate;
renderState = { renderState = {
...renderState, ...renderState,
data: { data: {
...renderState.data, ...renderState.data,
startDate: filteredDates[0].startDate, startDate,
endDate: filteredDates[filteredDates.length - 1].endDate, endDate,
}, },
}; };
} }
@ -73,9 +78,11 @@ const generateWeekChart = (weekPayload: ChartDataType, side: null | "left" | "ri
if (minusDate && plusDate) filteredDates = getWeeksBetweenTwoDates(minusDate, plusDate); if (minusDate && plusDate) filteredDates = getWeeksBetweenTwoDates(minusDate, plusDate);
startDate = filteredDates[0].startDate;
endDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() - 1);
renderState = { renderState = {
...renderState, ...renderState,
data: { ...renderState.data, startDate: filteredDates[0].startDate }, data: { ...renderState.data, startDate },
}; };
} }
// When side is right, generate more weeks on the right side of the end date // When side is right, generate more weeks on the right side of the end date
@ -87,16 +94,16 @@ const generateWeekChart = (weekPayload: ChartDataType, side: null | "left" | "ri
if (minusDate && plusDate) filteredDates = getWeeksBetweenTwoDates(minusDate, plusDate); if (minusDate && plusDate) filteredDates = getWeeksBetweenTwoDates(minusDate, plusDate);
startDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() + 1);
endDate = filteredDates[filteredDates.length - 1].endDate;
renderState = { renderState = {
...renderState, ...renderState,
data: { ...renderState.data, endDate: filteredDates[filteredDates.length - 1].endDate }, data: { ...renderState.data, endDate },
}; };
} }
const scrollWidth = const days = Math.abs(getNumberOfDaysBetweenTwoDates(startDate, endDate)) + 1;
filteredDates const scrollWidth = days * weekPayload.data.dayWidth;
.map((monthData: any) => monthData.children.length)
.reduce((partialSum: number, a: number) => partialSum + a, 0) * weekPayload.data.dayWidth;
return { state: renderState, payload: filteredDates, scrollWidth: scrollWidth }; return { state: renderState, payload: filteredDates, scrollWidth: scrollWidth };
}; };

View file

@ -1,6 +1,6 @@
import { RefObject, useEffect, useRef } from "react"; import { RefObject, useEffect, useRef } from "react";
const SCROLL_BY = 1; const SCROLL_BY = 3;
const AUTO_SCROLL_THRESHOLD = 15; const AUTO_SCROLL_THRESHOLD = 15;
const MAX_SPEED_THRESHOLD = 5; const MAX_SPEED_THRESHOLD = 5;
@ -13,6 +13,7 @@ export const useAutoScroller = (
) => { ) => {
const containerDimensions = useRef<DOMRect | undefined>(); const containerDimensions = useRef<DOMRect | undefined>();
const intervalId = useRef<ReturnType<typeof setInterval> | undefined>(undefined); const intervalId = useRef<ReturnType<typeof setInterval> | undefined>(undefined);
const mousePosition = useRef<{ clientX: number; clientY: number } | undefined>(undefined);
const clearRegisteredTimeout = () => { const clearRegisteredTimeout = () => {
clearInterval(intervalId.current); clearInterval(intervalId.current);
@ -26,6 +27,15 @@ export const useAutoScroller = (
if (!rect || !shouldScroll || (e.clientX === 0 && e.clientY === 0)) return; if (!rect || !shouldScroll || (e.clientX === 0 && e.clientY === 0)) return;
let diffX = 0,
diffY = 0;
if (mousePosition.current) {
diffX = e.clientX - mousePosition.current.clientX;
diffY = e.clientY - mousePosition.current.clientY;
}
mousePosition.current = { clientX: e.clientX, clientY: e.clientY };
const { left, top, width, height } = rect; const { left, top, width, height } = rect;
const mouseX = e.clientX - left - leftOffset; const mouseX = e.clientX - left - leftOffset;
@ -44,28 +54,28 @@ export const useAutoScroller = (
scrollByY = 0; scrollByY = 0;
// Check mouse positions against thresholds // Check mouse positions against thresholds
if (mouseX < thresholdX) { if (mouseX < thresholdX && diffX <= 0) {
scrollByX = -1 * SCROLL_BY; scrollByX = -1 * SCROLL_BY;
if (mouseX < maxSpeedX) { if (mouseX < maxSpeedX) {
scrollByX *= 2; scrollByX *= 2;
} }
} }
if (mouseX > currWidth - thresholdX) { if (mouseX > currWidth - thresholdX && diffX >= 0) {
scrollByX = SCROLL_BY; scrollByX = SCROLL_BY;
if (mouseX > currWidth - maxSpeedX) { if (mouseX > currWidth - maxSpeedX) {
scrollByX *= 2; scrollByX *= 2;
} }
} }
if (mouseY < thresholdY) { if (mouseY < thresholdY && diffY <= 0) {
scrollByY = -1 * SCROLL_BY; scrollByY = -1 * SCROLL_BY;
if (mouseX < maxSpeedY) { if (mouseX < maxSpeedY) {
scrollByY *= 2; scrollByY *= 2;
} }
} }
if (mouseY > currHeight - thresholdY) { if (mouseY > currHeight - thresholdY && diffY >= 0) {
scrollByY = SCROLL_BY; scrollByY = SCROLL_BY;
if (mouseY > currHeight - maxSpeedY) { if (mouseY > currHeight - maxSpeedY) {
scrollByY *= 2; scrollByY *= 2;

View file

@ -1,8 +1,7 @@
import { autorun } from "mobx"; import { autorun } from "mobx";
// Plane-web // Plane-web
import { RootStore } from "@/plane-web/store/root.store";
import { BaseTimeLineStore, IBaseTimelineStore } from "@/plane-web/store/timeline/base-timeline.store"; import { BaseTimeLineStore, IBaseTimelineStore } from "@/plane-web/store/timeline/base-timeline.store";
// Store
import { CoreRootStore } from "@/store/root.store";
export interface IIssuesTimeLineStore extends IBaseTimelineStore { export interface IIssuesTimeLineStore extends IBaseTimelineStore {
isDependencyEnabled: boolean; isDependencyEnabled: boolean;
@ -11,7 +10,7 @@ export interface IIssuesTimeLineStore extends IBaseTimelineStore {
export class IssuesTimeLineStore extends BaseTimeLineStore implements IIssuesTimeLineStore { export class IssuesTimeLineStore extends BaseTimeLineStore implements IIssuesTimeLineStore {
isDependencyEnabled = true; isDependencyEnabled = true;
constructor(_rootStore: CoreRootStore) { constructor(_rootStore: RootStore) {
super(_rootStore); super(_rootStore);
autorun((reaction) => { autorun((reaction) => {

View file

@ -1,6 +1,6 @@
import { autorun } from "mobx"; import { autorun } from "mobx";
// Store // Store
import { CoreRootStore } from "@/store/root.store"; import { RootStore } from "@/plane-web/store/root.store";
import { BaseTimeLineStore, IBaseTimelineStore } from "ce/store/timeline/base-timeline.store"; import { BaseTimeLineStore, IBaseTimelineStore } from "ce/store/timeline/base-timeline.store";
export interface IModulesTimeLineStore extends IBaseTimelineStore { export interface IModulesTimeLineStore extends IBaseTimelineStore {
@ -10,7 +10,7 @@ export interface IModulesTimeLineStore extends IBaseTimelineStore {
export class ModulesTimeLineStore extends BaseTimeLineStore implements IModulesTimeLineStore { export class ModulesTimeLineStore extends BaseTimeLineStore implements IModulesTimeLineStore {
isDependencyEnabled = false; isDependencyEnabled = false;
constructor(_rootStore: CoreRootStore) { constructor(_rootStore: RootStore) {
super(_rootStore); super(_rootStore);
autorun((reaction) => { autorun((reaction) => {