[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:
parent
a88a39fb1e
commit
724adeff5c
15 changed files with 128 additions and 60 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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: {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue