refactor(B04): 전처리 화면 자체 변종을 부품 상자 부품으로 — 켜기 칩 · 분할 고르기 · 고르기 · 슬라이더 · 값 목록 · 카드 · 도구줄 (PLAN 553-1)

- 지도 층 단추 열다섯 안팎 · 표시 토글 셋 · 라이다 겹침 = 켜기 칩(층 색 점) · 도엽 보간 방식 = 분할 고르기 · 도구줄 부품
- 고르기 38 → 고르기 부품 · 점 크기 · 밀도 = 슬라이더 · 입력 파일 정보 = 값 목록 · 초기화 = 위험 고스트 · 묶음 상자 = 카드 + 패널 머리
- 죽은 CSS 열여섯 걷음 · 날 색 → 공통 값 · 가이드 촬영 선택자 · 지킴 시험 test_553_1_pages 늘림

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 22:09:36 +09:00
co-authored by Claude Sonnet 5.5
parent a826804277
commit 58dafb1572
14 changed files with 441 additions and 858 deletions
+29 -37
View File
@@ -1,5 +1,6 @@
import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale";
import { themeColor } from "@ui/ui_template_palette";
import { createLayerToggle, setLayerLabel } from "./B04_PreProcess_UI_LayerToggle";
import { fetchWatershedAnalysis, type WatershedAnalysis } from "./B04_PreProcess_Api_Fetch";
import { drawFlowArrows } from "./B04_PreProcess_UI_FlowArrows";
import type { Normalizer, ViewState } from "./B04_PreProcess_UI_MapRender";
@@ -127,13 +128,14 @@ export function createWatershedOverlay(onChange: () => void): WatershedOverlay {
busyElement.hidden = text === "";
}
const button = document.createElement("button");
button.type = "button";
button.className = "b04-map__layer-button b04-map__layer-button--gis";
button.textContent = L("B04_Surface_Watershed_Btn");
button.style.setProperty("--b04-layer-color", themeColor("--color-danger", "#dc2626"));
button.setAttribute("aria-pressed", "false");
button.title = L("B04_Surface_Watershed_Btn_Tip");
// 재산정 단추 — 층 칩 꼴 · 눌러도 켜짐은 분석 결과가 정함(loadAnalysis 가 맞춤)
const toggle = createLayerToggle({
label: L("B04_Surface_Watershed_Btn"),
color: themeColor("--color-danger", "#dc2626"),
title: L("B04_Surface_Watershed_Btn_Tip"),
onChange: () => void loadAnalysis(true),
});
const button = toggle.root;
// 갈래별 표시 여부. 전체 토글(button)이 꺼져 있으면 이 값과 무관하게 아무것도 안 그린다.
// 1차 유역·유역 방향은 격자가 지도를 덮어 판독을 방해하므로 기본 꺼짐(2026-08-01 사용자 지시).
@@ -143,23 +145,18 @@ export function createWatershedOverlay(onChange: () => void): WatershedOverlay {
flow: false,
arrows: true,
};
const partButtons = PARTS.map((part) => {
const element = document.createElement("button");
element.type = "button";
const initialActive = shownParts[part.key];
element.className =
"b04-map__layer-button b04-map__layer-button--gis" + (initialActive ? " is-active" : "");
element.textContent = L(part.labelKey);
element.style.setProperty("--b04-layer-color", themeColor(part.token[0], part.token[1]));
element.setAttribute("aria-pressed", String(initialActive));
element.addEventListener("click", () => {
shownParts[part.key] = !shownParts[part.key];
element.classList.toggle("is-active", shownParts[part.key]);
element.setAttribute("aria-pressed", String(shownParts[part.key]));
onChange();
});
return element;
});
const partButtons = PARTS.map(
(part) =>
createLayerToggle({
label: L(part.labelKey),
color: themeColor(part.token[0], part.token[1]),
on: shownParts[part.key],
onChange: (on) => {
shownParts[part.key] = on;
onChange();
},
}).root,
);
let projectId: string | null = null;
@@ -495,8 +492,9 @@ export function createWatershedOverlay(onChange: () => void): WatershedOverlay {
if (!projectId || busy) return;
busy = true;
button.disabled = true;
button.textContent = L(
refresh ? "B04_Surface_Watershed_Btn_Analyzing" : "B04_Surface_Watershed_Btn_Loading",
setLayerLabel(
toggle,
L(refresh ? "B04_Surface_Watershed_Btn_Analyzing" : "B04_Surface_Watershed_Btn_Loading"),
);
// 진행 문구는 우상단 전용 줄에 띄운다 — 좌상단의 직전 결과를 지우지 않는다.
sayBusy(
@@ -508,8 +506,7 @@ export function createWatershedOverlay(onChange: () => void): WatershedOverlay {
try {
analysis = await fetchWatershedAnalysis(projectId, refresh);
shown = true;
button.classList.add("is-active");
button.setAttribute("aria-pressed", "true");
toggle.set(true);
const seconds = ((performance.now() - started) / 1000).toFixed(1);
const origin = analysis.from_cache
? L("B04_Surface_Watershed_Origin_Cached")
@@ -518,8 +515,7 @@ export function createWatershedOverlay(onChange: () => void): WatershedOverlay {
} catch (error) {
analysis = null;
shown = false;
button.classList.remove("is-active");
button.setAttribute("aria-pressed", "false");
toggle.set(false);
const message =
error instanceof Error ? error.message : L("B04_Surface_Watershed_LoadFailed");
// 저장분이 아직 없는 것은 오류가 아니다 — 무엇을 눌러야 하는지 알려 준다.
@@ -532,17 +528,14 @@ export function createWatershedOverlay(onChange: () => void): WatershedOverlay {
busy = false;
sayBusy(""); // 끝났으면 진행 문구를 거둔다 — 결과는 좌상단 줄에 남는다
button.disabled = false;
button.textContent = L("B04_Surface_Watershed_Btn");
setLayerLabel(toggle, L("B04_Surface_Watershed_Btn"));
onChange();
}
}
// 재산정 버튼은 언제나 처음부터 다시 분석한다.
// 재산정 버튼은 언제나 처음부터 다시 분석한다(칩의 onChange = 위 toggle).
// (저장분을 자동으로 띄우게 바꾼 뒤로 이 버튼이 표시 토글로 먼저 걸려, 눌러도 아무 일이
// 없는 것처럼 보였다 — 2026-08-01. 보이기/숨기기는 갈래별 버튼이 맡는다.)
button.addEventListener("click", () => {
void loadAnalysis(true);
});
return {
button,
@@ -557,8 +550,7 @@ export function createWatershedOverlay(onChange: () => void): WatershedOverlay {
flowCache = null;
shown = false;
say("");
button.classList.remove("is-active");
button.setAttribute("aria-pressed", "false");
toggle.set(false);
},
setProject(next: string) {
projectId = next;