- 그림칸 = 양식 drawing_area 그대로(여백 2 % 없앰) · 도각 편집이 영역 싣고 [완료] 때 저장 - 도면 응답 guide(작도 영역 도면 좌표) · M02 구조물 도각 응답 area - CAD 그리기 겹판 점선 사각형(저장 · DXF · 인쇄 제외) · 모서리 · 변 끌기(도각 편집 · M02 양식만) - 숫자 칸 공용 부품(왼쪽 · 위 · 폭 · 높이 mm) — M02 양식 · B07 도각 편집 · 끌기와 한 벌 - B08 구조물도 · M02 도면 카드 = 얹은 도각 영역 가이드(보기만) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TNMXVCZXMpHpVvqmFkeChL
78 lines
3.3 KiB
TypeScript
78 lines
3.3 KiB
TypeScript
/* =============================================================================
|
|
* ui_template/cad_host/cad_host_area.ts
|
|
* 작도 영역 숫자 칸 한 벌(169-1) — M02 도면 양식 · B07 도각 편집이 함께 쓴다.
|
|
*
|
|
* 칸 = 왼쪽 · 위 · 폭 · 높이(mm) · 저장 꼴은 그대로 [x0, y0, x1, y1](양식 `drawing_area`).
|
|
* CAD 가이드 사각형 끌기(`cad_host` `onGuideChange`) ↔ 이 칸(`set`)이 한 벌로 움직인다.
|
|
* ========================================================================== */
|
|
|
|
import { createInputField } from "@ui/ui_template_elements";
|
|
import type { CadGuideArea } from "./cad_host";
|
|
|
|
/** 작도 영역 칸이 없는 양식이 쓰는 값 — 서버 `Engine_Template._A1_INNER` 와 같다. */
|
|
export const DEFAULT_DRAWING_AREA: CadGuideArea = [42, 47, 812, 567];
|
|
|
|
/** 칸 이름 — 왼쪽 x · 위 y(윗변) · 폭 · 높이 */
|
|
const LABELS = ["왼쪽 (mm)", "위 (mm)", "폭 (mm)", "높이 (mm)"];
|
|
|
|
/** 0.1 mm 까지 — 끌기 값이 긴 소수로 안 보이게 */
|
|
const show = (value: number): string => String(Math.round(value * 10) / 10);
|
|
|
|
/** [x0, y0, x1, y1] → 칸 값 [왼쪽, 위, 폭, 높이] */
|
|
export const areaToFields = ([x0, y0, x1, y1]: CadGuideArea): number[] => [
|
|
x0,
|
|
y1,
|
|
x1 - x0,
|
|
y1 - y0,
|
|
];
|
|
|
|
/** 칸 값 [왼쪽, 위, 폭, 높이] → [x0, y0, x1, y1] · 폭 · 높이가 0 이하면 null */
|
|
export const fieldsToArea = ([left, top, width, height]: number[]): CadGuideArea | null =>
|
|
[left, top, width, height].every(Number.isFinite) && width > 0 && height > 0
|
|
? [left, top - height, left + width, top]
|
|
: null;
|
|
|
|
export interface AreaFields {
|
|
/** 칸 넷 */
|
|
element: HTMLElement;
|
|
/** 지금 값 — 어긋나면 null(칸마다 까닭 표시) */
|
|
read: () => CadGuideArea | null;
|
|
/** 끌기 · 다시 싣기가 바꾼 값 — 칸만 고침(`onInput` 안 부름) */
|
|
set: (area: CadGuideArea) => void;
|
|
}
|
|
|
|
export function createAreaFields(
|
|
start: CadGuideArea,
|
|
options: { readOnly?: boolean; onInput?: (area: CadGuideArea | null) => void } = {},
|
|
): AreaFields {
|
|
const element = document.createElement("div");
|
|
element.className = "cad-area-fields";
|
|
const fields = LABELS.map((label) => createInputField({ label, type: "number", value: "" }));
|
|
element.append(...fields.map((field) => field.root));
|
|
|
|
const read = (): CadGuideArea | null => {
|
|
const raws = fields.map((field) => field.input.value.trim());
|
|
const own = raws.map((raw) =>
|
|
raw === "" ? "값을 넣을 것" : Number.isFinite(Number(raw)) ? undefined : "숫자만",
|
|
);
|
|
const area = own.some(Boolean) ? null : fieldsToArea(raws.map(Number));
|
|
// 모두 숫자인데 어긋나면 폭 · 높이 중 0 이하인 칸만 짚음
|
|
const size = (index: number): string | undefined =>
|
|
own.some(Boolean) || index < 2 || Number(raws[index]) > 0 ? undefined : "0 보다 커야 함";
|
|
fields.forEach((field, index) => field.setError(own[index] ?? size(index)));
|
|
return area;
|
|
};
|
|
|
|
const set = (area: CadGuideArea): void => {
|
|
areaToFields(area).forEach((value, index) => (fields[index].input.value = show(value)));
|
|
read();
|
|
};
|
|
|
|
for (const field of fields) {
|
|
field.input.disabled = options.readOnly === true;
|
|
field.input.addEventListener("input", () => options.onInput?.(read()));
|
|
}
|
|
set(start);
|
|
return { element, read, set };
|
|
}
|