| import { useCallback } from 'react'; |
| import type { PPTElement, PPTShapeElement } from '@/lib/types/slides'; |
| import { useHistorySnapshot } from '@/lib/hooks/use-history-snapshot'; |
| import { SHAPE_PATH_FORMULAS } from '@/configs/shapes'; |
| import { useCanvasOperations } from '@/lib/hooks/use-canvas-operations'; |
|
|
| interface ShapePathData { |
| baseSize: number; |
| originPos: number; |
| min: number; |
| max: number; |
| relative: string; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function useMoveShapeKeypoint( |
| elementListRef: React.RefObject<PPTElement[]>, |
| setElementList: React.Dispatch<React.SetStateAction<PPTElement[]>>, |
| canvasScale: number, |
| ) { |
| const updateSlide = useCanvasOperations().updateSlide; |
|
|
| const { addHistorySnapshot } = useHistorySnapshot(); |
|
|
| const moveShapeKeypoint = useCallback( |
| (e: React.MouseEvent | React.TouchEvent, element: PPTShapeElement, index = 0) => { |
| const native = e.nativeEvent; |
| const isTouchEvent = native instanceof TouchEvent; |
| if (isTouchEvent && !native.changedTouches?.length) return; |
|
|
| let isMouseDown = true; |
|
|
| const startPageX = isTouchEvent ? native.changedTouches[0].pageX : native.pageX; |
| const startPageY = isTouchEvent ? native.changedTouches[0].pageY : native.pageY; |
|
|
| const originKeypoints = element.keypoints!; |
|
|
| const pathFormula = SHAPE_PATH_FORMULAS[element.pathFormula!]; |
| let shapePathData: ShapePathData | null = null; |
| if ('editable' in pathFormula && pathFormula.editable) { |
| const getBaseSize = pathFormula.getBaseSize![index]; |
| const range = pathFormula.range![index]; |
| const relative = pathFormula.relative![index]; |
| const keypoint = originKeypoints[index]; |
|
|
| const baseSize = getBaseSize(element.width, element.height); |
| const originPos = baseSize * keypoint; |
| const [min, max] = range; |
|
|
| shapePathData = { baseSize, originPos, min, max, relative }; |
| } |
|
|
| const handleMouseMove = (e: MouseEvent | TouchEvent) => { |
| if (!isMouseDown) return; |
|
|
| const currentPageX = e instanceof MouseEvent ? e.pageX : e.changedTouches[0].pageX; |
| const currentPageY = e instanceof MouseEvent ? e.pageY : e.changedTouches[0].pageY; |
| const moveX = (currentPageX - startPageX) / canvasScale; |
| const moveY = (currentPageY - startPageY) / canvasScale; |
|
|
| |
| const newElements = elementListRef.current.map((el) => { |
| if (el.id === element.id && shapePathData) { |
| const { baseSize, originPos, min, max, relative } = shapePathData; |
| const shapeElement = el as PPTShapeElement; |
|
|
| let keypoint = 0; |
|
|
| if (relative === 'center') keypoint = (originPos - moveX * 2) / baseSize; |
| else if (relative === 'left') keypoint = (originPos + moveX) / baseSize; |
| else if (relative === 'right') keypoint = (originPos - moveX) / baseSize; |
| else if (relative === 'top') keypoint = (originPos + moveY) / baseSize; |
| else if (relative === 'bottom') keypoint = (originPos - moveY) / baseSize; |
| else if (relative === 'left_bottom') keypoint = (originPos + moveX) / baseSize; |
| else if (relative === 'right_bottom') keypoint = (originPos - moveX) / baseSize; |
| else if (relative === 'top_right') keypoint = (originPos + moveY) / baseSize; |
| else if (relative === 'bottom_right') keypoint = (originPos - moveY) / baseSize; |
|
|
| if (keypoint < min) keypoint = min; |
| if (keypoint > max) keypoint = max; |
|
|
| let keypoints: number[] = []; |
| if (Array.isArray(originKeypoints)) { |
| keypoints = [...originKeypoints]; |
| keypoints[index] = keypoint; |
| } else keypoints = [keypoint]; |
|
|
| return { |
| ...el, |
| keypoints, |
| path: pathFormula.formula(shapeElement.width, shapeElement.height, keypoints), |
| }; |
| } |
| return el; |
| }); |
|
|
| |
| elementListRef.current = newElements; |
| setElementList(newElements); |
| }; |
|
|
| const handleMouseUp = (e: MouseEvent | TouchEvent) => { |
| isMouseDown = false; |
|
|
| document.ontouchmove = null; |
| document.ontouchend = null; |
| document.onmousemove = null; |
| document.onmouseup = null; |
|
|
| const currentPageX = e instanceof MouseEvent ? e.pageX : e.changedTouches[0].pageX; |
| const currentPageY = e instanceof MouseEvent ? e.pageY : e.changedTouches[0].pageY; |
|
|
| if (startPageX === currentPageX && startPageY === currentPageY) return; |
|
|
| updateSlide({ elements: elementListRef.current }); |
| addHistorySnapshot(); |
| }; |
|
|
| if (isTouchEvent) { |
| document.ontouchmove = handleMouseMove; |
| document.ontouchend = handleMouseUp; |
| } else { |
| document.onmousemove = handleMouseMove; |
| document.onmouseup = handleMouseUp; |
| } |
| }, |
| [elementListRef, setElementList, canvasScale, updateSlide, addHistorySnapshot], |
| ); |
|
|
| return { |
| moveShapeKeypoint, |
| }; |
| } |
|
|