Files
Aislo/A00_Common/design/design_profile_overlays.ts
T

74 lines
4.0 KiB
TypeScript

/* =============================================================================
* design_profile_overlays.ts
* 종단도 겹침 판(테이블) · 종단 열 아래 유토곡선 판 · 유토 총괄 배지(213-3 · 700줄 한계로 뗌).
* 만들어 붙이고 종단 스크롤과 잇는 데까지 — 그리기 · 높이는 종단도 몫.
* 종단 열(`column`) = [종단 칸(`bodyWrap`), 유토곡선 판](354-1) — 종단도가 content 왼쪽에 붙인다.
* ========================================================================== */
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,
);
// 유토곡선 = 종단 칸 아래 자기 판(354-1 · 배수유역도처럼) — 종단 [창 분할]에도 함께 감(content 안).
const column = document.createElement("div");
column.className = "b05-route-profile__column";
column.append(bodyWrap, massHaul.overlay);
// 판의 가로 스크롤을 종단 스크롤러와 양방향 동기화 — 측점 세로선 정렬 유지.
massHaul.attachScrollSync(body);
// 테이블은 종단 칸 바닥 겹침 판(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, column };
}