- 옮김: B04 2 · B05 23 · B06 11 · A00_Common/design 13 (9,299 줄) · 이미 logic/ 에 있던 16 파일 그대로 - 안 옮김: 묶음 입구(package.json build:*) · 파이썬 · 순수지만 계산 아닌 8 (보기 결선 · 콜백 · API 타입 · 갈아끼움 알림판) - import 266 줄(142 파일) · 시험 · 주석 · 짝 표시 문자열 경로 고침 · B05 · B06 CLAUDE.md 짝 줄 logic/ - 시험 도우미 새 경로: 가짜 require 열쇠 · B05()/B06() 부름 · 형제 import 자리 · tsc 묶어 돌리는 시험 · 정규식 · rglob - design_view_cross 줄 한도 시험 685 → 688 (긴 import 경로 줄바꿈 3줄) - 확인: typecheck 0 · 서버 묶음 넷(corridor · server-calc · b07-extent · b07-note) 다시 지어 코드 같음(//#region 경로 주석만 다름) · 관련 시험 270 파일 — 남은 실패 19 는 옮기기 전과 같음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
118 lines
4.6 KiB
TypeScript
118 lines
4.6 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile_UI_Structures_Widening.ts
|
|
* 노면공 「확폭 구간」 상자(PLAN 87-3) — 상세 내용 아래. 범위 안 확폭 > 0 측점을 이어진 구간으로 묶어
|
|
* 구간마다 단추(켬 = 확폭 포함 · 끔 = 규격 폭만 · 기본 켬). 끈 구간 = `options.widening_off`.
|
|
* 규칙(구간 묶기 · 글 읽고 쓰기)은 `design_structure_widening` · 횡단 측점 읽기는 `pipeSections`.
|
|
* ========================================================================== */
|
|
|
|
import { pipeSections } from "../A00_Common/design/design_structure_pipe_calc";
|
|
import {
|
|
isRunOff,
|
|
offForRuns,
|
|
toggleRun,
|
|
wideningArea,
|
|
wideningRuns,
|
|
type WideningRun,
|
|
} from "../A00_Common/design/logic/design_structure_widening";
|
|
import { stationLabel } from "../common_util/common_util_station";
|
|
import { group } from "./B05_Profile_UI_Drainage_Facility_Fields";
|
|
|
|
export interface WideningBox {
|
|
root: HTMLElement;
|
|
/** 종류 · 저장 값으로 다시 그림(범위형이 아니면 가림). */
|
|
paint: (visible: boolean, stored: string | number | undefined) => void;
|
|
/** 저장할 값 — 끈 구간이 없으면 빈 묶음. 횡단 자료가 없으면 저장 값을 그대로 지킴. */
|
|
read: () => Record<string, string>;
|
|
/** 범위 · 횡단 자료가 바뀌었을 때 다시 그림. */
|
|
refresh: () => void;
|
|
}
|
|
|
|
export function createWideningBox(hooks: {
|
|
range: () => { start: number | null; end: number | null };
|
|
interval: () => number;
|
|
onChange: () => void;
|
|
}): WideningBox {
|
|
const box = group("확폭 구간");
|
|
box.root.classList.add("b05-structure__widening");
|
|
box.root.hidden = true;
|
|
let off = "";
|
|
|
|
/** 지금 범위의 구간들 — 횡단 자료 · 범위가 없으면 null(+ 안내 글). */
|
|
const runs = (): {
|
|
list: WideningRun[] | null;
|
|
note: string;
|
|
area?: (run: WideningRun) => number;
|
|
} => {
|
|
const sections = pipeSections();
|
|
if (!sections?.length) return { list: null, note: "횡단 자료 없음" };
|
|
const { start, end } = hooks.range();
|
|
if (start === null || end === null || end <= start)
|
|
return { list: null, note: "시작 · 종료 측점을 넣으면 보임" };
|
|
const list = wideningRuns(sections, start, end);
|
|
// 확폭 면적(138-2) — 표시만 · 수량엔 안 넣음
|
|
const area = (run: WideningRun) => wideningArea(sections, run, { start, end });
|
|
return { list, note: list.length ? "" : "범위 안 확폭 없음", area };
|
|
};
|
|
|
|
const paintBody = (): void => {
|
|
const { list, note, area } = runs();
|
|
if (!list?.length) {
|
|
const text = document.createElement("span");
|
|
text.className = "b05-structure__widening-note";
|
|
text.textContent = note;
|
|
box.body.replaceChildren(text);
|
|
return;
|
|
}
|
|
const step = hooks.interval();
|
|
box.body.replaceChildren(
|
|
...list.map((run) => {
|
|
const on = !isRunOff(run, off);
|
|
const button = document.createElement("button");
|
|
button.type = "button";
|
|
button.className = `b05-route__irregular-btn${on ? " is-on" : ""}`;
|
|
button.setAttribute("aria-pressed", String(on));
|
|
button.dataset.wideningRun = `${run.start_m}-${run.end_m}`;
|
|
const from = stationLabel(run.start_m, step);
|
|
const to = stationLabel(run.end_m, step);
|
|
button.textContent = `${from === to ? from : `${from} ~ ${to}`} · 확폭 ${Number(run.widening_m.toFixed(2))} m`;
|
|
const size = area?.(run);
|
|
const areaText = document.createElement("span");
|
|
areaText.className = "b05-structure__widening-area";
|
|
areaText.textContent =
|
|
size !== undefined && Number.isFinite(size) ? `${size.toFixed(2)} ㎡` : "";
|
|
button.append(areaText);
|
|
button.title = on ? "확폭 포함 — 누르면 규격 폭만" : "규격 폭만 — 누르면 확폭 포함";
|
|
button.addEventListener("click", () => {
|
|
off = toggleRun(list, off, run);
|
|
paintBody();
|
|
hooks.onChange();
|
|
});
|
|
return button;
|
|
}),
|
|
);
|
|
};
|
|
|
|
// 횡단 자료가 늦게 오면 상자 위에 올 때 다시 그림
|
|
box.root.addEventListener("pointerenter", () => {
|
|
if (!box.root.hidden) paintBody();
|
|
});
|
|
|
|
return {
|
|
root: box.root,
|
|
paint(visible, stored) {
|
|
box.root.hidden = !visible;
|
|
off = typeof stored === "string" ? stored : "";
|
|
if (visible) paintBody();
|
|
},
|
|
read() {
|
|
const { list } = runs();
|
|
const text = list ? offForRuns(list, off) : off;
|
|
const out: Record<string, string> = text ? { widening_off: text } : {};
|
|
return out;
|
|
},
|
|
refresh() {
|
|
if (!box.root.hidden) paintBody();
|
|
},
|
|
};
|
|
}
|