fix(B05): 배수유역 영역 클릭 선택이 안 되던 문제

pointerdown에서 유역 고르기 후보(basinClickStart)를 기억하는 코드가 실제로는 들어가
있지 않아, pointerup의 후보가 늘 null이었고 pickBasinAt()이 한 번도 불리지 않았다.
같은 편집에 묶여 있던 좌클릭 전용 제한도 함께 빠져 있어 우클릭·가운데 클릭으로도
마커가 잡히고 있었다.

- 좌클릭일 때만 pipeEditor.handleDown()을 부르고, 잡았으면 pipeClickStart로 기록
- 마커를 못 잡은 좌클릭은 basinClickStart로 남겨 뗄 때 유역을 고른다
- 700줄 유지: basinIndexOfPipe()를 _Drainage_Parts.ts로 이동

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-02 00:32:06 +09:00
co-authored by Claude Opus 5
parent 0fb656ce49
commit 9cd70a14dc
2 changed files with 25 additions and 11 deletions
@@ -46,6 +46,7 @@ import {
MAX_PANEL_WIDTH_RATIO,
MIN_PANEL_WIDTH,
renderBasinRows,
basinIndexOfPipe,
pipeMarkerColor,
pointInRing,
reconcilePipes,
@@ -318,15 +319,11 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra
const pipeColor = (chainage: number): string => pipeMarkerColor(basins, chainage);
/** 마커 선택 ↔ 유역 목록 선택 동기화 + 삭제 버튼 활성화. */
/** 마커 선택 ↔ 유역 강조 동기화 + 삭제 버튼 활성화. */
function syncPipeSelection(): void {
const index = pipeEditor.selected();
deleteButton.disabled = index === null;
const pipe = index === null ? null : pipeEditor.pipes()[index];
const basin = pipe
? basins.find((item) => Math.abs(item.chainage_m - pipe.chainage_m) < 0.51)
: null;
selectBasin(basin ? basin.index : null);
selectBasin(basinIndexOfPipe(basins, index === null ? null : pipeEditor.pipes()[index]));
}
function scheduleDraw(): void {
@@ -338,12 +335,11 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra
}
/** 유역 제원 목록을 다시 그린다. 항목을 누르면 해당 유역만 진하게 강조한다. */
/** 유역 제원 목록을 다시 그린다. 항목을 누르면 그 유역만 진하게 강조한다. */
function renderBasinList(): void {
/** 유역 제원 목록. 항목을 누르면 그 유역만 진하게 강조한다. */
const renderBasinList = (): void =>
renderBasinRows(basinList, basins, selectedBasin, (index) =>
selectBasin(selectedBasin === index ? null : index),
);
}
/** 유역 강조를 바꾸는 **유일한 자리**. 지도 클릭·목록 클릭·마커 선택·밖에서 온 요청이 전부
* 여기를 거쳐야 그래프 측점선·사이드 패널과 어긋나지 않는다(2026-08-02 사용자 지시).
@@ -532,11 +528,19 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra
// 중간 버튼 기본 동작(페이지 자동 스크롤)이 지도 팬과 겹치지 않게 막는다.
if (event.button === 1) event.preventDefault();
const rect = viewport.getBoundingClientRect();
// 배관 마커 클릭/추가가 처리되면 지도 팬은 시작하지 않는다.
if (pipeEditor.handleDown(currentView(), event.clientX - rect.left, event.clientY - rect.top)) {
// 배관 마커는 **좌클릭으로만** 잡는다 — 우클릭은 메뉴, 가운데 버튼은 팬 전용이다
// (2026-08-01 사용자 지시).
if (
event.button === 0 &&
pipeEditor.handleDown(currentView(), event.clientX - rect.left, event.clientY - rect.top)
) {
// 마커를 잡은 좌클릭이므로 유역 고르기로는 넘기지 않는다.
pipeClickStart = { x: event.clientX, y: event.clientY };
viewport.setPointerCapture(event.pointerId);
return;
}
// 마커를 못 잡은 좌클릭은 유역 고르기 후보로 기억한다(끌지 않고 뗐을 때만 고른다).
if (event.button === 0) basinClickStart = { x: event.clientX, y: event.clientY };
// 팬은 가운데(휠) 버튼 전용이다. 좌버튼은 유역선 핸들·배관 마커를 고르고 끄는 데만 쓴다
// (좌버튼이 팬까지 겸하면 마커를 집으려다 지도가 딸려 움직인다 — 2026-08-01 사용자 지시).
// 가운데 버튼이 없는 터치·펜은 그대로 끌어서 팬 할 수 있게 둔다.
@@ -494,3 +494,13 @@ export function pipeMarkerColor(basins: ReadonlyArray<DetailBasin>, chainageM: n
if (!basin) return themeColor("--map-pipe-orphan", "#e5e7eb");
return basinColor(basin.index).replace(/0\.45\)$/, "1)");
}
/** 배관 마커가 받는 유역 번호. 마커가 없거나 대응 유역이 없으면 null. */
export function basinIndexOfPipe(
basins: ReadonlyArray<DetailBasin>,
pipe: { chainage_m: number } | null,
): number | null {
if (!pipe) return null;
const basin = basins.find((item) => Math.abs(item.chainage_m - pipe.chainage_m) < 0.51);
return basin ? basin.index : null;
}