ERP-node/frontend/lib/utils/groupingUtils.ts

151 lines
4.5 KiB
TypeScript
Raw Normal View History

2025-09-01 15:22:47 +09:00
// 그룹화 관련 유틸리티 함수들
import { ComponentData, GroupComponent, Position, Size } from "@/types/screen";
// 컴포넌트 ID 생성
export function generateComponentId(): string {
return `comp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// 그룹 컴포넌트 생성
export function createGroupComponent(
componentIds: string[],
title: string = "새 그룹",
position: Position = { x: 0, y: 0 },
2025-09-01 15:57:49 +09:00
boundingBox?: { width: number; height: number },
2025-09-01 15:22:47 +09:00
style?: any,
): GroupComponent {
2025-09-01 16:40:24 +09:00
// 픽셀 기반 크기 계산 (격자 제거)
const groupWidth = Math.max(200, (boundingBox?.width || 200) + 40); // 최소 200px, 여백 40px
const groupHeight = Math.max(100, (boundingBox?.height || 200) + 40); // 최소 100px, 여백 40px
2025-09-01 15:57:49 +09:00
2025-09-01 15:22:47 +09:00
return {
id: generateComponentId(),
type: "group",
position: { ...position, z: position.z || 1 }, // z 값 포함
2025-09-01 16:40:24 +09:00
size: { width: groupWidth, height: groupHeight },
title: title, // GroupComponent 타입에 맞게 title 사용
2025-09-01 15:22:47 +09:00
backgroundColor: "#f8f9fa",
border: "1px solid #dee2e6",
borderRadius: 8,
shadow: "0 2px 4px rgba(0,0,0,0.1)",
collapsible: true,
collapsed: false,
children: componentIds,
style: {
padding: "16px",
...style,
},
};
}
2025-09-01 16:40:24 +09:00
// 선택된 컴포넌트들의 경계 박스 계산 (픽셀 기반)
2025-09-01 15:22:47 +09:00
export function calculateBoundingBox(components: ComponentData[]): {
minX: number;
minY: number;
maxX: number;
maxY: number;
width: number;
height: number;
} {
if (components.length === 0) {
return { minX: 0, minY: 0, maxX: 0, maxY: 0, width: 0, height: 0 };
}
const minX = Math.min(...components.map((c) => c.position.x));
const minY = Math.min(...components.map((c) => c.position.y));
2025-09-01 16:40:24 +09:00
const maxX = Math.max(...components.map((c) => c.position.x + c.size.width)); // 격자 계산 제거
2025-09-01 15:22:47 +09:00
const maxY = Math.max(...components.map((c) => c.position.y + c.size.height));
return {
minX,
minY,
maxX,
maxY,
width: maxX - minX,
height: maxY - minY,
};
}
// 그룹 내 컴포넌트들의 상대 위치 계산
2025-09-01 15:57:49 +09:00
export function calculateRelativePositions(
components: ComponentData[],
groupPosition: Position,
groupId: string,
): ComponentData[] {
2025-09-01 15:22:47 +09:00
return components.map((component) => ({
...component,
position: {
x: component.position.x - groupPosition.x,
y: component.position.y - groupPosition.y,
z: component.position.z || 1, // z 값 유지
2025-09-01 15:22:47 +09:00
},
2025-09-01 15:57:49 +09:00
parentId: groupId, // 그룹 ID를 부모로 설정
2025-09-01 15:22:47 +09:00
}));
}
// 그룹 해제 시 컴포넌트들의 절대 위치 복원
export function restoreAbsolutePositions(components: ComponentData[], groupPosition: Position): ComponentData[] {
return components.map((component) => ({
...component,
position: {
x: component.position.x + groupPosition.x,
y: component.position.y + groupPosition.y,
z: component.position.z || 1, // z 값 유지
2025-09-01 15:22:47 +09:00
},
parentId: undefined,
}));
}
// 그룹 내 컴포넌트 필터링
export function getGroupChildren(components: ComponentData[], groupId: string): ComponentData[] {
return components.filter((component) => component.parentId === groupId);
}
// 그룹이 아닌 컴포넌트들 필터링
export function getNonGroupComponents(components: ComponentData[]): ComponentData[] {
return components.filter((component) => component.type !== "group");
}
// 선택 가능한 컴포넌트들 필터링 (그룹 제외)
export function getSelectableComponents(components: ComponentData[]): ComponentData[] {
return components.filter((component) => component.type === "widget" || component.type === "container");
}
// 그룹 스타일 생성
export function createGroupStyle(
backgroundColor: string = "#f8f9fa",
border: string = "1px solid #dee2e6",
borderRadius: number = 8,
): any {
return {
backgroundColor,
border,
borderRadius,
padding: "16px",
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
};
}
// 그룹 제목 유효성 검사
export function validateGroupTitle(title: string): boolean {
return title.trim().length > 0 && title.trim().length <= 50;
}
// 그룹 크기 자동 조정
export function autoResizeGroup(group: GroupComponent, children: ComponentData[]): GroupComponent {
if (children.length === 0) {
return group;
}
const boundingBox = calculateBoundingBox(children);
return {
...group,
size: {
width: Math.max(6, Math.ceil(boundingBox.width / 80) + 2), // 최소 6 그리드, 여백 2
height: Math.max(100, boundingBox.height + 40), // 최소 100px, 여백 40px
},
};
}