/* ============================================================================= * design_profile_overlays.ts * 종단도 바닥 오버레이 서브패널 — 유토곡선 · 테이블 · 유토 총괄 배지(213-3 · 700줄 한계로 뗌). * 만들어 `bodyWrap` 에 붙이고 종단 스크롤과 잇는 데까지 — 그리기 · 높이는 종단도 몫. * ========================================================================== */ import { attachMassHaulBadgeDrag, createMassHaulBadge } from "@util/common_util_mass_haul_badge"; import { readStateRaw, writeStateRaw } from "../b_page_state"; import { createHaulPlanPrefetch } from "../../B05_Profile/B05_Profile_Api_HaulPlan"; import { createProfileTableOverlay } from "../../B05_Profile/B05_Profile_UI_Profile_TableOverlay"; import { createRouteMassHaulPanel, type MassHaulSummaryValues, } from "../../B05_Profile/B05_Profile_UI_Profile_MassHaul"; export interface ProfileOverlaysDeps { projectId: string; routeId: () => number | null; /** 종단 열(요약 줄 · 본문 · 서클을 담은 칸) — 오버레이가 그 위를 덮는다. */ bodyWrap: HTMLElement; /** 종단 스크롤러 — 오버레이 가로 스크롤을 이것과 맞춘다. */ body: HTMLElement; /** 서브패널이 바뀜(펼침 · 범례 · 리사이저 · 유토 배분 도착). */ onChange: () => void; } export function createProfileOverlays(deps: ProfileOverlaysDeps) { const { bodyWrap, body, onChange } = deps; /** 유토곡선 총괄값 — **그래프 좌측 상단 배지**가 보인다(2026-09-06 사용자 지시). * 유토곡선을 접어도 이 값은 남아야 한다. */ const massBadge = createMassHaulBadge(); // 그래프 위 도구줄 · 측점 ▲ 줄(바닥 47px) 아래로 내려 겹치지 않게 한다(289). massBadge.root.style.setProperty("--mass-haul-badge-top", "52px"); bodyWrap.append(massBadge.root); // 그래프 안 끌어 옮김(309-2) — 자리는 화면 설정 한 칸(B05 · B06 같은 값) attachMassHaulBadgeDrag(massBadge.root, body, { read: () => readStateRaw("mass-haul-badge-pos"), write: (value) => writeStateRaw("mass-haul-badge-pos", value), }); let massHaulSummary: MassHaulSummaryValues | null = null; // 유토 배분은 **서버가 만든다**(2026-09-06) — 편집이 멈추면 뒤에서 받아 두고, 도착하면 // 곡선을 다시 그린다. 그 산식이 브라우저 번들에 안 실리는 것이 이 구조의 목적이다. const haulPrefetch = createHaulPlanPrefetch( deps.projectId, () => deps.routeId() ?? undefined, onChange, ); const massHaul = createRouteMassHaulPanel( onChange, (summary) => { const before = massHaulSummary; massHaulSummary = summary; if (before?.finalM3 !== summary?.finalM3) massBadge.set(summary); }, haulPrefetch, ); bodyWrap.append(massHaul.overlay, massHaul.handle); // 테이블도 유토곡선과 같은 오버레이 서브패널 — 유토곡선 위에 쌓인다(2026-08-05 사용자 지시). const tableOverlay = createProfileTableOverlay(onChange); bodyWrap.append(tableOverlay.overlay, tableOverlay.handle); tableOverlay.attachScrollSync(body); // 유토곡선·테이블 영역에서 브라우저 기본 우클릭 메뉴를 막는다(2026-08-05 사용자 지시). // 종단 그래프의 구조물 메뉴는 chartWrap에서 이미 preventDefault 후 자체 메뉴를 띄운다. body.addEventListener("contextmenu", (event) => event.preventDefault()); massHaul.overlay.addEventListener("contextmenu", (event) => event.preventDefault()); return { massHaul, tableOverlay }; }