Skip to content

Commit

Permalink
Merge pull request #251 from boostcampwm-2024/feature/fe/#224-refacto…
Browse files Browse the repository at this point in the history
…ring-canvas-with-map

[FE][Refactor] #224 : CanvasWithMap 이벤트 함수를 훅으로 분리
  • Loading branch information
effozen authored Nov 24, 2024
2 parents 2f32b00 + 6a6a6ca commit 7a0f842
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:

- name: Run Build
run: pnpm build # pnpm을 사용하여 빌드 실행
continue-on-error: false # 빌드 실패 시 워크플로우 실패로 처리
# continue-on-error: false # 빌드 실패 시 워크플로우 실패로 처리

- name: Run Tests
run: pnpm test # pnpm을 사용하여 테스트 실행
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/component/canvas/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export interface ICanvasRefMethods {
}

export const Canvas = forwardRef<ICanvasRefMethods, ICanvasProps>((props, ref) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null!);
const { points, addPoint, undo, redo, undoStack, redoStack } = useUndoRedo([]);
const [startPoint, setStartPoint] = useState<IPoint | null>(null);
const [endPoint, setEndPoint] = useState<IPoint | null>(null);
Expand Down
83 changes: 17 additions & 66 deletions frontend/src/component/canvas/CanvasWithMap.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Canvas, ICanvasRefMethods } from '@/component/canvas/Canvas.tsx';
import { Map, IMapRefMethods } from '@/component/maps/Map.tsx';
import classNames from 'classnames';
import { ICanvasVertex } from '@/utils/screen/canvasUtils.ts';
import { INaverMapVertexPosition } from '@/component/maps/naverMapUtils.ts';
import { useRef, useEffect, useState } from 'react';
import classNames from 'classnames';
import { Canvas, ICanvasRefMethods } from '@/component/canvas/Canvas.tsx';
import { Map } from '@/component/maps/Map.tsx';
import { IMapObject, IMapRefMethods } from '@/component/maps/Map.types.ts';
import { useEventHandlers } from '@/component/canvas/useEventHandlers.tsx';

