feat(635-4): B05 예정노선 수정에 흐린 다른 세트 겹 · 이음점 붙기 · 벗어남 안내 배선(요구 546 · 547)

- ExpectedDraw — plan-context 겹 읽음 · 그림(켬끔 상관없이 보기만) · 키트 snaps = 남 세트 끝 · 그리기 칸 벗어남 안내 한 줄 · 검증 창구 others
- 시험 test_635_4 배선 줄 대조 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-01 12:37:46 +09:00
co-authored by Claude Opus 5.5
parent 946304e9bb
commit 8d3f854daf
2 changed files with 22 additions and 3 deletions
+13 -1
View File
@@ -10,6 +10,7 @@
* 편집기 한 걸음(되돌리기 됨) → 페이지 [저장] = 손 편집과 같은 길 + 초안 `expected`(`expected_route_edit.csv`).
* [받은 노선으로] = 받은 꼭짓점으로 다시 추적 · 초안 `expected` = [](고친 예정노선 지움) — 한 걸음 · 페이지 [초기화] 는 그대로.
* 예정노선 세 벌 = 받은 노선(`expected_route.csv` · 안 덮음 · 고쳤으면 옅은 점선) · 저장본(`expected_edited`) · 이번 고침(`edit`).
* 같은 예정노선 다른 세트(635-4) = 흐린 겹 보기만(`B05_Profile_UI_PlanContext`) · 그 끝 = 긋기 · 끌기 붙을 자리 · 벗어나면 안내 한 줄.
* ========================================================================== */
import { keyIs } from "../A00_Common/key_registry";
@@ -34,6 +35,7 @@ import { createPlaceFind } from "../D03_PlanAnalysis/D03_PlanAnalysis_UI_Site";
import { requestJson, type RoutePlanResponse } from "./B05_Profile_Api_Replan";
import { loadDesignTerrainGrid, type DesignTerrainGrid } from "./B05_Profile_Api_TerrainGrid";
import { fillPlanPanel } from "./B05_Profile_UI_Panel_Plan";
import { createPlanContextLayer } from "./B05_Profile_UI_PlanContext";
import { markShown } from "./B05_Profile_UI_RouteEdit_Marks";
import { polylineLengthM } from "./B05_Profile_UI_RouteEdit_Render";
import type { RouteEditChrome } from "./B05_Profile_UI_RouteEdit_Chrome";
@@ -137,6 +139,8 @@ export function createExpectedDraw(params: ExpectedDrawParams): ExpectedDraw {
params.redraw();
});
const others = createPlanContextLayer(params.projectId, params.redraw);
// ── 예정노선 키트(긋기 · 고르기 · 메뉴 · 속성 판 · 칸 = 예정노선 페이지와 같은 한 벌) ──
const kit = createPlanKit({
page: "b05",
@@ -151,6 +155,7 @@ export function createExpectedDraw(params: ExpectedDrawParams): ExpectedDraw {
idle: () => open,
onMode,
onSelect: () => (kit.props.render(), params.redraw()),
snaps: others.joints,
cards: { site: { parts: [find.root] } },
});
const { draw, edit: editor, props, menu } = kit;
@@ -178,10 +183,11 @@ export function createExpectedDraw(params: ExpectedDrawParams): ExpectedDraw {
});
const compare = createText("", "muted");
const hint = createText(OFF_HINT, "muted");
const jointHint = createText("", "muted");
const row = document.createElement("div");
row.className = "b05-routeedit__expected-row";
row.append(originalToggle.root, resetButton);
drawCard.append(row, compare, hint);
drawCard.append(row, compare, jointHint, hint);
fillPlanPanel({
site: kit.cards.find((card) => card.contains(find.root)) ?? null,
draw: drawCard,
@@ -194,6 +200,8 @@ export function createExpectedDraw(params: ExpectedDrawParams): ExpectedDraw {
? `받은 노선 ${meters(received())} m → 고친 노선 ${meters(line())} m`
: "";
compare.hidden = !edited;
jointHint.textContent = others.note(line()) ?? "";
jointHint.hidden = !jointHint.textContent;
hint.textContent = !open ? OFF_HINT : network.lines.length ? HINT : EMPTY_HINT;
}
@@ -346,6 +354,7 @@ export function createExpectedDraw(params: ExpectedDrawParams): ExpectedDraw {
// ── 그림 ────────────────────────────────────────────────
function paint(context: CanvasRenderingContext2D): void {
others.paint(context, map()); // 다른 세트 = 흐린 겹(켬끔 상관없이 보기만)
if (showOriginal && original.length > 1 && line() !== original) {
context.save();
context.beginPath();
@@ -381,7 +390,9 @@ export function createExpectedDraw(params: ExpectedDrawParams): ExpectedDraw {
selected: editor.selected()?.kind ?? null,
busy,
compare: compare.textContent,
joint: jointHint.textContent,
}),
others: others.probe,
line,
original: () => original,
source: () => source,
@@ -396,6 +407,7 @@ export function createExpectedDraw(params: ExpectedDrawParams): ExpectedDraw {
saved = nextSaved;
network = fromLine();
syncCard();
void others.load().then(syncCard);
void requestJson<{ expected_source?: Vertex[] }>(
`/projects/${params.projectId}/route/plan/source`,
{},
@@ -1,11 +1,15 @@
"""B05 흐린 다른 세트 겹 · 이음점 붙기(PLAN 635-4 · 요구 546 · 547) — TS `logic/B05_Profile_PlanContext.ts`.
"""B05 흐린 다른 세트 겹 · 이음점 붙기(PLAN 635-4 · 요구 546 · 547).
TS `logic/B05_Profile_PlanContext.ts`
tsc 로 옮겨 Node 로 돌림.
- 흐릴 세트 = 내 세트 아님 · 연결 없음 = 빈 · 꺾은선 1 점 = 안 그림.
- 이음점 = 남 세트 끝 · 받을 때 이어진 이음점 = 내 받은 선 끝 1 m 안.
- 벗어남 = 이어졌던 이음점에서 지금 선 끝까지 1 m 밖만 안내 · 붙이면 안내 없음.
- 이름표 = 가장 긴 꺾은선 가운데.
- 지킴: 겹은 보기만(GET 만 · 파일 · 누름 칸 없음) · 기능 표 `others` = B05 보기만 · 키트가 이음점을 긋기 · 끌기에 넘김.
- 지킴: 겹은 보기만(GET 만 · 파일 · 누름 칸 없음) · 기능 표 `others` = B05 보기만 ·
키트가 이음점을 긋기 · 끌기에 넘김 ·
B05 예정노선 수정이 겹을 그림 · 이음점 넘김 · 안내 줄.
./venv/Scripts/python.exe -m pytest resources/tester/test_635_4_plan_context_layer.py -q
"""
@@ -130,3 +134,6 @@ def test_기능_표_others_B05_보기만_키트_이음점_넘김():
assert kit.count("snaps: params.snaps") == 2
assert 'note: "이음점에 붙음"' in (D03 / "D03_PlanAnalysis_UI_Draw.ts").read_text("utf-8")
assert "params.snaps?.()" in (D03 / "D03_PlanAnalysis_UI_Edit.ts").read_text("utf-8")
wire = (ROOT / "B05_Profile" / "B05_Profile_UI_ExpectedDraw.ts").read_text("utf-8")
assert "snaps: others.joints" in wire and "others.paint(context" in wire
assert "others.note(line())" in wire and "others.load()" in wire