Files
Aislo/B05_Profile/B05_Profile_UI_Profile_Zoom.ts
T
eomsangdonandClaude Opus 5.5 baea638043 refactor(B05): 날 단추 · 작은 도구 단추를 부품 단추 · 아이콘 단추 · 켜기 칩 · 목록 줄로 (PLAN 553-2)
- 종단 도구 · [창 분할] = 단추 유리 · 보조 단 18 · ▲▼ = 아이콘 단추 선 18 · 배율 + − ⤢ = 아이콘 단추 22
- 배수 머리 단추 = 단추 22 · 층 단추 = 켜기 칩 20(색 점 = 층 색) · 유역 줄 = 목록 줄 32
- [추가] · [삭제] · [리셋] · [해제] · 확폭 = 단추 주 · 위험 고스트 · 보조 · [-][+] = 아이콘 단추 24
- 지도 도구줄 · 3D 보기 줄 = 단 32(34 에서) · 접기 ▾ = 아이콘 단추 18 · 잰 값 닫기 = 아이콘 단추 24
- 페이지 CSS 의 단추 꼴(테두리 · 바탕 · 글 · 둥글기) 지움 · 날 색 대체값(#d98a00 · #5b8def · #3a3f4a) 지움
- 시험 선택자 · 가짜 DOM(setAttribute) 같이 고침

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 22:51:58 +09:00

84 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =============================================================================
* B05_Profile_UI_Profile_Zoom.ts
* 종단면도 줌 조작구 — 버튼 셋(줌인·줌아웃·초기화), 2026-09-04 사용자 확정.
*
* 공사 범위가 넓으면 종단 그래프가 눌려 읽히지 않는다. 사람이 맞출 것은 **가로 하나**다.
*
* X (가로) — **폭 배수**다. SVG transform 으로 늘리면 그래프만 커지고 측점 테이블·
* 계획고 편집 버튼층·구조물 알약 레인이 어긋난다(넷이 같은 `chainageMapper`
* 를 쓴다). 캔버스 폭 자체를 키우고 가로 스크롤로 훑는다.
* Y (세로) — **프로그램이 자동으로 맞춘다**. 보이는 구간의 지반·계획선 범위에 맞춰
* 잡으므로(`windowElevationRange`) 세로 배율·창 이동 버튼이 필요 없어졌다.
* 옛 `⇕+`·`⇕−`·`▲`·`▼` 네 버튼은 그래서 없앴다.
*
* **배율 1 = 기본값이자 축소 한계**(사용자 확정) — 폭맞춤보다 더 줄이면 측점이 겹쳐
* 읽을 수 없다. 한계에 닿은 버튼은 흐리게 죽인다.
*
* 배율은 페이지가 들고 있다 — 편집·재계산으로 다시 그려도 유지된다(B06 `cardZoomStates` 규칙).
* ========================================================================== */
/** 한 번 누를 때 배율 배수. 횡단도 줌(1/0.85)보다 성글게 — 폭 배수라 한 칸이 크게 느껴진다. */
const ZOOM_STEP = 1.25;
/** 가로 폭 배수 상한 — 이 이상은 캔버스가 수만 px이 되어 브라우저가 버겁다. */
const MAX_X = 8;
export interface ProfileZoomState {
/** 가로 폭 배수(1 = 현행 폭맞춤 = 기본값·축소 한계). */
x: number;
}
export interface ProfileZoom {
/** 절·성토 요약줄 오른쪽 끝에 붙는 버튼 묶음(한 번 만들어 계속 쓴다). */
bar: HTMLElement;
state: () => ProfileZoomState;
}
const clamp = (value: number, min: number, max: number): number =>
Math.min(max, Math.max(min, value));
export function createProfileZoom(onChange: () => void): ProfileZoom {
const state: ProfileZoomState = { x: 1 };
const bar = document.createElement("div");
bar.className = "b05-profile__zoom";
function add(label: string, title: string, action: () => void): HTMLButtonElement {
const button = document.createElement("button");
button.type = "button";
// 부품 「아이콘 단추」 단 22(553-2) · 글자 기호 그대로
button.className = "ui-icon-btn ui-icon-btn--ghost b05-profile__zoom-btn";
button.setAttribute("data-size", "22");
button.textContent = label;
button.title = title;
button.setAttribute("aria-label", title);
button.addEventListener("click", (event) => {
// 카드·측점 선택으로 번지면 그래프를 다시 그리며 방금 맞춘 배율이 날아간다.
event.stopPropagation();
action();
syncDisabled();
onChange();
});
bar.append(button);
return button;
}
const zoomIn = add("+", "가로 확대 — 측점 간격을 넓혀 폅니다 (세로는 자동으로 맞춥니다)", () => {
state.x = clamp(state.x * ZOOM_STEP, 1, MAX_X);
});
const zoomOut = add("−", "가로 축소 — 기본 폭(화면 맞춤)까지만 줄어듭니다", () => {
state.x = clamp(state.x / ZOOM_STEP, 1, MAX_X);
});
add("⤢", "기본 상태로 — 가로 폭맞춤, 세로 자동", () => {
state.x = 1;
});
/** 한계에 닿은 버튼은 눌러도 변화가 없다 — 흐리게 죽여 그 사실을 보인다. */
function syncDisabled(): void {
zoomOut.disabled = state.x <= 1 + 1e-9;
zoomIn.disabled = state.x >= MAX_X - 1e-9;
}
syncDisabled();
return { bar, state: () => ({ ...state }) };
}