diff --git a/B04_PreProcess/B04_PreProcess_UI_MapOverlays.ts b/B04_PreProcess/B04_PreProcess_UI_MapOverlays.ts index 9779fa2d..4b9867a1 100644 --- a/B04_PreProcess/B04_PreProcess_UI_MapOverlays.ts +++ b/B04_PreProcess/B04_PreProcess_UI_MapOverlays.ts @@ -55,10 +55,13 @@ export function drawFilledRing( drawRingBadge(context, [sumX / entry.ring.length, sumY / entry.ring.length], color, entry.label); } -/** 유역 번호 배지 한 개(원 + 숫자). 화면 좌표를 그대로 받는다. +/** 유역 번호 배지 한 개(라운드 사각 + 숫자). 화면 좌표를 그대로 받는다. * * 채움과 따로 떼어 둔 이유: 번호는 **맨 위에** 있어야 한다. 채움과 함께 그리면 그 위에 - * 얹히는 등고선·화살표·관 마커에 가려 읽을 수 없다(2026-08-01 사용자 지시). */ + * 얹히는 등고선·화살표·관 마커에 가려 읽을 수 없다(2026-08-01 사용자 지시). + * + * 원이 아니라 사각인 이유: 지도 위 다른 숫자들도 전부 동그라미라 크기로만 갈렸다. + * 형태를 바꿔 한눈에 구분되게 했다 — 크기는 그대로다(2026-08-17 사용자 지시). */ export function drawRingBadge( context: CanvasRenderingContext2D, center: readonly [number, number], @@ -66,9 +69,10 @@ export function drawRingBadge( label: string, ): void { const [centerX, centerY] = center; + const half = 11; context.save(); context.beginPath(); - context.arc(centerX, centerY, 11, 0, Math.PI * 2); + context.roundRect(centerX - half, centerY - half, half * 2, half * 2, 6); context.fillStyle = color; context.fill(); context.strokeStyle = haloColor(); diff --git a/B05_Profile/B05_Profile_UI_Drainage_Chrome.ts b/B05_Profile/B05_Profile_UI_Drainage_Chrome.ts index 11263f66..d8081564 100644 --- a/B05_Profile/B05_Profile_UI_Drainage_Chrome.ts +++ b/B05_Profile/B05_Profile_UI_Drainage_Chrome.ts @@ -65,9 +65,13 @@ export function createDrainageChrome( header.className = "b05-drainage__header"; const title = document.createElement("h3"); title.textContent = labels.title; + // 표시 필터 버튼 묶음 — 헤더가 아니라 지도 좌측 상단에 얹는다(2026-08-17 사용자 지시). + // 지도 위에 있으니 버튼을 누른 포인터가 아래 지도까지 내려가면 안 된다 — 유역 고르기가 + // 딸려 일어난다. 배선이 아니라 얹은 자리 때문에 생긴 것이라 여기서 막는다. const layerButtons = document.createElement("div"); layerButtons.className = "b05-drainage__layers"; - header.append(title, layerButtons); + layerButtons.addEventListener("pointerdown", (event) => event.stopPropagation()); + header.append(title); // 세부유역 산정 — B04가 미리 분석해 둔 결과를 읽어 관을 보충하고 세부유역만 나눈다. // 격자 해석은 하지 않으므로 즉시 끝난다. @@ -108,7 +112,19 @@ export function createDrainageChrome( const contextMenu = createMapContextMenu("b05-drainage"); // 유입 강도 색띠 범례 — CSS가 지도 우측 세로로 세운다. const legend = createFlowLegend(); - viewport.append(backgroundImage, canvas, status, progress.root, contextMenu.element, legend.root); + // 지도 좌상단 오버레이 — 필터 버튼 줄과 상태 문구를 세로로 쌓는다. 둘을 각각 지도에 + // 절대배치하면 버튼이 두 줄로 접힐 때 문구가 그 아래에 겹친다. + const mapOverlay = document.createElement("div"); + mapOverlay.className = "b05-drainage__map-overlay"; + mapOverlay.append(layerButtons, status); + viewport.append( + backgroundImage, + canvas, + mapOverlay, + progress.root, + contextMenu.element, + legend.root, + ); const summary = document.createElement("div"); summary.className = "b05-drainage__summary"; diff --git a/B05_Profile/B05_Profile_UI_Style.css b/B05_Profile/B05_Profile_UI_Style.css index 10e66579..b0c4e00a 100644 --- a/B05_Profile/B05_Profile_UI_Style.css +++ b/B05_Profile/B05_Profile_UI_Style.css @@ -958,15 +958,38 @@ font-size: var(--text-body-sm); } +/* 지도 좌상단 오버레이 — 표시 필터 버튼 줄 + 상태 문구(2026-08-17 사용자 지시로 + 헤더에서 옮겼다). 버튼 자체 여백과 별개로 지도 모서리에서 조금 띄운다. + 우측 폭을 묶는 이유: 화면 오른쪽 진행단계 오버레이(z-index 200)가 지도 위를 + 덮어, 여기까지 늘어난 버튼은 눌리지 않는다. 그 폭(패널 절반 + 우측 여백)을 뺀다. */ +.b05-drainage__map-overlay { + position: absolute; + z-index: 2; + top: var(--spacing-8); + left: var(--spacing-8); + display: flex; + flex-direction: column; + gap: var(--spacing-4); + /* 오버레이 빈 자리로는 지도 조작(팬·유역 고르기)이 그대로 통해야 한다. */ + pointer-events: none; +} + +/* 필터 버튼은 한 줄로 둔다 — 오른쪽 진행단계 오버레이에 끝이 가려도 창을 넓히거나 + 그 오버레이를 접으면 드러난다(2026-08-17 사용자 확정). 두 줄로 접는 쪽이 지도를 + 더 많이 가린다. */ .b05-drainage__layers { display: flex; - flex-wrap: wrap; + flex-wrap: nowrap; gap: var(--spacing-4); + pointer-events: auto; } /* 표시 토글 버튼 — B04 지도 레이어 버튼(.b04-map__layer-button--gis)과 같은 양식을 쓴다. 크기(패딩·글자)만 이 패널 기준을 유지한다(2026-08-01 사용자 지시). */ .b05-drainage__layer-button { + /* 한 줄 유지 — 좁아져도 글자가 접히거나 쭈그러들지 않게 크기를 고정한다. */ + flex: 0 0 auto; + white-space: nowrap; padding: 2px var(--spacing-8); border: 1px solid var(--color-border); border-radius: var(--radius-inputs); @@ -1050,9 +1073,8 @@ pointer-events: none; } +/* 상태 문구는 좌상단 오버레이가 세로로 쌓아 준다 — 필터 버튼 줄 바로 아래. */ .b05-drainage__status { - position: absolute; - inset: var(--spacing-8) var(--spacing-8) auto var(--spacing-8); color: var(--color-text-secondary); font-size: var(--text-caption); pointer-events: none;