diff --git a/frontend/components/admin/dashboard/CanvasElement.tsx b/frontend/components/admin/dashboard/CanvasElement.tsx
index 3decd573..43ce5163 100644
--- a/frontend/components/admin/dashboard/CanvasElement.tsx
+++ b/frontend/components/admin/dashboard/CanvasElement.tsx
@@ -131,9 +131,13 @@ export function CanvasElement({
const deltaY = e.clientY - dragStart.y;
// 임시 위치 계산 (스냅 안 됨)
- const rawX = Math.max(0, dragStart.elementX + deltaX);
+ let rawX = Math.max(0, dragStart.elementX + deltaX);
const rawY = Math.max(0, dragStart.elementY + deltaY);
+ // X 좌표가 캔버스 너비를 벗어나지 않도록 제한
+ const maxX = GRID_CONFIG.CANVAS_WIDTH - element.size.width;
+ rawX = Math.min(rawX, maxX);
+
setTempPosition({ x: rawX, y: rawY });
} else if (isResizing) {
const deltaX = e.clientX - resizeStart.x;
@@ -173,21 +177,29 @@ export function CanvasElement({
break;
}
+ // 가로 너비가 캔버스를 벗어나지 않도록 제한
+ const maxWidth = GRID_CONFIG.CANVAS_WIDTH - newX;
+ newWidth = Math.min(newWidth, maxWidth);
+
// 임시 크기/위치 저장 (스냅 안 됨)
setTempPosition({ x: Math.max(0, newX), y: Math.max(0, newY) });
setTempSize({ width: newWidth, height: newHeight });
}
},
- [isDragging, isResizing, dragStart, resizeStart],
+ [isDragging, isResizing, dragStart, resizeStart, element.size.width, element.type, element.subtype],
);
// 마우스 업 처리 (그리드 스냅 적용)
const handleMouseUp = useCallback(() => {
if (isDragging && tempPosition) {
// 드래그 종료 시 그리드에 스냅 (동적 셀 크기 사용)
- const snappedX = snapToGrid(tempPosition.x, cellSize);
+ let snappedX = snapToGrid(tempPosition.x, cellSize);
const snappedY = snapToGrid(tempPosition.y, cellSize);
+ // X 좌표가 캔버스 너비를 벗어나지 않도록 최종 제한
+ const maxX = GRID_CONFIG.CANVAS_WIDTH - element.size.width;
+ snappedX = Math.min(snappedX, maxX);
+
onUpdate(element.id, {
position: { x: snappedX, y: snappedY },
});
@@ -199,9 +211,13 @@ export function CanvasElement({
// 리사이즈 종료 시 그리드에 스냅 (동적 셀 크기 사용)
const snappedX = snapToGrid(tempPosition.x, cellSize);
const snappedY = snapToGrid(tempPosition.y, cellSize);
- const snappedWidth = snapSizeToGrid(tempSize.width, 2, cellSize);
+ let snappedWidth = snapSizeToGrid(tempSize.width, 2, cellSize);
const snappedHeight = snapSizeToGrid(tempSize.height, 2, cellSize);
+ // 가로 너비가 캔버스를 벗어나지 않도록 최종 제한
+ const maxWidth = GRID_CONFIG.CANVAS_WIDTH - snappedX;
+ snappedWidth = Math.min(snappedWidth, maxWidth);
+
onUpdate(element.id, {
position: { x: snappedX, y: snappedY },
size: { width: snappedWidth, height: snappedHeight },
@@ -213,7 +229,7 @@ export function CanvasElement({
setIsDragging(false);
setIsResizing(false);
- }, [isDragging, isResizing, tempPosition, tempSize, element.id, onUpdate, cellSize]);
+ }, [isDragging, isResizing, tempPosition, tempSize, element.id, element.size.width, onUpdate, cellSize]);
// 전역 마우스 이벤트 등록
React.useEffect(() => {
@@ -251,12 +267,11 @@ export function CanvasElement({
executionTime: 0,
});
} catch (error) {
- // console.error('❌ 데이터 로딩 오류:', error);
setChartData(null);
} finally {
setIsLoadingData(false);
}
- }, [element.dataSource?.query, element.type, element.subtype]);
+ }, [element.dataSource?.query, element.type]);
// 컴포넌트 마운트 시 및 쿼리 변경 시 데이터 로딩
useEffect(() => {
@@ -372,7 +387,7 @@ export function CanvasElement({
) : (