fix(B05 평면 도구줄): 스냅 상태줄 글 = 고른 간격 따라 — 측점 No. = 일반측점 · 0.1 · 1 · 10 m = 배수 (390-4)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
This commit is contained in:
2026-10-17 18:48:37 +09:00
co-authored by Claude Opus 5.5
parent cf51d0139c
commit 7827625ba4
3 changed files with 78 additions and 5 deletions
+2 -2
View File
@@ -263,7 +263,7 @@ export async function mountRouteEditor(
const showMinorContours = bindMinorContourToggle(minorContourButton, () => draw());
const snapStepM = bindStationSnap(chrome, projectId, stationIntervalM, (toggle) => {
if (toggle) setStationSnap(!stationSnap);
if (stationSnap && history) applyEdit("곡선 가운데(MC)를 일반측점에 맞췄습니다."); // 전체 · 한 걸음
if (stationSnap && history) applyEdit(snapStepM.text()); // 전체 · 한 걸음
draw();
});
/** 보던 화면 기억(계획서 18 ③) — 자료를 읽고 화면을 되살린 **뒤부터** 적는다. */
@@ -535,7 +535,7 @@ export async function mountRouteEditor(
curveHint,
contourHint,
commit: () => {
if (stationSnap) return applyEdit("곡선 가운데(MC)를 일반측점에 맞췄습니다."); // 놓을 때(366-3)
if (stationSnap) return applyEdit(snapStepM.text()); // 놓을 때(366-3)
history?.commit(snapshotNow());
historyControls.sync();
},
@@ -5,6 +5,7 @@
* 간격 = 0.1 m · 1 m · 10 m · 측점 No.(편집 창 측점 간격 · 기본) — 곡선 MC 를 그 간격 배수에 맞춤.
* 고른 값은 프로젝트별 화면 기억(pref `routeedit-snap-step`) · [저장] 대상 아님(서버 · 추천은 측점 No. 그대로).
* 스냅 끔이면 고르기는 흐림(CSS) · 고를 수는 있음.
* 상태줄 글은 고른 간격 따라(390-4) — 측점 No. = 「일반측점에」 · 그 밖 = 「1 m 배수에」 꼴.
* ========================================================================== */
import { readState, writeState } from "../A00_Common/b_page_state";
@@ -18,16 +19,24 @@ export function paintStationSnap(button: HTMLButtonElement, on: boolean): void {
button.setAttribute("aria-pressed", String(on));
}
/** 스냅 뒤 상태줄 글 — `step` = 고르기 값("0.1" · "1" · "10" · "station"). */
export function snapFitText(step: string): string {
const where = step === "station" ? "일반측점" : `${step} m 배수`;
return `곡선 가운데(MC)를 ${where}에 맞췄습니다.`;
}
export type SnapStep = { (): number; text: () => string };
/**
* 단추 · 고르기 배선 — `onChange(true)` = 단추 누름(켬끔 바꿈) · `onChange(false)` = 간격 바꿈.
* 돌려주는 함수 = 지금 스냅 간격(m).
* 돌려주는 함수 = 지금 스냅 간격(m) · `.text()` = 스냅 뒤 상태줄 글.
*/
export function bindStationSnap(
chrome: Pick<RouteEditChrome, "overlay" | "stationSnapButton">,
projectId: string,
stationIntervalM: number,
onChange: (toggle: boolean) => void,
): () => number {
): SnapStep {
const select = chrome.overlay.querySelector<HTMLSelectElement>('[data-act="snap-step"]')!;
const saved = readState<string>("routeedit-snap-step", projectId);
select.value = saved && STEPS.includes(saved) ? saved : "station";
@@ -36,5 +45,6 @@ export function bindStationSnap(
onChange(false);
});
chrome.stationSnapButton.addEventListener("click", () => onChange(true));
return () => (select.value === "station" ? stationIntervalM : Number(select.value));
const stepM = () => (select.value === "station" ? stationIntervalM : Number(select.value));
return Object.assign(stepM, { text: () => snapFitText(select.value) });
}
@@ -0,0 +1,63 @@
"""390-4 스냅 상태줄 글 = 고른 간격 따라 — `B05_Profile_UI_RouteEdit_SnapStep.ts` 의 `snapFitText`
를 Node 로 돌려 간격별 글 판정 + 편집기 두 자리(전체 · 놓을 때)가 그 글을 씀.
./venv/Scripts/python.exe -m pytest resources/tester/test_390_4_snap_step_text.py -q
"""
import json
import subprocess
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
B05 = ROOT / "B05_Profile"
SNAP = B05 / "B05_Profile_UI_RouteEdit_SnapStep.ts"
TS = ROOT / "config" / "node_modules" / "typescript"
STEPS = ["0.1", "1", "10", "station"]
NODE = """
const fs = require("fs");
const ts = require(process.argv[1]);
const js = ts.transpileModule(fs.readFileSync(process.argv[2], "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
new Function("exports", "module", "require", js)(box.exports, box, () => ({}));
const steps = JSON.parse(process.argv[3]);
console.log(JSON.stringify(Object.fromEntries(steps.map((s) => [s, box.exports.snapFitText(s)]))));
"""
@pytest.fixture(scope="module")
def texts() -> dict:
run = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", "-e", NODE, str(TS), str(SNAP), json.dumps(STEPS)],
capture_output=True,
text=True,
encoding="utf-8",
timeout=60,
)
assert run.returncode == 0, run.stderr
return json.loads(run.stdout)
@pytest.mark.parametrize(
("step", "want"),
[
("station", "곡선 가운데(MC)를 일반측점에 맞췄습니다."),
("0.1", "곡선 가운데(MC)를 0.1 m 배수에 맞췄습니다."),
("1", "곡선 가운데(MC)를 1 m 배수에 맞췄습니다."),
("10", "곡선 가운데(MC)를 10 m 배수에 맞췄습니다."),
],
)
def test_간격별_상태줄_글(texts, step, want) -> None:
assert texts[step] == want
def test_편집기는_고른_간격_글을_씀() -> None:
edit = (B05 / "B05_Profile_UI_RouteEdit.ts").read_text(encoding="utf-8")
assert "일반측점에 맞췄" not in edit
assert edit.count("applyEdit(snapStepM.text())") == 2
snap = SNAP.read_text(encoding="utf-8")
assert "text: () => snapFitText(select.value)" in snap