텍스트 컴포넌트 더블 클릭 시 컨텐츠 크기에 맞게 자동 조절
This commit is contained in:
parent
9fe22bc422
commit
aa283d11da
|
|
@ -190,6 +190,105 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
|
|||
const isLocked = component.locked === true;
|
||||
const isGrouped = !!component.groupId;
|
||||
|
||||
// 표시할 값 결정
|
||||
const getDisplayValue = (): string => {
|
||||
// 쿼리와 필드가 연결되어 있으면 실제 데이터 조회
|
||||
if (component.queryId && component.fieldName) {
|
||||
const queryResult = getQueryResult(component.queryId);
|
||||
|
||||
// 실행 결과가 있으면 첫 번째 행의 해당 필드 값 표시
|
||||
if (queryResult && queryResult.rows.length > 0) {
|
||||
const firstRow = queryResult.rows[0];
|
||||
const value = firstRow[component.fieldName];
|
||||
|
||||
// 값이 있으면 문자열로 변환하여 반환
|
||||
if (value !== null && value !== undefined) {
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
// 실행 결과가 없거나 값이 없으면 필드명 표시
|
||||
return `{${component.fieldName}}`;
|
||||
}
|
||||
|
||||
// 기본값이 있으면 기본값 표시
|
||||
if (component.defaultValue) {
|
||||
return component.defaultValue;
|
||||
}
|
||||
|
||||
// 둘 다 없으면 타입에 따라 기본 텍스트
|
||||
return component.type === "text" ? "텍스트 입력" : "레이블 텍스트";
|
||||
};
|
||||
|
||||
// 텍스트 컴포넌트: 더블 클릭 시 컨텐츠에 맞게 크기 조절
|
||||
const fitTextToContent = () => {
|
||||
if (isLocked) return;
|
||||
if (component.type !== "text" && component.type !== "label") return;
|
||||
|
||||
const minWidth = 50;
|
||||
const minHeight = 30;
|
||||
|
||||
// 여백을 px로 변환
|
||||
const marginRightPx = margins.right * MM_TO_PX;
|
||||
const marginBottomPx = margins.bottom * MM_TO_PX;
|
||||
const canvasWidthPx = canvasWidth * MM_TO_PX;
|
||||
const canvasHeightPx = canvasHeight * MM_TO_PX;
|
||||
|
||||
// 최대 크기 (여백 고려)
|
||||
const maxWidth = canvasWidthPx - marginRightPx - component.x;
|
||||
const maxHeight = canvasHeightPx - marginBottomPx - component.y;
|
||||
|
||||
const displayValue = getDisplayValue();
|
||||
const fontSize = component.fontSize || 14;
|
||||
|
||||
// 줄바꿈으로 분리하여 각 줄의 너비 측정
|
||||
const lines = displayValue.split("\n");
|
||||
let maxLineWidth = 0;
|
||||
|
||||
lines.forEach((line) => {
|
||||
const measureEl = document.createElement("span");
|
||||
measureEl.style.position = "absolute";
|
||||
measureEl.style.visibility = "hidden";
|
||||
measureEl.style.whiteSpace = "nowrap";
|
||||
measureEl.style.fontSize = `${fontSize}px`;
|
||||
measureEl.style.fontWeight = component.fontWeight || "normal";
|
||||
measureEl.style.fontFamily = "system-ui, -apple-system, sans-serif";
|
||||
measureEl.textContent = line || " "; // 빈 줄은 공백으로
|
||||
document.body.appendChild(measureEl);
|
||||
|
||||
const lineWidth = measureEl.getBoundingClientRect().width;
|
||||
maxLineWidth = Math.max(maxLineWidth, lineWidth);
|
||||
document.body.removeChild(measureEl);
|
||||
});
|
||||
|
||||
// 컴포넌트 padding (p-2 = 8px * 2) + 여유분
|
||||
const horizontalPadding = 24;
|
||||
const verticalPadding = 20;
|
||||
|
||||
// 줄 높이 계산 (font-size * line-height 약 1.5)
|
||||
const lineHeight = fontSize * 1.5;
|
||||
const totalHeight = lines.length * lineHeight;
|
||||
|
||||
const finalWidth = Math.min(maxLineWidth + horizontalPadding, maxWidth);
|
||||
const finalHeight = Math.min(totalHeight + verticalPadding, maxHeight);
|
||||
|
||||
const newWidth = Math.max(minWidth, finalWidth);
|
||||
const newHeight = Math.max(minHeight, finalHeight);
|
||||
|
||||
// 크기 업데이트
|
||||
updateComponent(component.id, {
|
||||
width: snapValueToGrid(newWidth),
|
||||
height: snapValueToGrid(newHeight),
|
||||
});
|
||||
};
|
||||
|
||||
// 더블 클릭 핸들러 (텍스트 컴포넌트만)
|
||||
const handleDoubleClick = (e: React.MouseEvent) => {
|
||||
if (component.type !== "text" && component.type !== "label") return;
|
||||
e.stopPropagation();
|
||||
fitTextToContent();
|
||||
};
|
||||
|
||||
// 드래그 시작
|
||||
const handleMouseDown = (e: React.MouseEvent) => {
|
||||
if ((e.target as HTMLElement).classList.contains("resize-handle")) {
|
||||
|
|
@ -405,36 +504,6 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
|
|||
canvasHeight,
|
||||
]);
|
||||
|
||||
// 표시할 값 결정
|
||||
const getDisplayValue = (): string => {
|
||||
// 쿼리와 필드가 연결되어 있으면 실제 데이터 조회
|
||||
if (component.queryId && component.fieldName) {
|
||||
const queryResult = getQueryResult(component.queryId);
|
||||
|
||||
// 실행 결과가 있으면 첫 번째 행의 해당 필드 값 표시
|
||||
if (queryResult && queryResult.rows.length > 0) {
|
||||
const firstRow = queryResult.rows[0];
|
||||
const value = firstRow[component.fieldName];
|
||||
|
||||
// 값이 있으면 문자열로 변환하여 반환
|
||||
if (value !== null && value !== undefined) {
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
// 실행 결과가 없거나 값이 없으면 필드명 표시
|
||||
return `{${component.fieldName}}`;
|
||||
}
|
||||
|
||||
// 기본값이 있으면 기본값 표시
|
||||
if (component.defaultValue) {
|
||||
return component.defaultValue;
|
||||
}
|
||||
|
||||
// 둘 다 없으면 타입에 따라 기본 텍스트
|
||||
return component.type === "text" ? "텍스트 입력" : "레이블 텍스트";
|
||||
};
|
||||
|
||||
// 컴포넌트 타입별 렌더링
|
||||
const renderContent = () => {
|
||||
const displayValue = getDisplayValue();
|
||||
|
|
@ -1182,6 +1251,7 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
|
|||
: "1px solid #e5e7eb",
|
||||
}}
|
||||
onMouseDown={handleMouseDown}
|
||||
onDoubleClick={handleDoubleClick}
|
||||
>
|
||||
{renderContent()}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue