import React, { useRef, useState } from 'react'; type Point = { x: number; y: number; }; type Drawing = { path: Path2D; offset: Point; }; const DrawingCanvas: React.FC = () => { const canvasRef = useRef(null); const [isDrawing, setIsDrawing] = useState(false); const [drawings, setDrawings] = useState([]); const [currentPath, setCurrentPath] = useState(null); const [drawMode, setDrawMode] = useState(true); // true for drawing, false for selecting const [selectMode, setSelectMode] = useState(false); const [selectMode2, setSelectMode2] = useState(false); const [selectionStart, setSelectionStart] = useState(null); const [selectedArea, setSelectedArea] = useState<{ start: Point; end: Point } | null>(null); const [selectedDrawings, setSelectedDrawings] = useState([]); const [mousePos, setMousePos] = useState(); const [dragStartPoint, setDragStartPoint] = useState(null); const handleTouchStart = (e: React.TouchEvent) => { handleMouseDown({ clientX: e.touches[0].clientX, clientY: e.touches[0].clientY, } as any); }; const handleTouchMove = (e: React.TouchEvent) => { handleMouseMove({ clientX: e.touches[0].clientX, clientY: e.touches[0].clientY, } as any); }; const handleTouchEnd = (e: React.TouchEvent) => { handleMouseUp({ clientX: e.changedTouches[0].clientX, clientY: e.changedTouches[0].clientY, } as any); }; const getCanvasRelativePosition = (e: React.MouseEvent): Point => { if (!canvasRef.current) return { x: 0, y: 0 }; const rect = canvasRef.current.getBoundingClientRect(); return { x: e.clientX - rect.left, y: e.clientY - rect.top, }; }; const redraw = () => { if (!canvasRef.current) return; const ctx = canvasRef.current.getContext('2d'); if (ctx) { ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height); ctx.save(); drawings.forEach((drawing) => { ctx.translate(drawing.offset.x, drawing.offset.y); ctx.strokeStyle = 'black'; ctx.lineWidth = 1; ctx.stroke(drawing.path); ctx.setTransform(1, 0, 0, 1, 0, 0); }); ctx.restore(); // 선택 영역이 있으면 항상 그려줍니다. if (selectedArea) { drawSelectionArea(selectedArea.start, selectedArea.end); } } }; const handleMouseDown = (e: React.MouseEvent) => { const point = getCanvasRelativePosition(e); setMousePos(point); if (drawMode) { setIsDrawing(true); const newPath = new Path2D(); newPath.moveTo(point.x, point.y); setCurrentPath(newPath); return; } if (selectMode) { if (selectedArea && isPointInsideRect(point, selectedArea)) { setDragStartPoint(point); return; } else { setSelectedDrawings([]); setDragStartPoint(null); setSelectedArea({ start: point, end: point } ); setSelectionStart(point); console.log("out"); return; } } }; const handleMouseMove = (e: React.MouseEvent) => { const point = getCanvasRelativePosition(e); if (drawMode && isDrawing && currentPath) { currentPath.lineTo(point.x, point.y); const ctx = canvasRef.current?.getContext('2d'); ctx?.stroke(currentPath); return; } if (selectMode && selectionStart && !dragStartPoint) { const normalizedArea = normalizeSelectionArea(selectionStart, point); setSelectedArea(normalizedArea); redraw(); drawSelectionArea(normalizedArea.start, normalizedArea.end); return; } if (selectedDrawings.length && mousePos && dragStartPoint) { const dx = point.x - mousePos.x; const dy = point.y - mousePos.y; const newDrawings = [...drawings]; for (let index of selectedDrawings) { newDrawings[index].offset.x += dx; newDrawings[index].offset.y += dy; } if (selectedArea) { selectedArea.start.x += dx; selectedArea.start.y += dy; selectedArea.end.x += dx; selectedArea.end.y += dy; } setDrawings(newDrawings); setMousePos(point); redraw(); if (selectedArea) { drawSelectionArea(selectedArea.start, selectedArea.end); } return; } }; const isPointInsideRect = (point: Point, rect: { start: Point; end: Point }): boolean => { return ( point.x >= rect.start.x && point.x <= rect.end.x && point.y >= rect.start.y && point.y <= rect.end.y ); }; const handleMouseUp = (e: React.MouseEvent) => { if (drawMode) { setIsDrawing(false); if (currentPath) { setDrawings([...drawings, { path: currentPath, offset: { x: 0, y: 0 } }]); setCurrentPath(null); } return; } if (selectMode && selectionStart) { if (selectedArea) { const normalizedArea = selectedArea; const selected = drawings.map((drawing, index) => isDrawingInsideSelection(drawing, normalizedArea) ? index : -1 ).filter(index => index !== -1); setSelectedDrawings(selected); redraw(); if (selected.length === 0) { setSelectedArea(null); } } setSelectionStart(null); setDragStartPoint(null); return; } setDragStartPoint(null); }; const isDrawingInsideSelection = (drawing: Drawing, selection: { start: Point; end: Point }): boolean => { const ctx = canvasRef.current?.getContext('2d'); if (!ctx) return false; const { start, end } = selection; for (let x = start.x; x <= end.x; x += 5) { for (let y = start.y; y <= end.y; y += 5) { if (ctx.isPointInPath(drawing.path, x - drawing.offset.x, y - drawing.offset.y)) { return true; } } } return false; }; const normalizeSelectionArea = (start: Point, end: Point): { start: Point; end: Point } => { return { start: { x: Math.min(start.x, end.x), y: Math.min(start.y, end.y) }, end: { x: Math.max(start.x, end.x), y: Math.max(start.y, end.y) } }; }; const drawSelectionArea = (start: Point, end: Point) => { if (!canvasRef.current) return; const ctx = canvasRef.current.getContext('2d'); if (ctx) { ctx.setLineDash([5, 5]); ctx.strokeStyle = 'blue'; ctx.strokeRect(start.x, start.y, end.x - start.x, end.y - start.y); ctx.setLineDash([]); } }; return (

); }; export default DrawingCanvas;