- 교각점 고정 단추: 켜면 그 꺾임점이 노드·손잡이 어느 쪽으로도 안 끌림(`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
103 lines
4.5 KiB
TypeScript
103 lines
4.5 KiB
TypeScript
/* =============================================================================
|
||
* 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;
|
||
}
|