feat(B05/B06): 계획서 1·2·4·5·6·8·11 구현 + 유토곡선 오버레이 서브패널 전환(7)

- 4: volumeRange 기본 ±200㎥ 고정, 초과 시에만 확장 (B05·B06 공용)
- 11: 진행단계 오버레이 최상단 대시보드(🏠) 버튼 — 항상 활성, B01 이동
- 6: 편집 버튼 방향색 — 올림(▲⇧) --color-danger, 내림(▼⇩) 파랑 #5b8def, hover 배경 포함
- 2: 구조물 목록 5개 높이 상한 + 내부 스크롤, 선택 항목 scrollIntoView
- 5: 종단 렌더러 bottomInsetPx 옵션 신설 — B05만 X축·측점 라벨 17px 상향,
  ▼ 버튼과 오버랩 해소 (B06 무변화)
- 1: 구조물 측점 열 기본값 미표기 — 측점 값 7행·곡선 2행 빈 셀, 선택 오버레이가 값 표시
- 8: B06 진입 stale 재계산을 측점별 순차 루프에서 일괄 프리뷰 1회로 교체
  · preview API에 full_designs·rock_boundary_offsets 추가
  · B05 세션 초안(readAlignmentDraft) 우선 사용해 두 화면 계획선 일치
- 7: 유토곡선을 1:1 분할에서 패널 바닥 오버레이 서브패널로 전환
  · 종단도+테이블 배치 불변, 오버레이가 위를 덮음
  · 높이는 공용 createPanelResizer(위 경계, 세션 보존), splitBar·MASS_SPLIT 제거
  · 자체 가로 스크롤러 + 종단 스크롤러 양방향 동기화, 전용 ㎥ sticky Y축
  · buildStickyYAxis 정의처를 MassHaul 모듈로 이동(Panel과 공용)

typecheck·vite build·ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-04 17:54:53 +09:00
co-authored by Claude Opus 5
parent c6d930b3f1
commit 6080d122bb
16 changed files with 497 additions and 278 deletions
+13 -5
View File
@@ -116,10 +116,15 @@ export function formatVolume(value: number): string {
}
/**
* Y축 상·하한을 잡는다. 0선은 항상 보이도록 범위에 포함하고, 위아래로 5% 여유를 준다.
* 값이 전부 0이면 폭이 0이 되어 나눗셈이 깨지므로 최소 폭을 씌운다.
*
* 범위는 **표시 중인 곡선이 아니라 전체 곡선**에서 잡는다(축 고정).
* Y축 기본 스케일(㎥). 계획선을 편집할 때마다 범위가 데이터로 다시 잡히면 그래프가
* 출렁여 변화를 읽기 어렵다(2026-08-04 사용자 확정) — 기본 ±200㎥으로 고정하고,
* 곡선이 이 범위를 벗어날 때만 그 방향으로 넓힌다.
*/
const VOLUME_RANGE_BASE_M3 = 200;
/**
* Y축 상·하한을 잡는다. 기본 −200~+200㎥ 고정(0선 항상 포함), 곡선이 넘치는 쪽만
* 데이터에 5% 여유를 더해 확장한다. B05·B06이 같은 함수를 쓰므로 두 화면이 함께 고정된다.
*/
function volumeRange(series: MassHaulSeries[]): { min: number; max: number } {
let rawMin = 0;
@@ -129,7 +134,10 @@ function volumeRange(series: MassHaulSeries[]): { min: number; max: number } {
rawMax = Math.max(rawMax, entry.result.max_cumulative_m3);
}
const padding = Math.max((rawMax - rawMin) * 0.05, 1);
return { min: rawMin - padding, max: rawMax + padding };
return {
min: Math.min(-VOLUME_RANGE_BASE_M3, rawMin - padding),
max: Math.max(VOLUME_RANGE_BASE_M3, rawMax + padding),
};
}
/**