Files
Aislo/B05_Profile/B05_Profile_UI_Profile_Preview.ts
T
eomsangdonandClaude Opus 5.5 38aae89b2d refactor(B05·B06): 종단도 한 벌 — B05 종단 패널 본체를 design_profile(createDesignProfile)로 옮김 · B06 위 종단을 같은 종단도(가운데 아래 · 카드 위 칸 스크롤)로 바꿈
- A00_Common/design/design_profile.ts 본체 · design_profile_slots.ts 판 자리 약속 · Profile_Panel 827 → 감싸개 37줄(Guard · Drag 로 나눔)
- B06: 옛 붙박이 종단(Section_View_Draw · Chart · Panel) 걷음 · Section_View_Profile 이음(선택 · 구조물 편집 · 카드 갱신 · 최소 흙덮기 관 목록)
- 크기 · 접기 키 하나(profile-height · profile-collapsed) · 옛 section-panel-* 값 옮겨 받음
- 소스 문자열 시험 넷을 옮긴 자리로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BU9gbNE3aWFUvE61pS2WGt
2026-09-29 20:28:15 +09:00

71 lines
3.0 KiB
TypeScript

/* =============================================================================
* B05_Profile_UI_Profile_Preview.ts
* 계획선 편집 → 횡단 설계 프리뷰 반영 (패널 본체에서 분리, 2026-09-02 · 700줄 한계).
*
* 계획고가 바뀌면 측점별 횡단 단면적도 바뀐다 — 서버에 한 번 물어 전 측점을 다시 계산해
* **공유 캐시가 들고 있는 같은 객체**를 제자리 갱신한다. 그래야 횡단 기준 유토곡선과
* 3D 예상형상이 같은 값으로 따라온다(2026-08-03·08-23 사용자 보고).
*
* 끌기 중에는 계속 호출되므로 디바운스하고, 늦게 온 응답은 seq 비교로 버린다.
* ========================================================================== */
import type { AlignmentEdits } from "./B05_Profile_UI_Profile_Alignment";
import { refreshCrossDesigns } from "../B06_Section/B06_Section_Cross_Refresh";
import type { SectionDetailResponse } from "../B06_Section/B06_Section_Api_Fetch";
export interface CrossPreviewContext {
projectId: string;
detail: () => SectionDetailResponse | null;
routeId: () => number | null;
edits: () => AlignmentEdits;
debounceMs: number;
/** 반영이 끝난 뒤 다시 그린다 — 다시 계산한 측점 누가거리를 넘긴다(횡단 카드 갱신용). */
onApplied: (updated: number[]) => void;
}
export interface CrossPreview {
/** 편집이 있을 때마다 부른다 — 마지막 값만 서버로 나간다. */
schedule: () => void;
/** 패널을 걷을 때 대기 중인 요청 타이머를 끈다. */
dispose: () => void;
}
export function createCrossPreview(ctx: CrossPreviewContext): CrossPreview {
let timer = 0;
let seq = 0;
return {
schedule() {
if (!ctx.detail() || ctx.routeId() === null) return;
window.clearTimeout(timer);
timer = window.setTimeout(() => {
const detail = ctx.detail();
const routeId = ctx.routeId();
if (!detail || routeId === null) return;
const current = (seq += 1);
// 재계산은 B06과 **같은 창구**를 쓴다 — 표준 단면값·암 경계 오프셋이 빠지면 서버가
// 다른 설계를 그려 같은 데이터가 두 화면에서 다른 값이 된다(2026-09-03 일원화).
const isCurrent = (): boolean =>
current === seq && ctx.detail() === detail && ctx.routeId() === routeId;
void refreshCrossDesigns({
projectId: ctx.projectId,
routeId,
detail,
edits: ctx.edits(),
// 늦게 온 옛 응답이 새 설계를 덮지 않게 반영 직전에 한 번 더 확인한다.
shouldApply: isCurrent,
})
.then((updated) => {
if (updated.length) ctx.onApplied(updated);
})
.catch(() => {
/* 프리뷰 실패는 무시 — 화면의 계획선은 그대로 두고 다음 편집에서 다시 시도한다. */
});
}, ctx.debounceMs);
},
dispose() {
window.clearTimeout(timer);
},
};
}