Files
Aislo/B06_Section/B06_Section_UI_Cross_View_Zoom.ts
T
eomsangdonandClaude Opus 5 abe956affc feat(b05): 계획노선 편집 손질 여섯 — 교각점 고정·횡단 벡터화·라벨 맨 위
- 교각점 고정 단추: 켜면 그 꺾임점이 노드·손잡이 어느 쪽으로도 안 끌림(`apexLock`)
- 계획 횡단선을 절·성토 교차점에서 끊음 — 그 밖은 원지반이라 지반선과 겹쳐 그려지던 것.
  교차점은 B06 이 쓰는 `toeOffsets` 를 열어 함께 씀
- 횡단 판을 캔버스에서 SVG 로 바꾸고 휠 줌·가운데 끌기 팬·더블클릭 원복을 붙임
- 줌·팬 본문을 `A00_Common/b_svg_zoom_pan.ts` 공용 조각으로 빼고 B06 은 감싸개만 남김
- 「이전 횡단」 판은 계획 평면선이 바뀔 때만 채움(같은 측점 두 번 누르기로는 안 채움)
- 「거리 재기」 단추의 눌린 꼴 추가 · 등고선 높이 라벨을 맨 위로 올리고 더 촘촘히

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJffo4VwgTumVUM3kdbJzd
2026-09-12 20:37:13 +09:00

103 lines
4.5 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.
/* =============================================================================
* B06_Section_UI_Cross_View_Zoom.ts
* 횡단 카드 그래프의 **확대·축소·팬** 조작구.
*
* ⚠ 줌·팬 **본문은 공용 조각**(`A00_Common/b_svg_zoom_pan.ts`)으로 옮겼다
* (2026-09-12 사용자 지시 「공용화해줘」) — 계획노선 편집 횡단이 같은 코드를 쓴다.
* 여기에는 **B06 것**만 남는다: 카드 여백(`CROSS_PAD`)을 씌운 감싸개, 측점별 배율 기억,
* 우측 상단 버튼 묶음. 동작 규칙(휠은 줌이 아님)은 그대로다 — 카드가 수십 장 깔리는
* 화면에서 휠을 줌에 묶으면 목록을 훑을 수가 없다(2026-08-02 사용자 확정).
* ========================================================================== */
import {
attachSvgZoomPan,
type ContentBounds,
type ZoomPanHandle,
type ZoomPanState,
} from "../A00_Common/b_svg_zoom_pan";
import { CROSS_PAD, L } from "./B06_Section_UI_Section_Common";
export type { ContentBounds, ZoomPanHandle, ZoomPanState };
/**
* 카드 표시 반폭 조작(2026-08-23 사용자 지시). 카드 하단 ◀/▶/↺을 없애고 우측 상단
* 줌 버튼에 합쳤다 — 원배율에서 −는 폭 넓히기, +는 폭 좁히기, ⤢는 교차점 맞춤이다.
*/
export interface CrossWidthActions {
/** 표시 반폭을 deltaM(m)만큼 조절한다. 계산 반폭을 넘으면 페이지가 재생성까지 처리. */
step: (deltaM: number) => void;
/**
* 초기화 — 표시 반폭을 전역 보기값으로 되돌린다. 단 그 폭에서 절·성토선과 원지반의
* 교차점이 안 보이는 측점은 교차점이 보이는 폭이 그 측점의 기본값이다.
*/
fit: () => void;
}
/** 측점별 줌·팬 상태 — 카드를 다시 만들어도 배율이 살아남는다(2026-08-22 사용자 ③). */
export const cardZoomStates = new Map<string, ZoomPanState>();
/** 카드 SVG 에 줌·팬을 붙인다 — 여백만 씌워 공용 조각에 넘긴다. 부르는 꼴은 그대로다. */
export function attachZoomPan(
svg: SVGSVGElement,
plotLayer: SVGGElement,
widthPx: number,
heightPx: number,
/** 이전 카드의 줌·팬 상태 — 조정창 조작으로 카드가 다시 그려져도 배율 유지. */
initial?: ZoomPanState,
/** 상태가 바뀔 때마다 부른다 — 카드 밖(뷰)이 담아 뒀다가 다음 렌더에 되돌린다. */
onChange?: (state: ZoomPanState) => void,
/** 도형이 실제로 그려진 범위(캐시 보유 폭). 확대 상태에서 팬 한계가 여기까지 늘어난다. */
content?: ContentBounds,
): ZoomPanHandle {
return attachSvgZoomPan({
svg,
layer: plotLayer,
widthPx,
heightPx,
pad: CROSS_PAD,
initial,
onChange,
content,
// 휠은 카드 목록을 훑는 몫이다 — 줌에 안 묶는다.
wheelZoom: false,
});
}
/**
* 그래프 우측 상단 줌 버튼(확대/축소/핏). 휠을 대신하는 조작구다.
*
* `width`를 넘기면 **원배율에서만** 버튼이 표시 반폭을 조절한다(2026-08-23 사용자 지시):
* + : 배율 확대(항상)
* − : 배율>1이면 축소, 원배율이면 표시 반폭 +1m(계산 반폭 20m를 넘으면 백엔드 재계산)
* ⤢ : 배율 원복 + 표시 반폭 초기화(전역 보기값, 교차점이 안 보이면 보이는 폭까지)
*/
export function buildZoomControls(handle: ZoomPanHandle, width?: CrossWidthActions): HTMLElement {
const bar = document.createElement("div");
bar.className = "b06-cross-card__zoom";
const add = (label: string, title: string, action: () => void): void => {
const button = document.createElement("button");
button.type = "button";
button.className = "b06-cross-card__zoom-btn";
button.textContent = label;
button.title = title;
button.addEventListener("click", (event) => {
// 카드 선택으로 번지면 그래프가 다시 그려져 방금 맞춘 배율이 날아간다.
event.stopPropagation();
action();
});
bar.append(button);
};
// +는 언제나 배율 확대다 — 원배율에서 폭 좁히기로 바꿔 놨더니 배율이 1에서 못 올라가
// 가운데 버튼 팬(배율>1에서만 열림)까지 막혔다(2026-08-23 사용자 보고).
add("+", L("B06_Profile_View_ZoomIn"), () => handle.zoom(1 / 0.85));
add("", L("B06_Profile_View_ZoomOut"), () => {
if (!width || handle.scale() > 1 + 1e-6) handle.zoom(0.85);
else width.step(1);
});
add("⤢", L("B06_Profile_View_ZoomFit"), () => {
handle.reset();
width?.fit();
});
return bar;
}