/* ============================================================================= * B05_Profile_UI_RouteEdit_Hover.ts * 노선 편집 평면 **맴돔 밝힘**(요구 241-14 · PLAN 381-3). * * 맴도는 자리는 `_Pointer` 가 `_Input.pickAtScreen`(집기와 같은 셈)으로 적고, 여기서 이길 쪽만 * 그린다 — 노드 = 바깥 고리 · 횡단 눈금 = 고른 측점과 같은 좌우 20 m 법선(`drawStationNormal` · * 391-1). `_Render` 가 노드 그린 뒤 부름. * ========================================================================== */ import { pickHover } from "./B05_Profile_UI_RouteEdit_Input"; import type { RouteEditScene } from "./B05_Profile_UI_RouteEdit_Render"; import { stationFrameAt } from "./logic/B05_Profile_UI_RouteEdit_Frame"; import type { Vertex } from "./logic/B05_Profile_UI_RouteEdit_Curve"; /** 측점 법선 색 — 노선(주황)·재기(초록)·등고선(연보라)과 겹치지 않는 하늘색. */ const STATION_NORMAL_COLOR = "#0ea5e9"; /** 법선 좌우 길이(m) — 서버 `SECTION_CROSS_HALF_WIDTH_M` 과 같은 값 · 고정(391-1). */ const STATION_NORMAL_HALF_M = 20; /** 측점 법선(391-1) — 맴돔 · 고름 한 그림: 측점에서 노선에 직각 좌우 20 m · 끝 점 · 측점 고리. * 방향은 지금 그려진 노선으로 매 프레임 다시 짚음(`stationFrameAt`) — 끄는 동안 바로 따라감. */ export function drawStationNormal( context: CanvasRenderingContext2D, scene: RouteEditScene, line: ReadonlyArray, chainageM: number, ): void { const frame = stationFrameAt(line, chainageM); if (!frame) return; const [ox, oy] = frame.origin; const [lx, ly] = frame.left; const half = STATION_NORMAL_HALF_M; const [cx, cy] = scene.toScreen(frame.origin); const [ax, ay] = scene.toScreen([ox + lx * half, oy + ly * half]); const [bx, by] = scene.toScreen([ox - lx * half, oy - ly * half]); context.save(); context.setLineDash([]); context.strokeStyle = STATION_NORMAL_COLOR; context.fillStyle = STATION_NORMAL_COLOR; context.lineWidth = 2.4; context.beginPath(); context.moveTo(ax, ay); context.lineTo(bx, by); context.stroke(); for (const [x, y] of [ [ax, ay], [bx, by], ]) { context.beginPath(); context.arc(x, y, 3, 0, Math.PI * 2); context.fill(); } context.lineWidth = 2; context.beginPath(); context.arc(cx, cy, 6, 0, Math.PI * 2); context.stroke(); context.restore(); } /** 맴도는 자리 밝힘(381-3) — 누르면 집힐 쪽만: 노드 = 바깥 고리 · 횡단 눈금 = 측점 법선. */ export function drawPickHover( context: CanvasRenderingContext2D, scene: RouteEditScene, line: ReadonlyArray, style: CSSStyleDeclaration, nodeR: number, ): void { const hover = pickHover(context.canvas); if (!hover) return; context.save(); context.setLineDash([]); if ("node" in hover) { const vertex = scene.planned[hover.node]; if (vertex) { const [x, y] = scene.toScreen(vertex); const radius = (hover.node === scene.picked ? nodeR + 2 : nodeR) + 4; context.beginPath(); context.arc(x, y, radius, 0, Math.PI * 2); context.strokeStyle = style.getPropertyValue("--map-halo") || "rgba(255,255,255,0.9)"; context.lineWidth = 4; context.stroke(); context.strokeStyle = style.getPropertyValue("--map-route") || "#f97316"; context.lineWidth = 2; context.stroke(); } } else { drawStationNormal(context, scene, line, hover.chainage); } context.restore(); }