fix(B05 노선편집): 349-0h B06 다녀온 뒤 평면 작게 · 구석으로 그려짐 고침 — 숨은 동안(칸 크기 0) 화면 다시 셈 · 보던 화면 적기 건너뜀 · 다시 보이면 떠나기 전 가운데 · 배율 그대로

- 원인: 숨김(크기 0) 알림에 크기 0 으로 화면을 되살려 가운데가 도엽 구석 · 배율 1/8 로 바뀌고 그 값이 기억에도 적힘
- resize 크기 0 이면 그대로 돌아감 · 기억 꾼은 칸 너비 0 이면 안 잡음 · 처음 열기(기억 없음) = 등고 영역 맞춤 그대로
- 시험: test_349_0h_routeedit_hidden_keep 3 · test_b05_routeedit_view 숨김 1(옛 길 재현) · 관련 20 통과 · typecheck 0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Se7ytqbohmBQnfYpwYFnYf
This commit is contained in:
2026-10-16 15:17:48 +09:00
co-authored by Claude Opus 5.5
parent 4a750cdb2b
commit 98ab68d4b0
4 changed files with 93 additions and 1 deletions
+2 -1
View File
@@ -263,7 +263,7 @@ export async function mountRouteEditor(
/** 보던 화면 기억(계획서 18 ③) — 자료를 읽고 화면을 되살린 **뒤부터** 적는다. */
let viewReady = false;
const viewMemory = createViewMemory(projectId, () =>
meta && viewReady ? captureView(meta, view, rotation.radians()) : null,
meta && viewReady && view.width > 0 ? captureView(meta, view, rotation.radians()) : null,
);
/** 떠날 때 — 페이지가 버린다(345-3 · 닫기 단추 없음). */
@@ -298,6 +298,7 @@ export async function mountRouteEditor(
// 노선이 화면 밖으로 나가고, 그 자리가 보던 화면으로 저장돼 다시 열어도 빈 화면이 된다.
const kept = meta && viewReady ? captureView(meta, view, rotation.radians()) : null;
const { width, height } = fitCanvas(canvas, context);
if (width <= 0 || height <= 0) return; // 숨은 동안(크기 0) — 화면 · 기억 그대로 · 보이면 다시 셈(349-0h).
view = { ...view, width, height, mapRect: computeMapRect(meta, width, height) };
if (meta && kept) view = { ...view, ...restoreSavedView(meta, view, kept) };
if (!viewReady) openView(); // 숨은 채 섰으면(크기 0) 처음 보일 때 맞춘다.
@@ -122,6 +122,31 @@ const shrunk = viewOf(1280, 760, zoomed.scale, zoomed.offsetX, zoomed.offsetY);
const refit = { ...shrunk, ...viewMod.restoreSavedView(meta, shrunk, keptBefore) };
const keptAfter = viewMod.captureView(meta, refit, 0);
// ③-4 숨김(크기 0) 뒤 다시 보임(349-0h) — 크기 0 으로 셈한 화면은 엉뚱함 · 그 셈을 건너뛰고
// 떠나기 전 화면을 다시 보일 때 크기로 되살리면 그대로.
const shown = viewOf(1500, 1000, 4, -600, 250);
const keptShown = viewMod.captureView(meta, shown, 0);
const zero = viewOf(0, 0, shown.scale, shown.offsetX, shown.offsetY);
const zeroView = { ...zero, ...viewMod.restoreSavedView(meta, zero, keptShown) };
const zeroBack = viewOf(1500, 1000, 1, 0, 0);
const fromZero = viewMod.captureView(
meta,
{
...zeroBack,
...viewMod.restoreSavedView(meta, zeroBack, viewMod.captureView(meta, zeroView, 0)),
},
0,
);
const back = viewOf(1500, 1000, shown.scale, shown.offsetX, shown.offsetY);
const keptBack = viewMod.captureView(
meta,
{
...back,
...viewMod.restoreSavedView(meta, back, keptShown),
},
0,
);
// ④ 노드 끼우기·빼기 — 편집값 여섯 줄이 같은 자리에서 함께 움직인다.
const columns = {
planned: [
@@ -152,6 +177,7 @@ process.stdout.write(
stray: { rotationRad: stray.rotationRad, onScreen: strayOnScreen },
keptBefore,
keptAfter,
hidden: { keptShown, fromZero, keptBack },
afterInsert,
afterRemove,
}),
@@ -0,0 +1,54 @@
"""349-0h — B06 다녀와도 노선 편집 평면은 떠나기 전 화면 그대로.
숨은 동안(크기 0) 칸 크기 알림에 화면을 다시 셈하지 않고 기억도 적지 않음 ·
다시 보이면 떠나기 전 화면(가운데 · 배율)을 새 칸 크기로 되살림 · 처음 열기는 등고 영역 맞춤.
배선은 글로 봄.
./venv/Scripts/python.exe -m pytest resources/tester/test_349_0h_routeedit_hidden_keep.py -q
"""
from __future__ import annotations
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
B05 = ROOT / "B05_Profile"
EDITOR = (B05 / "B05_Profile_UI_RouteEdit.ts").read_text(encoding="utf-8")
VIEW = (B05 / "B05_Profile_UI_RouteEdit_View.ts").read_text(encoding="utf-8")
def _body(text: str, head: str) -> str:
at = text.index(head)
return text[at : text.index("\n }", at)]
def test_숨은_동안_화면을_다시_셈하지_않음() -> None:
resize = _body(EDITOR, "function resize(): void {")
kept = resize.index("const kept = meta && viewReady ? captureView(")
fit = resize.index("fitCanvas(canvas, context);")
guard = resize.index("if (width <= 0 || height <= 0) return;")
assign = resize.index("view = { ...view, width, height,")
restore = resize.index("restoreSavedView(meta, view, kept)")
opening = resize.index("if (!viewReady) openView();")
# 떠나기 전 화면을 잡고 · 크기 0 이면 그대로 둠 · 보이면 새 크기로 되살림 · 처음이면 맞춤
assert kept < fit < guard < assign < restore < opening
assert len(EDITOR.splitlines()) <= 700
def test_숨은_동안_기억을_적지_않음() -> None:
assert (
"meta && viewReady && view.width > 0 ? captureView(meta, view, rotation.radians())"
in EDITOR
)
# 보임 · 숨김 알림 — 보이면 크기 다시 셈 · 숨으면 그 전 화면을 적음
assert "host.onShow(() => (historyControls.listen(true), resize()));" in EDITOR
assert "host.onHide(() => (historyControls.listen(false), viewMemory.flush()));" in EDITOR
def test_처음_열기는_기억_없으면_등고_영역_맞춤() -> None:
opening = VIEW[
VIEW.index("export function openingView(") : VIEW.index("export function fitView(")
]
assert "const saved = readSavedView(projectId);" in opening
assert "return { view: fitView(meta, view, nodes, contours), rotationRad: 0 };" in opening
open_view = _body(EDITOR, "function openView(): void {")
assert "view.width <= 0) return;" in open_view # 크기 0 이면 맞춤도 미룸
@@ -73,3 +73,14 @@ def test_노드_끼우기_빼기는_편집값이_같은_자리로(results):
assert removed["planned"] == [[0, 0], [10, 0], [20, 0]]
assert removed["curveRadius"] == [None, 30, None]
assert removed["apexLock"] == [False, True, False]
def test_숨김_크기_0_뒤_다시_보이면_그대로(results):
"""349-0h — 크기 0 으로 셈하면 구석 · 작게(옛 흠) · 건너뛰고 되살리면 떠나기 전 그대로."""
hidden = results["hidden"]
kept, from_zero, back = hidden["keptShown"], hidden["fromZero"], hidden["keptBack"]
assert from_zero["pxPerMeter"] < kept["pxPerMeter"] / 4 # 옛 길 — 아주 작게
assert from_zero["cx"] != pytest.approx(kept["cx"], abs=1.0) # 옛 길 — 가운데가 구석으로
assert back["cx"] == pytest.approx(kept["cx"], abs=1e-6)
assert back["cy"] == pytest.approx(kept["cy"], abs=1e-6)
assert back["pxPerMeter"] == pytest.approx(kept["pxPerMeter"], rel=1e-9)