feat(B05 평면): 366-2 도구줄 차례 [?] | ↶ ↷ | 3D | 회전 · 1m 등고선 · 절/성토선 · 거리 재기 | 측점 스냅 · 분석 지형 · 구분선 넷 · [맞춤] 지움(처음 열 때 맞춤 그대로) · 회전 단추 도구줄로
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
This commit is contained in:
@@ -56,7 +56,6 @@ import {
|
||||
captureView,
|
||||
createViewMemory,
|
||||
fitCanvas,
|
||||
fitView,
|
||||
openingView,
|
||||
restoreSavedView,
|
||||
screenToMetric,
|
||||
@@ -318,13 +317,6 @@ export async function mountRouteEditor(
|
||||
rotation.set(opening.rotationRad);
|
||||
viewReady = true;
|
||||
}
|
||||
// [맞춤] — 처음 그림과 같은 등고 영역 맞춤(회전 0 · 349-0). 셈은 `_View` 몫.
|
||||
overlay.querySelector('[data-act="fit"]')!.addEventListener("click", () => {
|
||||
if (!meta || view.width <= 0 || !planned.length) return;
|
||||
view = fitView(meta, view, planned, contours?.layer ?? null);
|
||||
rotation.set(0);
|
||||
draw();
|
||||
});
|
||||
|
||||
const toScreen = (vertex: Vertex): [number, number] =>
|
||||
meta ? metricToScreen(meta, view, vertex[0], vertex[1]) : [0, 0];
|
||||
|
||||
@@ -11,6 +11,7 @@ import { bindFootprintToggle } from "./B05_Profile_UI_RouteEdit_Footprint";
|
||||
* **배치**(352-1) — 지도가 칸 전체 · 머리 줄 · 테두리 없음. 도구는 3D 와 같은 떠 있는 유리 단추
|
||||
* (지도 왼쪽 위 · ☰ 비킴), [?] 조작 설명은 도구줄 아래 2열, 상태·범례는 왼쪽 아래, 잰 값은 오른쪽
|
||||
* 아래. 횡단 두 판은 지도 오른쪽을 덮는 판(아래 종단 판이 그 위).
|
||||
* 도구줄 차례(366-2) — [?] | ↶ ↷ | 3D | ⟲ ⟳ · 1m 등고선 · 절/성토선 · 거리 재기 | 측점 스냅 · 분석 지형.
|
||||
*
|
||||
* 자리(345-3) — 모달이 아니라 종단 보기 가운데 위 본문(옛 3D 자리)에 붙는다. 덮개 · 전체 화면 ·
|
||||
* 닫기 단추는 걷었다 · [취소] · [확인] · [노선 반영] · [저장 전으로]는 없앰(346-3 · 352-2 — 노선은 페이지
|
||||
@@ -60,8 +61,31 @@ export function createRouteEditChrome(
|
||||
<div class="b05-routeedit__canvas-wrap" aria-label="계획노선 편집">
|
||||
<canvas class="b05-routeedit__canvas"></canvas>
|
||||
<div class="b05-route__view-controls b05-routeedit__tools">
|
||||
<button type="button" class="ui-btn ui-btn--glass b05-routeedit__hint-toggle"
|
||||
data-act="hint-toggle" aria-expanded="false" title="조작 도움말 펼치기 · 접기">?</button>
|
||||
<i class="b05-route__view-separator" aria-hidden="true"></i>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="undo"
|
||||
title="되돌리기 (Ctrl+Z)" aria-label="되돌리기" disabled>↶</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="redo"
|
||||
title="다시하기 (Ctrl+Y)" aria-label="다시하기" disabled>↷</button>
|
||||
<i class="b05-route__view-separator" aria-hidden="true"></i>
|
||||
<span data-slot="tools"></span>
|
||||
<i class="b05-route__view-separator" aria-hidden="true"></i>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="rotate-ccw"
|
||||
title="반시계로 돌리기" aria-label="반시계로 돌리기">${HALF_TURN_ICON.ccw}</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="rotate-cw"
|
||||
title="시계로 돌리기" aria-label="시계로 돌리기">${HALF_TURN_ICON.cw}</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="contour-minor"
|
||||
aria-pressed="false" disabled
|
||||
title="1m 간격 등고선을 얇고 옅게 겹칩니다 (확대하면 보임)">1m 등고선</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="footprint"
|
||||
title="도로 끝 · 비탈 끝(깎기 붉음 · 쌓기 파랑)을 평면에 겹칩니다">절/성토선</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="measure"
|
||||
title="노선 위 두 점을 눌러 거리·기울기를 잽니다 (Shift+클릭도 같음)">거리 재기</button>
|
||||
<i class="b05-route__view-separator" aria-hidden="true"></i>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="station-snap"
|
||||
aria-pressed="false"
|
||||
title="곡선(호) 안 측점 하나를 곡선 중점(MC)으로 옮깁니다 — [저장] 때 저장">측점 스냅</button>
|
||||
<label class="b05-routeedit__terrain" hidden
|
||||
title="노선 편집 분석(등고선 · 지반고 · 기울기 · 횡단 미리보기 · 추천)에 쓸 지형 — 확정 지표면 · 종횡단은 안 바뀝니다">분석 지형
|
||||
<select class="ui-select ui-select--sm" data-act="terrain">
|
||||
@@ -69,27 +93,8 @@ export function createRouteEditChrome(
|
||||
<option value="sheet">수치지형도</option>
|
||||
</select>
|
||||
</label>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="fit"
|
||||
title="등고 영역(등고선 범위 · 노선)을 평면 가운데 알맞게 맞춥니다 (회전은 풂)">맞춤</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="contour-minor"
|
||||
aria-pressed="false" disabled
|
||||
title="1m 간격 등고선을 얇고 옅게 겹칩니다 (확대하면 보임)">1m 등고선</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="measure"
|
||||
title="노선 위 두 점을 눌러 거리·기울기를 잽니다 (Shift+클릭도 같음)">거리 재기</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="station-snap"
|
||||
aria-pressed="false"
|
||||
title="곡선(호) 안 측점 하나를 곡선 중점(MC)으로 옮깁니다 — [저장] 때 저장">측점 스냅</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="footprint"
|
||||
title="도로 끝 · 비탈 끝(깎기 붉음 · 쌓기 파랑)을 평면에 겹칩니다">절/성토선</button>
|
||||
<i class="b05-route__view-separator" aria-hidden="true"></i>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="undo"
|
||||
title="되돌리기 (Ctrl+Z)" aria-label="되돌리기" disabled>↶</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="redo"
|
||||
title="다시하기 (Ctrl+Y)" aria-label="다시하기" disabled>↷</button>
|
||||
</div>
|
||||
<div class="b05-routeedit__hint">
|
||||
<button type="button" class="ui-btn ui-btn--glass b05-routeedit__hint-toggle"
|
||||
data-act="hint-toggle" aria-expanded="false" title="조작 도움말 펼치기 · 접기">?</button>
|
||||
<div class="b05-routeedit__hint-body">
|
||||
<span>노드 끌기 = 옮기기</span><span>노드 클릭 = R 라벨</span>
|
||||
<span>선 두 번 클릭 = 노드 추가</span><span>노드 오른쪽 클릭 = 삭제</span>
|
||||
@@ -97,12 +102,6 @@ export function createRouteEditChrome(
|
||||
<span>가운데(휠) 버튼 끌기 = 지도 이동</span><span>휠 = 확대</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="b05-routeedit__spin">
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="rotate-ccw"
|
||||
title="반시계로 돌리기" aria-label="반시계로 돌리기">${HALF_TURN_ICON.ccw}</button>
|
||||
<button type="button" class="ui-btn ui-btn--glass" data-act="rotate-cw"
|
||||
title="시계로 돌리기" aria-label="시계로 돌리기">${HALF_TURN_ICON.cw}</button>
|
||||
</div>
|
||||
<div class="b05-routeedit__measure" hidden>
|
||||
<span class="b05-routeedit__measure-text"></span>
|
||||
<span data-slot="measure-close"></span>
|
||||
@@ -142,7 +141,7 @@ export function createRouteEditChrome(
|
||||
|
||||
// 도움말 = 기본 접힘 · [?] 한 번에 펼침(345-5 덧 3).
|
||||
const hint = overlay.querySelector<HTMLElement>(".b05-routeedit__hint")!;
|
||||
const hintToggle = hint.querySelector<HTMLButtonElement>('[data-act="hint-toggle"]')!;
|
||||
const hintToggle = overlay.querySelector<HTMLButtonElement>('[data-act="hint-toggle"]')!;
|
||||
const setHint = (open: boolean): void => {
|
||||
hintOpen = open;
|
||||
hint.classList.toggle("is-open", open);
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
--b05-side-open: 460px;
|
||||
}
|
||||
|
||||
/* 도구줄 — 3D 도구줄 규격 그대로 · 오른쪽 회전 단추 · 횡단 판을 비켜 줄바꿈. */
|
||||
/* 도구줄 — 3D 도구줄 규격 그대로 · 회전 단추도 이 줄(366-2) · 넘치면 줄바꿈. */
|
||||
.b05-routeedit__tools {
|
||||
right: calc(var(--spacing-12) + 112px); /* 오른쪽 위 회전 단추 자리 */
|
||||
right: var(--spacing-12);
|
||||
flex-wrap: wrap;
|
||||
pointer-events: none; /* 빈 자리는 지도 조작을 통과 */
|
||||
}
|
||||
|
||||
@@ -125,16 +125,14 @@ def test_판은_덮이기만_따라_안_옮김() -> None:
|
||||
assert ".b05-route-profile.is-collapsed {\n height: 0;" in style
|
||||
|
||||
|
||||
def test_처음_열기와_맞춤_단추_같은_셈() -> None:
|
||||
def test_처음_열기_맞춤_그대로_맞춤_단추_없음() -> None:
|
||||
"""366-2 — [맞춤] 단추는 지움 · 처음 열 때 등고 영역 맞춤(fitView)은 그대로."""
|
||||
view = (B05 / "B05_Profile_UI_RouteEdit_View.ts").read_text(encoding="utf-8")
|
||||
assert "return { view: fitView(meta, view, nodes, contours), rotationRad: 0 };" in view
|
||||
assert "unionArea([route, ...(contours?.features ?? [])])" in view
|
||||
chrome = (B05 / "B05_Profile_UI_RouteEdit_Chrome.ts").read_text(encoding="utf-8")
|
||||
assert 'data-act="fit"' in chrome and ">맞춤</button>" in chrome
|
||||
assert 'data-act="fit"' not in chrome and ">맞춤</button>" not in chrome
|
||||
editor = (B05 / "B05_Profile_UI_RouteEdit.ts").read_text(encoding="utf-8")
|
||||
assert "openingView(projectId, meta, view, planned, contours?.layer ?? null)" in editor
|
||||
at = editor.index("""overlay.querySelector('[data-act="fit"]')!""")
|
||||
handler = editor[at : at + 260]
|
||||
assert "view = fitView(meta, view, planned, contours?.layer ?? null);" in handler
|
||||
assert "rotation.set(0);" in handler
|
||||
assert 'data-act="fit"' not in editor and "fitView" not in editor
|
||||
assert len(editor.splitlines()) <= 700
|
||||
|
||||
@@ -208,11 +208,34 @@ def test_노선_추천_다듬기_23_3():
|
||||
return open(os.path.join(page, name), encoding="utf-8").read()
|
||||
|
||||
chrome = read("B05_Profile_UI_RouteEdit_Chrome.ts")
|
||||
# 345-4 — [노선 추천]은 좌측 칸 · 머리 구분선은 [3D](tools) 뒤 · 되돌리기 앞 둘 그대로
|
||||
tools = chrome.index('data-slot="tools"')
|
||||
divider = chrome.index("b05-route__view-separator", tools) # 352-1 — 3D 도구줄 구분선 그대로
|
||||
assert tools < divider < chrome.index('data-act="contour-minor"')
|
||||
assert chrome.count("b05-route__view-separator") == 2
|
||||
# 366-2 — [?] | ↶ ↷ | 3D | ⟲ ⟳ · 1m 등고선 · 절/성토선 · 거리 재기 | 측점 스냅 · 분석 지형(맨 오른쪽)
|
||||
bar = chrome[
|
||||
chrome.index("b05-routeedit__tools") : chrome.index('<div class="b05-routeedit__hint">')
|
||||
]
|
||||
order = [
|
||||
'data-act="hint-toggle"',
|
||||
"|",
|
||||
'data-act="undo"',
|
||||
'data-act="redo"',
|
||||
"|",
|
||||
'data-slot="tools"',
|
||||
"|",
|
||||
'data-act="rotate-ccw"',
|
||||
'data-act="rotate-cw"',
|
||||
'data-act="contour-minor"',
|
||||
'data-act="footprint"',
|
||||
'data-act="measure"',
|
||||
"|",
|
||||
'data-act="station-snap"',
|
||||
'class="b05-routeedit__terrain"',
|
||||
]
|
||||
at = 0
|
||||
for mark in order:
|
||||
key = "b05-route__view-separator" if mark == "|" else mark
|
||||
at = bar.index(key, at) + 1
|
||||
assert bar.count("b05-route__view-separator") == 4
|
||||
assert chrome.count("b05-route__view-separator") == 4
|
||||
assert "b05-routeedit__spin" not in chrome # 회전 = 도구줄(추천 모달 CSS 는 남음)
|
||||
shared = read("B05_Profile_UI_RouteEdit_Recommend_Map.ts")
|
||||
for name in ("bindRouteEditNavigation", "createMapRotation", "fitCanvas", "metricToScreen"):
|
||||
assert f"{name}(" in shared
|
||||
|
||||
Reference in New Issue
Block a user