- Add EditorCanvas component with visual distortion area editing - Point-in-polygon detection for area selection - Individual point dragging with visual handles - Entire area dragging by clicking inside polygon - UV-space distortion circle visualization - Add AreaList component for managing multiple distortion areas - Add ParameterPanel for editing distortion properties - Base points (normalized coordinates) - Drag vectors and distortion strength - Animation duration and easing - Add DistortionEditor main component with sidebar layout - Add useDistortionEditor hook for state management - Add editor types and interfaces 사각형 내부를 클릭하여 전체 영역을 드래그할 수 있는 기능 포함
96 lines
2.5 KiB
TypeScript
96 lines
2.5 KiB
TypeScript
import { useState, useCallback } from 'react';
|
|
import { DistortionArea, Point } from '../../types/area';
|
|
import { EditorState } from '../types';
|
|
|
|
export const useDistortionEditor = (initialAreas: DistortionArea[] = []) => {
|
|
const [state, setState] = useState<EditorState>({
|
|
selectedAreaId: initialAreas[0]?.id || null,
|
|
areas: initialAreas,
|
|
editMode: 'normal',
|
|
draggingPointIndex: null,
|
|
});
|
|
|
|
/** 영역 선택 */
|
|
const selectArea = useCallback((areaId: string | null) => {
|
|
setState((prev) => ({ ...prev, selectedAreaId: areaId }));
|
|
}, []);
|
|
|
|
/** 영역 추가 */
|
|
const addArea = useCallback((area: DistortionArea) => {
|
|
setState((prev) => ({
|
|
...prev,
|
|
areas: [...prev.areas, area],
|
|
selectedAreaId: area.id,
|
|
}));
|
|
}, []);
|
|
|
|
/** 영역 삭제 */
|
|
const removeArea = useCallback((areaId: string) => {
|
|
setState((prev) => {
|
|
const newAreas = prev.areas.filter((a) => a.id !== areaId);
|
|
return {
|
|
...prev,
|
|
areas: newAreas,
|
|
selectedAreaId:
|
|
prev.selectedAreaId === areaId ? newAreas[0]?.id || null : prev.selectedAreaId,
|
|
};
|
|
});
|
|
}, []);
|
|
|
|
/** 영역 업데이트 */
|
|
const updateArea = useCallback((areaId: string, updates: Partial<DistortionArea>) => {
|
|
setState((prev) => ({
|
|
...prev,
|
|
areas: prev.areas.map((area) => (area.id === areaId ? { ...area, ...updates } : area)),
|
|
}));
|
|
}, []);
|
|
|
|
/** 포인트 업데이트 */
|
|
const updatePoint = useCallback((areaId: string, pointIndex: number, point: Point) => {
|
|
setState((prev) => ({
|
|
...prev,
|
|
areas: prev.areas.map((area) => {
|
|
if (area.id === areaId) {
|
|
const newPoints = [...area.basePoints] as [Point, Point, Point, Point];
|
|
newPoints[pointIndex] = point;
|
|
return { ...area, basePoints: newPoints };
|
|
}
|
|
return area;
|
|
}),
|
|
}));
|
|
}, []);
|
|
|
|
/** 드래그 시작 */
|
|
const startDragging = useCallback((pointIndex: number) => {
|
|
setState((prev) => ({ ...prev, draggingPointIndex: pointIndex }));
|
|
}, []);
|
|
|
|
/** 드래그 종료 */
|
|
const stopDragging = useCallback(() => {
|
|
setState((prev) => ({ ...prev, draggingPointIndex: null }));
|
|
}, []);
|
|
|
|
/** 편집 모드 변경 */
|
|
const setEditMode = useCallback((mode: EditorState['editMode']) => {
|
|
setState((prev) => ({ ...prev, editMode: mode }));
|
|
}, []);
|
|
|
|
/** 선택된 영역 가져오기 */
|
|
const getSelectedArea = useCallback(() => {
|
|
return state.areas.find((a) => a.id === state.selectedAreaId) || null;
|
|
}, [state.areas, state.selectedAreaId]);
|
|
|
|
return {
|
|
state,
|
|
selectArea,
|
|
addArea,
|
|
removeArea,
|
|
updateArea,
|
|
updatePoint,
|
|
startDragging,
|
|
stopDragging,
|
|
setEditMode,
|
|
getSelectedArea,
|
|
};
|
|
};
|