리포트 관리 중간 병합 #90

Merged
hyeonsu merged 53 commits from feature/report into main 2025-10-13 15:19:02 +09:00
2 changed files with 43 additions and 8 deletions
Showing only changes of commit f19db38973 - Show all commits

View File

@ -20,6 +20,8 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
snapValueToGrid,
calculateAlignmentGuides,
clearAlignmentGuides,
canvasWidth,
canvasHeight,
} = useReportDesigner();
const [isDragging, setIsDragging] = useState(false);
const [isResizing, setIsResizing] = useState(false);
@ -96,8 +98,20 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
if (isDragging) {
const newX = Math.max(0, e.clientX - dragStart.x);
const newY = Math.max(0, e.clientY - dragStart.y);
const snappedX = snapValueToGrid(newX);
const snappedY = snapValueToGrid(newY);
// 캔버스 경계 체크 (mm를 px로 변환: 1mm ≈ 3.7795px)
const canvasWidthPx = canvasWidth * 3.7795;
const canvasHeightPx = canvasHeight * 3.7795;
// 컴포넌트가 캔버스 안에 있도록 제한
const maxX = canvasWidthPx - component.width;
const maxY = canvasHeightPx - component.height;
const boundedX = Math.min(Math.max(0, newX), maxX);
const boundedY = Math.min(Math.max(0, newY), maxY);
const snappedX = snapValueToGrid(boundedX);
const snappedY = snapValueToGrid(boundedY);
// 정렬 가이드라인 계산
calculateAlignmentGuides(component.id, snappedX, snappedY, component.width, component.height);
@ -116,9 +130,16 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
if (isGrouped) {
components.forEach((c) => {
if (c.groupId === component.groupId && c.id !== component.id) {
const newGroupX = c.x + deltaX;
const newGroupY = c.y + deltaY;
// 그룹 컴포넌트도 경계 체크
const groupMaxX = canvasWidthPx - c.width;
const groupMaxY = canvasHeightPx - c.height;
updateComponent(c.id, {
x: c.x + deltaX,
y: c.y + deltaY,
x: Math.min(Math.max(0, newGroupX), groupMaxX),
y: Math.min(Math.max(0, newGroupY), groupMaxY),
});
}
});
@ -128,10 +149,22 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
const deltaY = e.clientY - resizeStart.y;
const newWidth = Math.max(50, resizeStart.width + deltaX);
const newHeight = Math.max(30, resizeStart.height + deltaY);
// 캔버스 경계 체크
const canvasWidthPx = canvasWidth * 3.7795;
const canvasHeightPx = canvasHeight * 3.7795;
// 컴포넌트가 캔버스를 벗어나지 않도록 최대 크기 제한
const maxWidth = canvasWidthPx - component.x;
const maxHeight = canvasHeightPx - component.y;
const boundedWidth = Math.min(newWidth, maxWidth);
const boundedHeight = Math.min(newHeight, maxHeight);
// Grid Snap 적용
updateComponent(component.id, {
width: snapValueToGrid(newWidth),
height: snapValueToGrid(newHeight),
width: snapValueToGrid(boundedWidth),
height: snapValueToGrid(boundedHeight),
});
}
};
@ -171,6 +204,8 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
snapValueToGrid,
calculateAlignmentGuides,
clearAlignmentGuides,
canvasWidth,
canvasHeight,
]);
// 표시할 값 결정

View File

@ -265,9 +265,9 @@ export function ReportDesignerCanvas() {
<div className="border-b bg-white px-4 py-2 text-center text-sm font-medium text-gray-700"> </div>
{/* 캔버스 스크롤 영역 */}
<div className="flex-1 overflow-auto p-8">
<div className="flex flex-1 items-center justify-center overflow-auto p-8">
{/* 눈금자와 캔버스를 감싸는 컨테이너 */}
<div className="mx-auto inline-flex flex-col">
<div className="inline-flex flex-col">
{/* 좌상단 코너 + 가로 눈금자 */}
{showRuler && (
<div className="flex">