import { createButton } from "@ui/ui_template_elements"; import { bindFootprintToggle } from "./B05_Profile_UI_RouteEdit_Footprint"; /* ============================================================================= * B05_Profile_UI_RouteEdit_Chrome.ts * 계획노선 편집(평면)의 **뼈대** — 칸·단추·오버레이 판을 만들고 자주 쓰는 요소를 집어 준다. * * `B05_Profile_UI_RouteEdit.ts` 가 700줄을 넘겨 떼어낸 조각이다(2026-09-12). 생김새만 있고 * 동작은 없다 — 배선은 본체와 각 조각(`_Apply`·`_Rotate`·`_History`…)이 한다. * * **배치**(2026-09-12 사용자 지시 ⑩~⑬·⑱) — 아래 정보행을 없애고 지도 위 오버레이로 옮겼다. * 단추는 제목행 오른쪽, 조작 설명은 지도 왼쪽 위 2열, 상태·범례는 왼쪽 아래, 잰 값은 오른쪽 * 아래. 메인 창은 왼쪽으로 밀고 오른쪽 세로 칸에 횡단 두 판이 앉는다. * * 자리(345-3) — 모달이 아니라 종단 보기 가운데 위 본문(옛 3D 자리)에 붙는다. 덮개 · 전체 화면 · * 닫기 단추는 걷었다 · [취소] → [반영 전으로] · [확인] → [노선 반영] · 오른쪽 횡단 칸은 접는 칸. * 머리 `tools` 자리에 부른 쪽 단추([3D])가 앉는다. [노선 추천] · 현재 추천 · [초기화]는 좌측 * 「노선 추천」 칸으로 옮겼다(345-4 · `_Panel_Recommend`). * ========================================================================== */ /** 회전 단추 아이콘 — **반만 도는 화살표**(2026-09-12 사용자 지시 ㉙). 한 바퀴를 다 그린 * 기호(`↺`·`↻`)는 「한 바퀴 돈다」로 읽혀 한 칸씩 도는 동작과 안 맞았다. */ export const HALF_TURN_ICON = { ccw: ``, cw: ``, }; export interface RouteEditChrome { overlay: HTMLElement; canvas: HTMLCanvasElement; status: HTMLElement; busy: HTMLElement; measureBox: HTMLElement; measureText: HTMLElement; measureButton: HTMLButtonElement; minorContourButton: HTMLButtonElement; /** [측점 스냅] 켬끔(요구 224-2) — `aria-pressed` · `is-active` 는 본체가 맞춤. */ stationSnapButton: HTMLButtonElement; /** 분석 지형 고르기(PLAN 133-1) — 라이다 있는 프로젝트만 보임(감싼 label 의 hidden). */ terrainSelect: HTMLSelectElement; } /** 뼈대를 만들어 `parent` 에 붙이고, 자주 쓰는 요소를 집어 돌려준다. */ export function createRouteEditChrome( parent: HTMLElement, tools: HTMLElement[] = [], ): RouteEditChrome { const overlay = document.createElement("div"); overlay.className = "b05-routeedit"; overlay.innerHTML = `

계획노선

노드 끌기 = 옮기기노드 클릭 = R 라벨 선 두 번 클릭 = 노드 추가노드 오른쪽 클릭 = 삭제 측점 눈금 클릭 = 횡단 미리보기Shift+클릭 = 거리·기울기 가운데(휠) 버튼 끌기 = 지도 이동휠 = 확대
노선을 읽는 중… 예상노선(원본) 계획노선
종단을 읽는 중…
`; parent.append(overlay); overlay.querySelector('[data-slot="tools"]')!.replaceWith(...tools); // 횡단 미리보기 = 접는 칸 — 좁은 화면은 접힌 채 시작(지도가 먼저다). const sideWrap = overlay.querySelector(".b05-routeedit__side-wrap")!; const sideToggle = overlay.querySelector('[data-act="side-toggle"]')!; const setSide = (open: boolean): void => { sideWrap.classList.toggle("is-collapsed", !open); sideToggle.setAttribute("aria-expanded", String(open)); }; setSide(window.innerWidth >= 1500); sideToggle.addEventListener("click", () => setSide(sideWrap.classList.contains("is-collapsed"))); const measureCloseButton = createButton({ label: "✕", variant: "ghost" }); measureCloseButton.classList.add("b05-routeedit__measure-close"); measureCloseButton.setAttribute("aria-label", "닫기"); measureCloseButton.title = "닫기"; overlay.querySelector('[data-slot="measure-close"]')!.replaceWith(measureCloseButton); const canvas = overlay.querySelector(".b05-routeedit__canvas")!; const status = overlay.querySelector(".b05-routeedit__status")!; const measureBox = overlay.querySelector(".b05-routeedit__measure")!; const measureText = overlay.querySelector(".b05-routeedit__measure-text")!; const measureButton = overlay.querySelector('[data-act="measure"]')!; const busy = overlay.querySelector(".b05-routeedit__busy")!; const minorContourButton = overlay.querySelector( '[data-act="contour-minor"]', )!; const terrainSelect = overlay.querySelector('[data-act="terrain"]')!; const stationSnapButton = overlay.querySelector('[data-act="station-snap"]')!; bindFootprintToggle(overlay.querySelector('[data-act="footprint"]')!); return { overlay, canvas, status, busy, measureBox, measureText, measureButton, minorContourButton, stationSnapButton, terrainSelect, }; }