interface ICanvasWithMapProps {
className?: string;
Expand All @@ -14,32 +14,13 @@ interface ICanvasWithMapProps {
allowCanvas?: boolean;
}

interface IMouseEventState {
isMouseDown: boolean;
mouseDownPosition: { x: number; y: number };
// mouseMovePosition: { x: number; y: number };
mouseDeltaPosition: { x: number; y: number };
}

export interface ILocationObject {
canvas: ICanvasVertex;
map: INaverMapVertexPosition;
}

const MouseEventStateInitialValue = {
isMouseDown: false,
mouseDownPosition: { x: 0, y: 0 },
// mouseMovePosition: { x: 0, y: 0 },
mouseDeltaPosition: { x: 0, y: 0 },
};

export const CanvasWithMap = (props: ICanvasWithMapProps) => {
const mapRefMethods = useRef<IMapRefMethods | null>(null);
const mapElement = useRef<HTMLElement | null>(null);
const canvasRefMethods = useRef<ICanvasRefMethods | null>(null);
const mapElement = useRef<HTMLElement | null>(null);
const canvasElement = useRef<HTMLCanvasElement | null>(null);
const mouseEventState = useRef<IMouseEventState>({ ...MouseEventStateInitialValue });
const [mapObject, setMapObject] = useState<naver.maps.Map | null>(null);

const [mapObject, setMapObject] = useState<IMapObject | null>(null);

useEffect(() => {
if (canvasRefMethods.current?.getCanvasElement)
Expand All @@ -50,46 +31,16 @@ export const CanvasWithMap = (props: ICanvasWithMapProps) => {
mapElement.current = mapRefMethods.current?.getMapContainer() ?? null;
}, [mapObject]);

const initMap = (mapObj: naver.maps.Map | null) => {
setMapObject(mapObj);
};

const handleClick = (event: React.MouseEvent) => {
mapRefMethods.current?.onMouseClickHandler(event);
canvasRefMethods.current?.onMouseClickHandler(event);
};

const handleMouseDown = (event: React.MouseEvent<HTMLElement>) => {
if (!mapElement.current || !canvasElement.current) return;
mouseEventState.current.isMouseDown = true;
mouseEventState.current.mouseDownPosition = { x: event.clientX, y: event.clientY };
canvasRefMethods.current?.onMouseDownHandler(event);
};

const handleMouseMove = (event: React.MouseEvent<HTMLElement>) => {
if (!mapElement.current || !canvasElement.current || !mouseEventState.current.isMouseDown)
return;

// TODO: 쓰로틀링 걸기
mouseEventState.current.mouseDeltaPosition = {
x: -(event.clientX - mouseEventState.current.mouseDownPosition.x),
y: -(event.clientY - mouseEventState.current.mouseDownPosition.y),
};

mapObject?.panBy(
new naver.maps.Point(
mouseEventState.current.mouseDeltaPosition.x,
mouseEventState.current.mouseDeltaPosition.y,
),
);

canvasRefMethods.current?.onMouseMoveHandler(event);
};
const { handleClick, handleMouseDown, handleMouseMove, handleMouseUp } = useEventHandlers(
canvasElement.current,
canvasRefMethods.current,
mapElement.current,
mapRefMethods.current,
mapObject,
);

const handleMouseUp = (event: React.MouseEvent) => {
if (!mapElement.current || !canvasElement.current) return;
mouseEventState.current = { ...MouseEventStateInitialValue };
canvasRefMethods.current?.onMouseUpHandler(event);
const initMap = (mapObj: IMapObject | null) => {
setMapObject(mapObj);
};

return (
Expand Down
86 changes: 86 additions & 0 deletions frontend/src/component/canvas/useEventHandlers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { useRef } from 'react';
import { ICanvasRefMethods } from '@/component/canvas/Canvas.tsx';
import { IMapObject, IMapRefMethods } from '@/component/maps/Map.types.ts';

// TODO: 리팩토룅 시 null을 처리하기
interface IUseEventHandlers {
(
canvasElement: HTMLCanvasElement | null,
canvasRefMethods: ICanvasRefMethods | null,
mapElement: HTMLElement | null,
mapRefMethods: IMapRefMethods | null,
mapObject: IMapObject | null, // 비동기 로딩 시 null로 처리가 될 수 있어서 예외처리 필요
): {
handleClick: (event: React.MouseEvent) => void;
handleMouseDown: (event: React.MouseEvent) => void;
handleMouseMove: (event: React.MouseEvent) => void;
handleMouseUp: (event: React.MouseEvent) => void;
};
}

interface IMouseEventState {
isMouseDown: boolean;
mouseDownPosition: { x: number; y: number };
// mouseMovePosition: { x: number; y: number };
mouseDeltaPosition: { x: number; y: number };
}

const MouseEventStateInitialValue = {
isMouseDown: false,
mouseDownPosition: { x: 0, y: 0 },
// mouseMovePosition: { x: 0, y: 0 },
mouseDeltaPosition: { x: 0, y: 0 },
};

export const useEventHandlers: IUseEventHandlers = (
canvasElement,
canvasRefMethods,
mapElement,
mapRefMethods,
mapObject,
) => {
// if (!canvasElement || !canvasElement || !mapElement || !mapRefMethods || !mapObject)
// throw new Error('🚀 useEventHandler error : null 값이 포함되어 있습니다.');

const mouseEventState = useRef<IMouseEventState>({ ...MouseEventStateInitialValue });

const handleClick = (event: React.MouseEvent) => {
mapRefMethods?.onMouseClickHandler(event);
canvasRefMethods?.onMouseClickHandler(event);
};

const handleMouseDown = (event: React.MouseEvent) => {
if (!mapElement || !canvasElement) return;
mouseEventState.current.isMouseDown = true;
mouseEventState.current.mouseDownPosition = { x: event.clientX, y: event.clientY };
canvasRefMethods?.onMouseDownHandler(event);
};

const handleMouseMove = (event: React.MouseEvent) => {
if (!mapElement || !canvasElement || !mouseEventState.current.isMouseDown) return;

// TODO: 쓰로틀링 걸기
mouseEventState.current.mouseDeltaPosition = {
x: -(event.clientX - mouseEventState.current.mouseDownPosition.x),
y: -(event.clientY - mouseEventState.current.mouseDownPosition.y),
};

// TODO: 범용 지도에 따른 Refactoring 필요, 우선은 네이버 지도에 한해서만 수행
mapObject?.panBy(
new naver.maps.Point(
mouseEventState.current.mouseDeltaPosition.x,
mouseEventState.current.mouseDeltaPosition.y,
),
);

canvasRefMethods?.onMouseMoveHandler(event);
};

const handleMouseUp = (event: React.MouseEvent) => {
if (!mapElement || !canvasElement) return;
mouseEventState.current = { ...MouseEventStateInitialValue };
canvasRefMethods?.onMouseUpHandler(event);
};

return { handleClick, handleMouseDown, handleMouseMove, handleMouseUp };
};

0 comments on commit 7a0f842

Please sign in to comment.