refactor(B06): 700줄 초과 파일 분리 — Router·Cross_View·Section_View·Style

- B06_Section_Router.py(824) → Router_Design.py(139) 분리
- Cross_View → Cross_View_Metrics.ts(75) 분리
- Cross_Design → Cross_Design_Surface.ts(54) 분리
- Section_View → Section_View_Panel.ts(53) 분리
- Page → Page_Common.ts(15) 분리
- Style_Cross.css → Style_Cross_Controls.css(174) 분리
- B06_Section/ 전체 700줄 초과 0건

검증: tsc --noEmit 통과 · ruff check 통과(import 정렬·포맷 적용) ·
prettier 적용 · pytest tmp/tests/ 148 passed, 7 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-22 17:04:08 +09:00
co-authored by Claude Opus 5
parent be7503d741
commit e54da341ea
14 changed files with 553 additions and 600 deletions
+13 -71
View File
@@ -39,8 +39,6 @@ import {
applyLegendToggle,
computeMassHaulSeries,
MASS_HAUL_BALANCE_KEY,
MASS_HAUL_DEFAULT_VISIBLE,
normalizeVisibleBasis,
type MassHaulSeries,
} from "@util/common_util_mass_haul";
import { computeHaulPlan } from "@util/common_util_mass_haul_balance";
@@ -52,9 +50,21 @@ import {
createMassHaulChart,
createMassHaulLegend,
createMassHaulSummary,
MASS_HAUL_HEIGHT,
MASS_HAUL_MIN_HEIGHT,
} from "@util/common_util_mass_haul_view";
import {
BASE_PANEL_HEIGHT,
chartHeights,
MASS_HAUL_VISIBLE_KEY,
MAX_PANEL_HEIGHT_RATIO,
MIN_LONG_HEIGHT,
MIN_PANEL_HEIGHT,
PANEL_CHROME_PX,
PANEL_COLLAPSED_KEY,
PANEL_HEIGHT_KEY,
readVisibleSeries,
unwrapChart,
} from "./B06_Section_UI_Section_View_Panel";
import {
calculateYScale,
CROSS_GRID_GAP,
@@ -66,7 +76,6 @@ import {
emptyView,
inferStationInterval,
L,
LONG_HEIGHT,
longitudinalMaxChainage,
LONG_PAD,
type YScaleOptions,
@@ -81,73 +90,6 @@ export type { CrossDesignChange, DesignChangeHandler, RockBoundaryControl };
* 유토곡선 아래에 빈 공간이 남는다). 화면에 붙기 전이라 잴 수 없는 첫 렌더에서만 쓰는
* 출발값이고, 최소 패널 높이 계산의 기준이기도 하다.
*/
const PANEL_CHROME_PX = 102;
/** 손대지 않았을 때의 패널 높이 — 이 값이 축소 비례의 기준(H₀)이 된다. */
const BASE_PANEL_HEIGHT = LONG_HEIGHT + MASS_HAUL_HEIGHT + PANEL_CHROME_PX;
const MIN_LONG_HEIGHT = 110;
const MIN_PANEL_HEIGHT = MIN_LONG_HEIGHT + MASS_HAUL_MIN_HEIGHT + PANEL_CHROME_PX;
const MAX_PANEL_HEIGHT_RATIO = 0.8;
const PANEL_HEIGHT_KEY = "b06:profile-panel-height";
const PANEL_COLLAPSED_KEY = "b06:profile-panel-collapsed";
// 곡선 키·기본값이 바뀔 때마다 저장 키의 판을 올려 갈아탄다(옛 세션값을 읽으면 의도와 다른
// 곡선이 켜진다). v2: 키가 `${기준}_${환산}` → `${기준}`. v3: 기본 표시가 횡단 기준 하나로.
// v4: 토량 분배 레이어(`balance`)가 범례에 합류.
const MASS_HAUL_VISIBLE_KEY = "b06:masshaul-visible-v4";
/** 곡선 기준 + 토량 분배 레이어. 저장값이 없을 때 켜 두는 항목. */
const DEFAULT_VISIBLE_KEYS: string[] = [...MASS_HAUL_DEFAULT_VISIBLE, MASS_HAUL_BALANCE_KEY];
/** 켜 둔 곡선 목록은 세션에만 남긴다(패널 높이·접힘과 같은 규칙). */
function readVisibleSeries(): Set<string> {
try {
const raw = sessionStorage.getItem(MASS_HAUL_VISIBLE_KEY);
if (!raw) return new Set(DEFAULT_VISIBLE_KEYS);
const parsed: unknown = JSON.parse(raw);
// 기준 키는 라디오라 항상 하나로 눌러 맞춘다(분배 레이어 켜짐 여부는 저장값 그대로).
return Array.isArray(parsed)
? normalizeVisibleBasis(new Set(parsed.map(String)))
: new Set(DEFAULT_VISIBLE_KEYS);
} catch {
return new Set(DEFAULT_VISIBLE_KEYS);
}
}
/**
* 패널 높이를 두 그래프에 나눈다 (2026-08-02 사용자 지시).
* 기본값 이상으로 키우면 → 종단도는 현재 높이 그대로 두고 늘어난 몫은 유토곡선이 먹는다.
* 기본값보다 줄이면 → 두 그래프가 같은 비율로 함께 작아진다.
*/
function chartHeights(availableHeightPx: number): { long: number; mass: number } {
if (!Number.isFinite(availableHeightPx) || availableHeightPx <= 0) {
return { long: LONG_HEIGHT, mass: MASS_HAUL_HEIGHT };
}
// 두 그래프가 나눠 가질 실제 몫. **합이 이 값과 정확히 같아야** 한다 — 넘으면 세로 스크롤이,
// 모자라면 유토곡선 아래에 빈 공간이 남는다(2026-08-02 사용자 지적).
const available = Math.max(availableHeightPx, MIN_LONG_HEIGHT + MASS_HAUL_MIN_HEIGHT);
// 기본 높이 이상이면 종단도는 고정, 늘어난 몫은 유토곡선이 전부 흡수한다.
if (available >= LONG_HEIGHT + MASS_HAUL_HEIGHT) {
return { long: LONG_HEIGHT, mass: available - LONG_HEIGHT };
}
const ratio = available / (LONG_HEIGHT + MASS_HAUL_HEIGHT);
// 유토곡선 몫을 먼저 잡되 종단도 하한을 남겨 둔다 — 그래야 두 하한이 동시에 걸려도 합이 넘지 않는다.
const mass = Math.min(
Math.max(MASS_HAUL_MIN_HEIGHT, Math.round(MASS_HAUL_HEIGHT * ratio)),
available - MIN_LONG_HEIGHT,
);
return { long: available - mass, mass };
}
/**
* 종단 렌더러가 돌려준 `chart-wrap`에서 SVG만 꺼낸다.
* 종단도와 유토곡선이 **하나의 가로 스크롤 컨테이너**를 공유해야 X축 정렬이 유지된다
* (각자 wrap을 가지면 스크롤이 따로 놀아 같은 측점이 어긋나 보인다).
*/
function unwrapChart(node: HTMLElement): Element {
return node.classList.contains("b06-section__chart-wrap") && node.firstElementChild
? node.firstElementChild
: node;
}
export interface SectionViewController {
root: HTMLElement;
render: (