가로 세로 가운데 안내선 추가

This commit is contained in:
dohyeons 2025-10-02 11:54:15 +09:00
parent ae616ae611
commit fdc476a9e0
1 changed files with 69 additions and 54 deletions

View File

@ -168,60 +168,6 @@ export function ReportDesignerProvider({ reportId, children }: { reportId: strin
[snapToGrid, gridSize],
);
// 정렬 가이드라인 계산 (드래그 중인 컴포넌트 제외)
const calculateAlignmentGuides = useCallback(
(draggingId: string, x: number, y: number, width: number, height: number) => {
const verticalLines: number[] = [];
const horizontalLines: number[] = [];
// 드래그 중인 컴포넌트의 주요 위치
const left = x;
const right = x + width;
const centerX = x + width / 2;
const top = y;
const bottom = y + height;
const centerY = y + height / 2;
// 다른 컴포넌트들과 비교
components.forEach((comp) => {
if (comp.id === draggingId) return;
const compLeft = comp.x;
const compRight = comp.x + comp.width;
const compCenterX = comp.x + comp.width / 2;
const compTop = comp.y;
const compBottom = comp.y + comp.height;
const compCenterY = comp.y + comp.height / 2;
// 세로 정렬 체크 (left, center, right) - 정확히 일치할 때만
if (left === compLeft) verticalLines.push(compLeft);
if (left === compRight) verticalLines.push(compRight);
if (right === compLeft) verticalLines.push(compLeft);
if (right === compRight) verticalLines.push(compRight);
if (centerX === compCenterX) verticalLines.push(compCenterX);
// 가로 정렬 체크 (top, center, bottom) - 정확히 일치할 때만
if (top === compTop) horizontalLines.push(compTop);
if (top === compBottom) horizontalLines.push(compBottom);
if (bottom === compTop) horizontalLines.push(compTop);
if (bottom === compBottom) horizontalLines.push(compBottom);
if (centerY === compCenterY) horizontalLines.push(compCenterY);
});
// 중복 제거
setAlignmentGuides({
vertical: Array.from(new Set(verticalLines)),
horizontal: Array.from(new Set(horizontalLines)),
});
},
[components],
);
// 정렬 가이드라인 초기화
const clearAlignmentGuides = useCallback(() => {
setAlignmentGuides({ vertical: [], horizontal: [] });
}, []);
// 복사 (Ctrl+C)
const copyComponents = useCallback(() => {
if (selectedComponentIds.length > 0) {
@ -778,6 +724,75 @@ export function ReportDesignerProvider({ reportId, children }: { reportId: strin
right: 20,
});
// 정렬 가이드라인 계산 (캔버스 중앙선 포함)
const calculateAlignmentGuides = useCallback(
(draggingId: string, x: number, y: number, width: number, height: number) => {
const verticalLines: number[] = [];
const horizontalLines: number[] = [];
const threshold = 5; // 5px 오차 허용
// 캔버스를 픽셀로 변환 (1mm = 3.7795px)
const canvasWidthPx = canvasWidth * 3.7795;
const canvasHeightPx = canvasHeight * 3.7795;
const canvasCenterX = canvasWidthPx / 2;
const canvasCenterY = canvasHeightPx / 2;
// 드래그 중인 컴포넌트의 주요 위치
const left = x;
const right = x + width;
const centerX = x + width / 2;
const top = y;
const bottom = y + height;
const centerY = y + height / 2;
// 캔버스 중앙선 체크
if (Math.abs(centerX - canvasCenterX) < threshold) {
verticalLines.push(canvasCenterX);
}
if (Math.abs(centerY - canvasCenterY) < threshold) {
horizontalLines.push(canvasCenterY);
}
// 다른 컴포넌트들과 비교
components.forEach((comp) => {
if (comp.id === draggingId) return;
const compLeft = comp.x;
const compRight = comp.x + comp.width;
const compCenterX = comp.x + comp.width / 2;
const compTop = comp.y;
const compBottom = comp.y + comp.height;
const compCenterY = comp.y + comp.height / 2;
// 세로 정렬 체크 (left, center, right) - 오차 허용
if (Math.abs(left - compLeft) < threshold) verticalLines.push(compLeft);
if (Math.abs(left - compRight) < threshold) verticalLines.push(compRight);
if (Math.abs(right - compLeft) < threshold) verticalLines.push(compLeft);
if (Math.abs(right - compRight) < threshold) verticalLines.push(compRight);
if (Math.abs(centerX - compCenterX) < threshold) verticalLines.push(compCenterX);
// 가로 정렬 체크 (top, center, bottom) - 오차 허용
if (Math.abs(top - compTop) < threshold) horizontalLines.push(compTop);
if (Math.abs(top - compBottom) < threshold) horizontalLines.push(compBottom);
if (Math.abs(bottom - compTop) < threshold) horizontalLines.push(compTop);
if (Math.abs(bottom - compBottom) < threshold) horizontalLines.push(compBottom);
if (Math.abs(centerY - compCenterY) < threshold) horizontalLines.push(compCenterY);
});
// 중복 제거
setAlignmentGuides({
vertical: Array.from(new Set(verticalLines)),
horizontal: Array.from(new Set(horizontalLines)),
});
},
[components, canvasWidth, canvasHeight],
);
// 정렬 가이드라인 초기화
const clearAlignmentGuides = useCallback(() => {
setAlignmentGuides({ vertical: [], horizontal: [] });
}, []);
// 리포트 및 레이아웃 로드
const loadLayout = useCallback(async () => {
setIsLoading(true);