diff --git a/frontend/src/component/canvas/Canvas.tsx b/frontend/src/component/canvas/Canvas.tsx index 3c511755..f1406b3c 100644 --- a/frontend/src/component/canvas/Canvas.tsx +++ b/frontend/src/component/canvas/Canvas.tsx @@ -1,5 +1,13 @@ import classNames from 'classnames'; -import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react'; +import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react'; +import { useDrawing } from '@/hooks/useDrawing.ts'; +import { usePanning } from '@/hooks/usePanning.ts'; +import { useZoom } from '@/hooks/useZoom.ts'; +import { MdArrowCircleLeft, MdArrowCircleRight } from 'react-icons/md'; +import { useUndoRedo } from '@/hooks/useUndoRedo.ts'; +import { ButtonState } from '@/component/common/enums.ts'; +import { useFloatingButton } from '@/hooks/useFloatingButton.ts'; +import { FloatingButton } from '@/component/common/floatingbutton/FloatingButton.tsx'; interface ICanvasProps { className?: string; @@ -9,13 +17,38 @@ interface ICanvasProps { // onMouseMove?: () => void; } +interface IPoint { + x: number; + y: number; +} + +// 네이버 지도 기준 확대/축소 비율 단계 +const NAVER_STEP_SCALES = [ + 100, 100, 100, 100, 100, 100, 50, 30, 20, 10, 5, 3, 1, 0.5, 0.3, 0.1, 0.05, 0.03, 0.02, 0.01, + 0.005, +]; + +// 선의 굵기 상수 +const LINE_WIDTH = 2; +// 선의 색 상수 +const STROKE_STYLE = 'black'; +// 지도의 처음 확대/축소 비율 단계 index +const INITIAL_ZOOM_INDEX = 12; + export interface ICanvasRefMethods { getCanvasElement: () => HTMLCanvasElement | null; - onMouseClickHandler: (event?: React.MouseEvent) => void; + onMouseClickHandler: (event: React.MouseEvent) => void; + onMouseDownHandler: (event: React.MouseEvent) => void; + onMouseMoveHandler: (event: React.MouseEvent) => void; + onMouseUpHandler: (event: React.MouseEvent) => void; } export const Canvas = forwardRef((props, ref) => { const canvasRef = useRef(null); + const { points, addPoint, undo, redo, undoStack, redoStack } = useUndoRedo([]); + const [startPoint, setStartPoint] = useState(null); + const [endPoint, setEndPoint] = useState(null); + const { isMenuOpen, toolType, toggleMenu, handleMenuClick } = useFloatingButton(); useEffect(() => { const canvas = canvasRef.current; @@ -28,20 +61,110 @@ export const Canvas = forwardRef((props, ref) = canvas.height = canvas.offsetHeight; }, []); + const { draw, scaleRef, viewPosRef } = useDrawing({ + canvasRef, + points, + startPoint, + endPoint, + lineWidth: LINE_WIDTH, + strokeStyle: STROKE_STYLE, + initialScale: NAVER_STEP_SCALES[INITIAL_ZOOM_INDEX], + }); + + const { handleMouseMove, handleMouseDown, handleMouseUp } = usePanning({ viewPosRef, draw }); + const { handleWheel } = useZoom({ + scaleRef, + viewPosRef, + draw, + stepScales: NAVER_STEP_SCALES, + initialZoomIndex: INITIAL_ZOOM_INDEX, + }); + + const handleCanvasClick = (e: React.MouseEvent) => { + const rect = canvasRef.current?.getBoundingClientRect(); + if (!rect) return; + + const x = (e.clientX - rect.left - viewPosRef.current.x) / scaleRef.current; + const y = (e.clientY - rect.top - viewPosRef.current.y) / scaleRef.current; + + switch (toolType) { + case ButtonState.LINE_DRAWING: + addPoint({ x, y }); + break; + case ButtonState.START_MARKER: + setStartPoint({ x, y }); + break; + case ButtonState.DESTINATION_MARKER: + setEndPoint({ x, y }); + break; + default: + addPoint({ x, y }); + break; + } + + draw(); + }; + useImperativeHandle(ref, () => ({ getCanvasElement: () => canvasRef.current ?? null, onMouseClickHandler: event => { - console.log(event?.screenX, event?.screenY); + handleCanvasClick(event); + }, + onMouseDownHandler: event => { + handleMouseDown(event); + }, + onMouseUpHandler: () => { + handleMouseUp(); + }, + onMouseMoveHandler: event => { + handleMouseMove(event); }, })); return ( - +
+
+ + +
+ +
+ +
+
); }); diff --git a/frontend/src/component/canvas/CanvasWithMap.tsx b/frontend/src/component/canvas/CanvasWithMap.tsx index b7063345..2b41a5aa 100644 --- a/frontend/src/component/canvas/CanvasWithMap.tsx +++ b/frontend/src/component/canvas/CanvasWithMap.tsx @@ -1,4 +1,4 @@ -import { Canvas, ICanvasRefMethods } from '@/component/canvas/LineDrawer_test.tsx'; +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';