캔버스 여백 설정
This commit is contained in:
parent
27e33e27d1
commit
4e1e5b0d51
|
|
@ -22,6 +22,7 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
|
||||||
clearAlignmentGuides,
|
clearAlignmentGuides,
|
||||||
canvasWidth,
|
canvasWidth,
|
||||||
canvasHeight,
|
canvasHeight,
|
||||||
|
margins,
|
||||||
} = useReportDesigner();
|
} = useReportDesigner();
|
||||||
const [isDragging, setIsDragging] = useState(false);
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
const [isResizing, setIsResizing] = useState(false);
|
const [isResizing, setIsResizing] = useState(false);
|
||||||
|
|
@ -99,16 +100,24 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
|
||||||
const newX = Math.max(0, e.clientX - dragStart.x);
|
const newX = Math.max(0, e.clientX - dragStart.x);
|
||||||
const newY = Math.max(0, e.clientY - dragStart.y);
|
const newY = Math.max(0, e.clientY - dragStart.y);
|
||||||
|
|
||||||
// 캔버스 경계 체크 (mm를 px로 변환: 1mm ≈ 3.7795px)
|
// 여백을 px로 변환 (1mm ≈ 3.7795px)
|
||||||
|
const marginTopPx = margins.top * 3.7795;
|
||||||
|
const marginBottomPx = margins.bottom * 3.7795;
|
||||||
|
const marginLeftPx = margins.left * 3.7795;
|
||||||
|
const marginRightPx = margins.right * 3.7795;
|
||||||
|
|
||||||
|
// 캔버스 경계 체크 (mm를 px로 변환)
|
||||||
const canvasWidthPx = canvasWidth * 3.7795;
|
const canvasWidthPx = canvasWidth * 3.7795;
|
||||||
const canvasHeightPx = canvasHeight * 3.7795;
|
const canvasHeightPx = canvasHeight * 3.7795;
|
||||||
|
|
||||||
// 컴포넌트가 캔버스 안에 있도록 제한
|
// 컴포넌트가 여백 안에 있도록 제한
|
||||||
const maxX = canvasWidthPx - component.width;
|
const minX = marginLeftPx;
|
||||||
const maxY = canvasHeightPx - component.height;
|
const minY = marginTopPx;
|
||||||
|
const maxX = canvasWidthPx - marginRightPx - component.width;
|
||||||
|
const maxY = canvasHeightPx - marginBottomPx - component.height;
|
||||||
|
|
||||||
const boundedX = Math.min(Math.max(0, newX), maxX);
|
const boundedX = Math.min(Math.max(minX, newX), maxX);
|
||||||
const boundedY = Math.min(Math.max(0, newY), maxY);
|
const boundedY = Math.min(Math.max(minY, newY), maxY);
|
||||||
|
|
||||||
const snappedX = snapValueToGrid(boundedX);
|
const snappedX = snapValueToGrid(boundedX);
|
||||||
const snappedY = snapValueToGrid(boundedY);
|
const snappedY = snapValueToGrid(boundedY);
|
||||||
|
|
@ -150,13 +159,17 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
|
||||||
const newWidth = Math.max(50, resizeStart.width + deltaX);
|
const newWidth = Math.max(50, resizeStart.width + deltaX);
|
||||||
const newHeight = Math.max(30, resizeStart.height + deltaY);
|
const newHeight = Math.max(30, resizeStart.height + deltaY);
|
||||||
|
|
||||||
|
// 여백을 px로 변환
|
||||||
|
const marginRightPx = margins.right * 3.7795;
|
||||||
|
const marginBottomPx = margins.bottom * 3.7795;
|
||||||
|
|
||||||
// 캔버스 경계 체크
|
// 캔버스 경계 체크
|
||||||
const canvasWidthPx = canvasWidth * 3.7795;
|
const canvasWidthPx = canvasWidth * 3.7795;
|
||||||
const canvasHeightPx = canvasHeight * 3.7795;
|
const canvasHeightPx = canvasHeight * 3.7795;
|
||||||
|
|
||||||
// 컴포넌트가 캔버스를 벗어나지 않도록 최대 크기 제한
|
// 컴포넌트가 여백을 벗어나지 않도록 최대 크기 제한
|
||||||
const maxWidth = canvasWidthPx - component.x;
|
const maxWidth = canvasWidthPx - marginRightPx - component.x;
|
||||||
const maxHeight = canvasHeightPx - component.y;
|
const maxHeight = canvasHeightPx - marginBottomPx - component.y;
|
||||||
|
|
||||||
const boundedWidth = Math.min(newWidth, maxWidth);
|
const boundedWidth = Math.min(newWidth, maxWidth);
|
||||||
const boundedHeight = Math.min(newHeight, maxHeight);
|
const boundedHeight = Math.min(newHeight, maxHeight);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ export function ReportDesignerCanvas() {
|
||||||
updateComponent,
|
updateComponent,
|
||||||
canvasWidth,
|
canvasWidth,
|
||||||
canvasHeight,
|
canvasHeight,
|
||||||
|
margins,
|
||||||
selectComponent,
|
selectComponent,
|
||||||
selectedComponentId,
|
selectedComponentId,
|
||||||
selectedComponentIds,
|
selectedComponentIds,
|
||||||
|
|
@ -66,12 +67,33 @@ export function ReportDesignerCanvas() {
|
||||||
height = 70;
|
height = 70;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 여백을 px로 변환 (1mm ≈ 3.7795px)
|
||||||
|
const marginTopPx = margins.top * 3.7795;
|
||||||
|
const marginLeftPx = margins.left * 3.7795;
|
||||||
|
const marginRightPx = margins.right * 3.7795;
|
||||||
|
const marginBottomPx = margins.bottom * 3.7795;
|
||||||
|
|
||||||
|
// 캔버스 경계 (px)
|
||||||
|
const canvasWidthPx = canvasWidth * 3.7795;
|
||||||
|
const canvasHeightPx = canvasHeight * 3.7795;
|
||||||
|
|
||||||
|
// 드롭 위치 계산 (여백 내부로 제한)
|
||||||
|
const rawX = x - 100;
|
||||||
|
const rawY = y - 25;
|
||||||
|
const minX = marginLeftPx;
|
||||||
|
const minY = marginTopPx;
|
||||||
|
const maxX = canvasWidthPx - marginRightPx - width;
|
||||||
|
const maxY = canvasHeightPx - marginBottomPx - height;
|
||||||
|
|
||||||
|
const boundedX = Math.min(Math.max(minX, rawX), maxX);
|
||||||
|
const boundedY = Math.min(Math.max(minY, rawY), maxY);
|
||||||
|
|
||||||
// 새 컴포넌트 생성 (Grid Snap 적용)
|
// 새 컴포넌트 생성 (Grid Snap 적용)
|
||||||
const newComponent: ComponentConfig = {
|
const newComponent: ComponentConfig = {
|
||||||
id: `comp_${uuidv4()}`,
|
id: `comp_${uuidv4()}`,
|
||||||
type: item.componentType,
|
type: item.componentType,
|
||||||
x: snapValueToGrid(Math.max(0, x - 100)),
|
x: snapValueToGrid(boundedX),
|
||||||
y: snapValueToGrid(Math.max(0, y - 25)),
|
y: snapValueToGrid(boundedY),
|
||||||
width: snapValueToGrid(width),
|
width: snapValueToGrid(width),
|
||||||
height: snapValueToGrid(height),
|
height: snapValueToGrid(height),
|
||||||
zIndex: components.length,
|
zIndex: components.length,
|
||||||
|
|
@ -319,6 +341,19 @@ export function ReportDesignerCanvas() {
|
||||||
}}
|
}}
|
||||||
onClick={handleCanvasClick}
|
onClick={handleCanvasClick}
|
||||||
>
|
>
|
||||||
|
{/* 페이지 여백 가이드 */}
|
||||||
|
{currentPage && (
|
||||||
|
<div
|
||||||
|
className="pointer-events-none absolute border-2 border-dashed border-blue-300/50"
|
||||||
|
style={{
|
||||||
|
top: `${currentPage.margins.top}mm`,
|
||||||
|
left: `${currentPage.margins.left}mm`,
|
||||||
|
right: `${currentPage.margins.right}mm`,
|
||||||
|
bottom: `${currentPage.margins.bottom}mm`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 정렬 가이드라인 렌더링 */}
|
{/* 정렬 가이드라인 렌더링 */}
|
||||||
{alignmentGuides.vertical.map((x, index) => (
|
{alignmentGuides.vertical.map((x, index) => (
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -1352,61 +1352,6 @@ export function ReportDesignerRightPanel() {
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* 배경색 */}
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle className="text-sm">배경</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="space-y-3">
|
|
||||||
<div>
|
|
||||||
<Label className="text-xs">배경색</Label>
|
|
||||||
<div className="mt-1 flex gap-2">
|
|
||||||
<Input
|
|
||||||
type="color"
|
|
||||||
value={currentPage.background_color}
|
|
||||||
onChange={(e) =>
|
|
||||||
updatePageSettings(currentPageId, {
|
|
||||||
background_color: e.target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
className="h-10 w-20"
|
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
value={currentPage.background_color}
|
|
||||||
onChange={(e) =>
|
|
||||||
updatePageSettings(currentPageId, {
|
|
||||||
background_color: e.target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
className="flex-1"
|
|
||||||
placeholder="#ffffff"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 배경색 프리셋 */}
|
|
||||||
<div className="grid grid-cols-4 gap-2">
|
|
||||||
{["#ffffff", "#f3f4f6", "#e5e7eb", "#d1d5db"].map((color) => (
|
|
||||||
<button
|
|
||||||
key={color}
|
|
||||||
onClick={() =>
|
|
||||||
updatePageSettings(currentPageId, {
|
|
||||||
background_color: color,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
className="h-8 rounded border-2 transition-all hover:scale-110"
|
|
||||||
style={{
|
|
||||||
backgroundColor: color,
|
|
||||||
borderColor: currentPage.background_color === color ? "#3b82f6" : "#d1d5db",
|
|
||||||
}}
|
|
||||||
title={color}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-full items-center justify-center">
|
<div className="flex h-full items-center justify-center">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue