Skip to content

Commit

Permalink
fix: SCHEDULER-111: improved scrolling
Browse files Browse the repository at this point in the history
  • Loading branch information
arek-bitnoise committed Jun 27, 2024
1 parent 49a88a4 commit 2bb227f
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 56 deletions.
15 changes: 10 additions & 5 deletions src/components/Calendar/Grid/Grid.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { forwardRef, useCallback, useEffect, useRef } from "react";
import { drawGrid } from "@/utils/drawGrid/drawGrid";
import { boxHeight, canvasWrapperId, leftColumnWidth, screenWidthMultiplier } from "@/constants";
import { boxHeight, canvasWrapperId, leftColumnWidth, outsideWrapperId } from "@/constants";
import { Loader, Tiles } from "@/components";
import { useCalendar } from "@/context/CalendarProvider";
import { resizeCanvas } from "@/utils/resizeCanvas";
import { getCanvasWidth } from "@/utils/getCanvasWidth";
import { GridProps } from "./types";
import { StyledCanvas, StyledInnerWrapper, StyledSpan, StyledWrapper } from "./styles";

Expand All @@ -18,7 +19,7 @@ const Grid = forwardRef<HTMLDivElement, GridProps>(function Grid(

const handleResize = useCallback(
(ctx: CanvasRenderingContext2D) => {
const width = window.innerWidth * screenWidthMultiplier;
const width = getCanvasWidth();
const height = rows * boxHeight + 1;
resizeCanvas(ctx, width, height);
drawGrid(ctx, zoom, rows, cols, startDate);
Expand Down Expand Up @@ -50,8 +51,9 @@ const Grid = forwardRef<HTMLDivElement, GridProps>(function Grid(

useEffect(() => {
if (!refRight.current) return;
const observerRight = new IntersectionObserver((e) =>
e[0].isIntersecting ? handleScrollNext() : null
const observerRight = new IntersectionObserver(
(e) => (e[0].isIntersecting ? handleScrollNext() : null),
{ root: document.getElementById(outsideWrapperId) }
);
observerRight.observe(refRight.current);

Expand All @@ -62,7 +64,10 @@ const Grid = forwardRef<HTMLDivElement, GridProps>(function Grid(
if (!refLeft.current) return;
const observerLeft = new IntersectionObserver(
(e) => (e[0].isIntersecting ? handleScrollPrev() : null),
{ rootMargin: `0px 0px 0px -${leftColumnWidth}px` }
{
root: document.getElementById(outsideWrapperId),
rootMargin: `0px 0px 0px -${leftColumnWidth}px`
}
);
observerLeft.observe(refLeft.current);

Expand Down
11 changes: 9 additions & 2 deletions src/components/Calendar/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { FC, useCallback, useEffect, useRef } from "react";
import { headerHeight, screenWidthMultiplier, canvasHeaderWrapperId } from "@/constants";
import {
headerHeight,
screenWidthMultiplier,
canvasHeaderWrapperId,
outsideWrapperId,
leftColumnWidth
} from "@/constants";
import { useCalendar } from "@/context/CalendarProvider";
import { useLanguage } from "@/context/LocaleProvider";
import { drawHeader } from "@/utils/drawHeader/drawHeader";
import { resizeCanvas } from "@/utils/resizeCanvas";
import { getCanvasWidth } from "@/utils/getCanvasWidth";
import { HeaderProps } from "./types";
import { StyledCanvas, StyledOuterWrapper, StyledWrapper } from "./styles";
import Topbar from "./Topbar";
Expand All @@ -15,7 +22,7 @@ const Header: FC<HeaderProps> = ({ zoom, topBarWidth }) => {

const handleResize = useCallback(
(ctx: CanvasRenderingContext2D) => {
const width = window.innerWidth * screenWidthMultiplier;
const width = getCanvasWidth();
const height = headerHeight + 1;
resizeCanvas(ctx, width, height);

Expand Down
1 change: 0 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,5 @@ export const maxHoursPerDay = 8;
export const topRowTextYPos = headerMonthHeight / 2 + 2;
export const middleRowTextYPos = headerWeekHeight / 2 + headerMonthHeight + 1;
export const buttonWeeksJump = 2;
export const scrollWeeksJump = 4;
export const minutesInHour = 60;
export const tileDefaultBgColor = "rgb(114,141,226)";
59 changes: 25 additions & 34 deletions src/context/CalendarProvider/CalendarProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,9 @@ import { Coords, ZoomLevel, allZoomLevel } from "@/types/global";
import { isAvailableZoom } from "@/types/guards";
import { getDatesRange, getParsedDatesRange } from "@/utils/getDatesRange";
import { parseDay } from "@/utils/dates";
import { getCols } from "@/utils/getCols";
import {
buttonWeeksJump,
dayWidth,
outsideWrapperId,
screenWidthMultiplier,
scrollWeeksJump,
weekWidth
} from "@/constants";
import { getCols, getVisibleCols } from "@/utils/getCols";
import { buttonWeeksJump, outsideWrapperId } from "@/constants";
import { getCanvasWidth } from "@/utils/getCanvasWidth";
import { calendarContext } from "./calendarContext";
import { CalendarProviderProps } from "./types";
dayjs.extend(weekOfYear);
Expand Down Expand Up @@ -52,48 +46,37 @@ const CalendarProvider = ({
const parsedStartDate = parseDay(startDate);
const outsideWrapper = useRef<HTMLElement | null>(null);
const [tilesCoords, setTilesCoords] = useState<Coords[]>([{ x: 0, y: 0 }]);
const scrollForwardOffsetModifier = 2;

const moveHorizontalScroll = useCallback(
(direction: Direction, behavior: ScrollBehavior = "smooth") => {
(direction: Direction, behavior: ScrollBehavior = "auto") => {
const canvasWidth = getCanvasWidth();
switch (direction) {
case "back":
return outsideWrapper.current?.scrollTo({
behavior,
left: zoom === 0 ? weekWidth * screenWidthMultiplier : dayWidth * screenWidthMultiplier
left: canvasWidth / 3
});

case "forward":
return outsideWrapper.current?.scrollTo({
behavior,
left:
zoom === 0
? window.innerWidth +
(cols / screenWidthMultiplier -
screenWidthMultiplier +
scrollForwardOffsetModifier) *
weekWidth
: window.innerWidth +
(cols / screenWidthMultiplier -
screenWidthMultiplier +
scrollForwardOffsetModifier) *
dayWidth
left: canvasWidth / 3
});

case "middle":
return outsideWrapper.current?.scrollTo({
behavior,
left: window.innerWidth
left: canvasWidth / 2
});

default:
return outsideWrapper.current?.scrollTo({
behavior,
left: window.innerWidth
left: canvasWidth / 2
});
}
},
[cols, zoom]
[]
);

const updateTilesCoords = (coords: Coords[]) => {
Expand All @@ -102,13 +85,15 @@ const CalendarProvider = ({

const loadMore = useCallback(
(direction: Direction) => {
const cols = getVisibleCols(zoom);
const offset = zoom === 0 ? cols * 7 : cols;
const load = debounce(() => {
switch (direction) {
case "back":
setDate((prev) => prev.subtract(scrollWeeksJump, "weeks"));
setDate((prev) => prev.subtract(offset, "days"));
break;
case "forward":
setDate((prev) => prev.add(scrollWeeksJump, "weeks"));
setDate((prev) => prev.add(offset, "days"));
break;
case "middle":
setDate(dayjs());
Expand All @@ -123,6 +108,7 @@ const CalendarProvider = ({

useEffect(() => {
outsideWrapper.current = document.getElementById(outsideWrapperId);
setCols(getCols(zoom));
}, []);

useEffect(() => {
Expand All @@ -143,7 +129,7 @@ const CalendarProvider = ({
useEffect(() => {
if (isInitialized) return;

moveHorizontalScroll("middle", "auto");
moveHorizontalScroll("middle");
setIsInitialized(true);
setDate(defaultStartDate);
}, [defaultStartDate, isInitialized, moveHorizontalScroll]);
Expand All @@ -159,7 +145,9 @@ const CalendarProvider = ({
if (isLoading) return;

loadMore("forward");
moveHorizontalScroll("forward");
debounce(() => {
moveHorizontalScroll("forward");
}, 300)();
}, [isLoading, loadMore, moveHorizontalScroll]);

const handleGoPrev = () => {
Expand All @@ -171,16 +159,19 @@ const CalendarProvider = ({

const handleScrollPrev = useCallback(() => {
if (!isInitialized || isLoading) return;

loadMore("back");
moveHorizontalScroll("back");
debounce(() => {
moveHorizontalScroll("back");
}, 300)();
}, [isInitialized, isLoading, loadMore, moveHorizontalScroll]);

const handleGoToday = useCallback(() => {
if (isLoading) return;

loadMore("middle");
moveHorizontalScroll("middle");
debounce(() => {
moveHorizontalScroll("middle");
}, 300)();
}, [isLoading, loadMore, moveHorizontalScroll]);

const zoomIn = () => changeZoom(zoom + 1);
Expand Down
7 changes: 7 additions & 0 deletions src/utils/getCanvasWidth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { outsideWrapperId, leftColumnWidth, screenWidthMultiplier } from "@/constants";

export const getCanvasWidth = () => {
const wrapperWidth = document.getElementById(outsideWrapperId)?.clientWidth || 0;
const width = (wrapperWidth - leftColumnWidth) * screenWidthMultiplier;
return width;
};
22 changes: 17 additions & 5 deletions src/utils/getCols.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { weekWidth, screenWidthMultiplier, dayWidth } from "@/constants";
import {
weekWidth,
dayWidth,
outsideWrapperId,
leftColumnWidth,
screenWidthMultiplier
} from "@/constants";

export const getCols = (zoom: number) =>
zoom === 0
? Math.ceil(window.innerWidth / weekWidth) * screenWidthMultiplier
: Math.ceil(window.innerWidth / dayWidth) * screenWidthMultiplier;
export const getCols = (zoom: number) => {
const wrapperWidth = document.getElementById(outsideWrapperId)?.clientWidth || 0;
const componentWidth = wrapperWidth - leftColumnWidth;
const visibleCols =
zoom === 0 ? Math.ceil(componentWidth / weekWidth) : Math.ceil(componentWidth / dayWidth);

return visibleCols * screenWidthMultiplier;
};

export const getVisibleCols = (zoom: number) => getCols(zoom) / screenWidthMultiplier;
13 changes: 4 additions & 9 deletions src/utils/getDatesRange.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import dayjs from "dayjs";
import { weekWidth, dayWidth } from "@/constants";
import { getCols } from "./getCols";

export type DatesRange = {
startDate: dayjs.Dayjs;
Expand All @@ -12,16 +12,11 @@ export type ParsedDatesRange = {
};

export const getDatesRange = (date: dayjs.Dayjs, zoom: number): DatesRange => {
const cols =
zoom === 0
? Math.ceil(window.innerWidth / weekWidth) * 3
: Math.ceil(window.innerWidth / dayWidth) * 3;
const colsOffset = getCols(zoom) / 2;
const startDate =
zoom === 0
? date.subtract(cols / 3 + 3, "weeks").set("day", 1)
: date.subtract(cols / 3 + 3, "days");
zoom === 0 ? date.subtract(colsOffset, "weeks") : date.subtract(colsOffset, "days");

const endDate = zoom === 0 ? startDate.add(cols, "weeks") : startDate.add(cols, "days");
const endDate = zoom === 0 ? date.add(colsOffset, "weeks") : date.add(colsOffset, "days");

return {
startDate,
Expand Down

0 comments on commit 2bb227f

Please sign in to comment.