import { RefObject, useCallback, useEffect, useMemo, useRef, useState, } from "react"; import { Line, Circle, Group } from "react-konva"; import { minMax, toRGBColorString, dragBoundFunc, flattenPoints, } from "@/utils/canvasUtil"; import type { KonvaEventObject } from "konva/lib/Node"; import Konva from "konva"; import { Vector2d } from "konva/lib/types"; type PolygonDrawerProps = { stageRef: RefObject; points: number[][]; isActive: boolean; isHovered: boolean; isFinished: boolean; color: number[]; handlePointDragMove: (e: KonvaEventObject) => void; handleGroupDragEnd: (e: KonvaEventObject) => void; }; export default function PolygonDrawer({ stageRef, points, isActive, isHovered, isFinished, color, handlePointDragMove, handleGroupDragEnd, }: PolygonDrawerProps) { const vertexRadius = 6; const flattenedPoints = useMemo(() => flattenPoints(points), [points]); const [minMaxX, setMinMaxX] = useState([0, 0]); const [minMaxY, setMinMaxY] = useState([0, 0]); const groupRef = useRef(null); const [cursor, setCursor] = useState("default"); const handleMouseOverPoint = ( e: KonvaEventObject, ) => { if (!e.target) return; if (!isFinished && points.length >= 3 && e.target.name() === "point-0") { e.target.scale({ x: 2, y: 2 }); setCursor("crosshair"); } else { setCursor("move"); } }; const handleMouseOutPoint = ( e: KonvaEventObject, ) => { if (!e.target) return; if (isFinished) { setCursor("default"); } else { setCursor("crosshair"); } if (e.target.name() === "point-0") { e.target.scale({ x: 1, y: 1 }); } }; const handleGroupDragStart = () => { const arrX = points.map((p) => p[0]); const arrY = points.map((p) => p[1]); setMinMaxX(minMax(arrX)); setMinMaxY(minMax(arrY)); }; const groupDragBound = (pos: Vector2d) => { if (!stageRef.current) { return pos; } let { x, y } = pos; const sw = stageRef.current.width(); const sh = stageRef.current.height(); if (minMaxY[0] + y < 0) y = -1 * minMaxY[0]; if (minMaxX[0] + x < 0) x = -1 * minMaxX[0]; if (minMaxY[1] + y > sh) y = sh - minMaxY[1]; if (minMaxX[1] + x > sw) x = sw - minMaxX[1]; return { x, y }; }; const colorString = useCallback( (darkened: boolean) => { return toRGBColorString(color, darkened); }, [color], ); useEffect(() => { if (!stageRef.current) { return; } stageRef.current.container().style.cursor = cursor; }, [stageRef, cursor]); return ( isFinished ? setCursor("move") : setCursor("crosshair") } onMouseOut={() => isFinished ? setCursor("default") : setCursor("crosshair") } /> {isFinished && isActive && ( setCursor("crosshair")} onMouseOut={() => isFinished ? setCursor("default") : setCursor("crosshair") } /> )} {points.map((point, index) => { if (!isActive) { return; } const x = point[0]; const y = point[1]; return ( { if (stageRef.current) { return dragBoundFunc( stageRef.current.width(), stageRef.current.height(), vertexRadius, pos, ); } else { return pos; } }} /> ); })} ); }