diff --git a/frontend/contexts/ReportDesignerContext.tsx b/frontend/contexts/ReportDesignerContext.tsx index 42fb9504..3db07bc9 100644 --- a/frontend/contexts/ReportDesignerContext.tsx +++ b/frontend/contexts/ReportDesignerContext.tsx @@ -147,6 +147,40 @@ interface ReportDesignerContextType { const ReportDesignerContext = createContext(undefined); +// 페이지 사이즈 변경 시 컴포넌트 위치 및 크기 재계산 유틸리티 함수 +const recalculateComponentPositions = ( + components: ComponentConfig[], + oldWidth: number, + oldHeight: number, + newWidth: number, + newHeight: number +): ComponentConfig[] => { + // 사이즈가 동일하면 그대로 반환 + if (oldWidth === newWidth && oldHeight === newHeight) { + return components; + } + + const widthRatio = newWidth / oldWidth; + const heightRatio = newHeight / oldHeight; + + return components.map((comp) => { + // 위치와 크기 모두 비율대로 재계산 + // 소수점 2자리까지만 유지 + const newX = Math.round(comp.x * widthRatio * 100) / 100; + const newY = Math.round(comp.y * heightRatio * 100) / 100; + const newCompWidth = Math.round(comp.width * widthRatio * 100) / 100; + const newCompHeight = Math.round(comp.height * heightRatio * 100) / 100; + + return { + ...comp, + x: newX, + y: newY, + width: newCompWidth, + height: newCompHeight, + }; + }); +}; + export function ReportDesignerProvider({ reportId, children }: { reportId: string; children: ReactNode }) { const [reportDetail, setReportDetail] = useState(null); const [layout, setLayout] = useState(null); @@ -994,10 +1028,42 @@ export function ReportDesignerProvider({ reportId, children }: { reportId: strin }, []); const updatePageSettings = useCallback((pageId: string, settings: Partial) => { - setLayoutConfig((prev) => ({ - ...prev, - pages: prev.pages.map((page) => (page.page_id === pageId ? { ...page, ...settings } : page)), - })); + setLayoutConfig((prev) => { + const targetPage = prev.pages.find((p) => p.page_id === pageId); + if (!targetPage) { + return prev; + } + + // 페이지 사이즈 변경 감지 + const isWidthChanging = settings.width !== undefined && settings.width !== targetPage.width; + const isHeightChanging = settings.height !== undefined && settings.height !== targetPage.height; + + // 사이즈 변경 시 컴포넌트 위치 재계산 + let updatedComponents = targetPage.components; + if (isWidthChanging || isHeightChanging) { + const oldWidth = targetPage.width; + const oldHeight = targetPage.height; + const newWidth = settings.width ?? targetPage.width; + const newHeight = settings.height ?? targetPage.height; + + updatedComponents = recalculateComponentPositions( + targetPage.components, + oldWidth, + oldHeight, + newWidth, + newHeight + ); + } + + return { + ...prev, + pages: prev.pages.map((page) => + page.page_id === pageId + ? { ...page, ...settings, components: updatedComponents } + : page + ), + }; + }); }, []); // 전체 페이지 공유 워터마크 업데이트