캔버스 스케일 팩터를 고정 px 단위로 통일

This commit is contained in:
dohyeons 2025-12-22 15:13:49 +09:00
parent 0decfe95de
commit 117912045f
4 changed files with 40 additions and 29 deletions

View File

@ -7,6 +7,9 @@ import { getFullImageUrl } from "@/lib/api/client";
import JsBarcode from "jsbarcode";
import QRCode from "qrcode";
// 고정 스케일 팩터 (화면 해상도와 무관)
const MM_TO_PX = 4;
// 1D 바코드 렌더러 컴포넌트
interface BarcodeRendererProps {
value: string;
@ -252,15 +255,15 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
const newX = Math.max(0, e.clientX - dragStart.x);
const newY = Math.max(0, e.clientY - dragStart.y);
// 여백을 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;
// 여백을 px로 변환
const marginTopPx = margins.top * MM_TO_PX;
const marginBottomPx = margins.bottom * MM_TO_PX;
const marginLeftPx = margins.left * MM_TO_PX;
const marginRightPx = margins.right * MM_TO_PX;
// 캔버스 경계 체크 (mm를 px로 변환)
const canvasWidthPx = canvasWidth * 3.7795;
const canvasHeightPx = canvasHeight * 3.7795;
const canvasWidthPx = canvasWidth * MM_TO_PX;
const canvasHeightPx = canvasHeight * MM_TO_PX;
// 컴포넌트가 여백 안에 있도록 제한
const minX = marginLeftPx;
@ -312,12 +315,12 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
const newHeight = Math.max(30, resizeStart.height + deltaY);
// 여백을 px로 변환
const marginRightPx = margins.right * 3.7795;
const marginBottomPx = margins.bottom * 3.7795;
const marginRightPx = margins.right * MM_TO_PX;
const marginBottomPx = margins.bottom * MM_TO_PX;
// 캔버스 경계 체크
const canvasWidthPx = canvasWidth * 3.7795;
const canvasHeightPx = canvasHeight * 3.7795;
const canvasWidthPx = canvasWidth * MM_TO_PX;
const canvasHeightPx = canvasHeight * MM_TO_PX;
// 컴포넌트가 여백을 벗어나지 않도록 최대 크기 제한
const maxWidth = canvasWidthPx - marginRightPx - component.x;

View File

@ -8,6 +8,10 @@ import { CanvasComponent } from "./CanvasComponent";
import { Ruler } from "./Ruler";
import { v4 as uuidv4 } from "uuid";
// mm를 px로 변환하는 고정 스케일 팩터 (화면 해상도와 무관하게 일정)
// A4 기준: 210mm x 297mm → 840px x 1188px
export const MM_TO_PX = 4;
export function ReportDesignerCanvas() {
const canvasRef = useRef<HTMLDivElement>(null);
const {
@ -76,15 +80,15 @@ export function ReportDesignerCanvas() {
height = 30;
}
// 여백을 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 marginTopPx = margins.top * MM_TO_PX;
const marginLeftPx = margins.left * MM_TO_PX;
const marginRightPx = margins.right * MM_TO_PX;
const marginBottomPx = margins.bottom * MM_TO_PX;
// 캔버스 경계 (px)
const canvasWidthPx = canvasWidth * 3.7795;
const canvasHeightPx = canvasHeight * 3.7795;
const canvasWidthPx = canvasWidth * MM_TO_PX;
const canvasHeightPx = canvasHeight * MM_TO_PX;
// 드롭 위치 계산 (여백 내부로 제한)
const rawX = x - 100;
@ -402,8 +406,8 @@ export function ReportDesignerCanvas() {
}}
className={`relative bg-white shadow-lg ${isOver ? "ring-2 ring-blue-500" : ""}`}
style={{
width: `${canvasWidth}mm`,
minHeight: `${canvasHeight}mm`,
width: `${canvasWidth * MM_TO_PX}px`,
minHeight: `${canvasHeight * MM_TO_PX}px`,
backgroundImage: showGrid
? `
linear-gradient(to right, #e5e7eb 1px, transparent 1px),
@ -419,10 +423,10 @@ export function ReportDesignerCanvas() {
<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`,
top: `${currentPage.margins.top * MM_TO_PX}px`,
left: `${currentPage.margins.left * MM_TO_PX}px`,
right: `${currentPage.margins.right * MM_TO_PX}px`,
bottom: `${currentPage.margins.bottom * MM_TO_PX}px`,
}}
/>
)}

View File

@ -8,9 +8,12 @@ interface RulerProps {
offset?: number; // 스크롤 오프셋 (px)
}
// 고정 스케일 팩터 (화면 해상도와 무관)
const MM_TO_PX = 4;
export function Ruler({ orientation, length, offset = 0 }: RulerProps) {
// mm를 px로 변환 (1mm = 3.7795px, 96dpi 기준)
const mmToPx = (mm: number) => mm * 3.7795;
// mm를 px로 변환
const mmToPx = (mm: number) => mm * MM_TO_PX;
const lengthPx = mmToPx(length);
const isHorizontal = orientation === "horizontal";

View File

@ -803,9 +803,10 @@ export function ReportDesignerProvider({ reportId, children }: { reportId: strin
const horizontalLines: number[] = [];
const threshold = 5; // 5px 오차 허용
// 캔버스를 픽셀로 변환 (1mm = 3.7795px)
const canvasWidthPx = canvasWidth * 3.7795;
const canvasHeightPx = canvasHeight * 3.7795;
// 캔버스를 픽셀로 변환 (고정 스케일 팩터: 1mm = 4px)
const MM_TO_PX = 4;
const canvasWidthPx = canvasWidth * MM_TO_PX;
const canvasHeightPx = canvasHeight * MM_TO_PX;
const canvasCenterX = canvasWidthPx / 2;
const canvasCenterY = canvasHeightPx / 2;