fix(B05): 종단 그래프에서 측점을 골라도 선택이 풀리던 것 수정

끌어서 이동이 pointerdown 즉시 `setPointerCapture` 를 걸어, 뒤따르는 click 의
대상이 측점 `<g>` 가 아니라 스크롤러가 됐다. 그래서 측점 클릭이 배경 클릭으로
처리돼 선택이 그 자리에서 풀렸다(사용자 보고: 측점을 골라도 하이라이트가 안 됨).

- 포인터 잡기를 **끌기 문턱을 넘긴 뒤로** 미룸. 단순 클릭은 캡처가 없어 측점에
  그대로 닿고, 실제로 끌기 시작한 뒤에는 잡아 두어 창 밖에서 손을 떼도 이어진다.
- 문턱 4px → 6px. 손 떨림에 쉽게 넘어가 측점을 고르기 어려웠다.

검증(공용 브라우저, 실제 마우스 입력): 측점 클릭 → 선택·하이라이트 정상(420m),
끌기 → 선택 유지하며 팬 이동(scrollLeft 1660 → 1780).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-06 16:37:38 +09:00
co-authored by Claude Opus 5
parent 7086959e10
commit 7b0aced287
+15 -5
View File
@@ -24,7 +24,9 @@ const EASE = 0.35;
/** 이보다 가까우면 도착으로 보고 딱 맞춘다(px). */
const SNAP_PX = 0.5;
/** 이만큼 넘게 움직여야 "끌기"로 본다(px). 그 아래는 클릭(측점 선택)으로 흘려보낸다. */
const DRAG_THRESHOLD_PX = 4;
/** 이만큼 움직여야 「끌기」로 본다 — 그 아래는 클릭이다.
* 4px 은 손 떨림에도 넘어가 측점을 고르기 어려웠다(2026-09-06 사용자 지적). */
const DRAG_THRESHOLD_PX = 6;
/** 끌기를 시작하면 안 되는 조작 부품 — 이 위에서 누른 것은 그 부품의 몫이다.
* 구조물 마크는 자기 `pointerdown`에서 전파를 끊으므로 여기 적지 않아도 된다. */
const DRAG_BLOCK_SELECTOR =
@@ -95,9 +97,15 @@ export function attachWheelHorizontalScroll(scroller: HTMLElement): void {
);
/* ── 끌어서 이동 ─────────────────────────────────────────────────────────
* 좌클릭(0)·휠 버튼(1)으로 잡아 끈다. 문턱(4px)을 넘긴 뒤에야 이동으로 보고, 넘긴
* 경우에만 뒤따르는 click을 한 번 삼킨다 — 그래야 "그림을 조금 움직였는데 측점 선택이
* 풀리는" 일이 없다. 창 밖에서 손을 떼도 풀리도록 포인터를 잡아 둔다.
* 좌클릭(0)·휠 버튼(1)으로 잡아 끈다. 문턱을 넘긴 뒤에야 이동으로 보고, 넘긴 경우에만
* 뒤따르는 click을 한 번 삼킨다 — 그래야 "그림을 조금 움직였는데 측점 선택이 풀리는"
* 일이 없다.
*
* ⚠ 포인터 잡기(`setPointerCapture`)는 **문턱을 넘긴 뒤에만** 한다(2026-09-06).
* 누르는 즉시 잡으면 뒤따르는 click 의 대상이 측점 `<g>` 가 아니라 스크롤러가 되어,
* 측점 클릭이 배경 클릭으로 처리되고 선택이 그 자리에서 풀렸다 — 「측점을 골라도
* 하이라이트가 안 된다」는 증상의 원인. 끌기가 실제로 시작된 뒤에는 잡아 두어야
* 창 밖에서 손을 떼도 이동이 풀리지 않는다.
*/
let dragId: number | null = null;
let dragX = 0;
@@ -137,7 +145,7 @@ export function attachWheelHorizontalScroll(scroller: HTMLElement): void {
dragLeft = scroller.scrollLeft;
dragTop = scroller.scrollTop;
dragMoved = false;
scroller.setPointerCapture(event.pointerId);
// 여기서는 포인터를 잡지 않는다 — 위 주석 참고(클릭이 측점에 닿아야 한다).
// 휠 버튼은 브라우저 자동 스크롤이 뜨므로 막는다.
if (event.button === 1) event.preventDefault();
});
@@ -150,6 +158,8 @@ export function attachWheelHorizontalScroll(scroller: HTMLElement): void {
if (!dragMoved) {
dragMoved = true;
scroller.style.cursor = "grabbing";
// 이제부터 진짜 끌기다 — 창 밖으로 나가도 이어지도록 포인터를 잡는다.
scroller.setPointerCapture(event.pointerId);
}
scroller.scrollLeft = dragLeft - dx;
scroller.scrollTop = dragTop - dy;