fix(B05): 종단 새 창 최대화 때 편집 · 다시 그리기 — 놓인 창 화면 틀 · 시계 공용 함수로 통일(230-2)

공용 common_util_view_window(viewOf · frameOf) 신설.
design_profile rebuild · 접기 · render, Heights 높이 맞춤, 표 · 유토곡선 크기 끌기, 유토곡선 세로창 미끄러짐,
끌기 뒤 그리기, ▲▼ · 방향키 길게 누르기, 배수유역도, 구조물 말풍선 — 메인 창 전역 틀 · 시계 대신 요소가 놓인 창 것.
새 시험 test_230_2_popout_frames(메인 창 틀 멈춤 흉내 · 새 창 패널 코드 훑기).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
This commit is contained in:
2026-10-10 17:52:01 +09:00
co-authored by Claude Opus 5.5
parent edc98bad57
commit 3ec5779169
16 changed files with 429 additions and 41 deletions
+12 -3
View File
@@ -23,6 +23,7 @@ import { MASS_HAUL_BALANCE_KEY } from "./common_util_mass_haul";
import { appendBalanceLayer, haulPlanChips } from "./common_util_mass_haul_balance_view";
import { segmentOf } from "./common_util_mass_haul_curve";
import { L, stationLabel, svgElement, svgText } from "./common_util_svg";
import { viewOf } from "./common_util_view_window";
/**
* 유토곡선 X축을 **호출한 쪽 종단 그래프와 맞추는** 값. 좌우 여백과 누가거리 최댓값이
@@ -74,6 +75,8 @@ export interface MassHaulWindowState {
settled: boolean;
/** 예약해 둔 다음 프레임(중복 예약 방지). */
frame: number;
/** `frame` 을 받아 둔 창 — 걷을 때도 같은 창에서(230-2). */
view?: Window;
}
export function createMassHaulWindowState(): MassHaulWindowState {
@@ -81,11 +84,17 @@ export function createMassHaulWindowState(): MassHaulWindowState {
}
/** 아직 목표에 못 갔으면 다음 프레임에 한 번 더 그리게 예약한다. */
export function scheduleMassHaulSettle(state: MassHaulWindowState, redraw: () => void): void {
if (state.frame) cancelAnimationFrame(state.frame);
/** `node` = 곡선이 놓인 요소 — 그 창의 틀에서 잰다(새 창 최대화 때 메인 창 틀은 멈춤 · 230-2). */
export function scheduleMassHaulSettle(
state: MassHaulWindowState,
redraw: () => void,
node?: Node,
): void {
if (state.frame) (state.view ?? window).cancelAnimationFrame(state.frame);
state.frame = 0;
if (state.settled) return;
state.frame = requestAnimationFrame(() => {
state.view = viewOf(node);
state.frame = state.view.requestAnimationFrame(() => {
state.frame = 0;
redraw();
});
+18
View File
@@ -0,0 +1,18 @@
/* =============================================================================
* common_util_view_window.ts
* 요소가 지금 놓인 창 — 종단 패널을 새 창으로 빼면 그 창이다(230-1 · 230-2).
*
* 메인 창 전역 `requestAnimationFrame` · 시계를 쓰면, 새 창을 최대화해 메인 창이 가려질 때
* 브라우저가 메인 창 화면 틀을 멈추고 시계를 늦춰 휠 · 편집 · 다시 그리기가 멈췄다.
* 화면 틀 · 시계는 이 함수로 그 요소의 창에서 받는다.
* ========================================================================== */
/** 요소가 놓인 창(문서에 안 붙었으면 메인 창). */
export function viewOf(node: Node | null | undefined): Window {
return node?.ownerDocument?.defaultView ?? window;
}
/** 요소가 놓인 창의 다음 화면 틀에 부른다. */
export function frameOf(node: Node | null | undefined, callback: FrameRequestCallback): number {
return viewOf(node).requestAnimationFrame(callback);
}