feat(B04/B05): 지도 레이어 기본 표시값 정의 + 명칭 정리
2026-08-01 사용자 지정 기본값을 한곳(BACKGROUND_DEFAULT_ON / GIS_DEFAULT_ON / CONTOUR_LABEL_DEFAULT_ON)에 모아 정의한다. - 켜짐: 백지도, 위성, 시군구, 읍면동, 세류(전체) - 꺼짐: 하이브리드, 연속지적도, 등고선, 도엽등고선, 표고점, 성절토, 옹벽석축, 등고라벨 - 유수방향 레이어는 화면에서 제외(목록에서 삭제) - 명칭: 세류(하천중심선) -> 세류(전체), 배수유역 재산정 -> 유역 분석 - 유역 갈래 기본값(1차 꺼짐 / 2차 켜짐 / 유역방향 꺼짐 / 평균흐름 켜짐)은 기존과 동일 - B05 배수유역도 초기 보기는 도로 기준 줌인으로 되돌림(B04 하단 지도는 배경 전체 보기 유지) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,7 @@ export interface SurfaceMapViewer {
|
||||
}
|
||||
|
||||
const BACKGROUND_LAYERS = ["white", "satellite", "hybrid"] as const;
|
||||
// 유수방향은 화면에 쓰지 않기로 해 목록에서 뺐다(2026-08-01 사용자 지시).
|
||||
const GIS_LAYERS = [
|
||||
"지적도",
|
||||
"행정구역_시군구",
|
||||
@@ -40,11 +41,34 @@ const GIS_LAYERS = [
|
||||
"도엽_표고점",
|
||||
"도엽_성절토",
|
||||
"도엽_옹벽석축",
|
||||
"도엽_유수방향",
|
||||
] as const;
|
||||
type BackgroundLayer = (typeof BACKGROUND_LAYERS)[number];
|
||||
type GisLayer = (typeof GIS_LAYERS)[number];
|
||||
|
||||
/* ── 처음 열었을 때 켜져 있을 레이어 (2026-08-01 사용자 지정) ──────────────
|
||||
* 지도가 복잡해지지 않도록 실제로 자주 보는 것만 켠 채로 시작한다.
|
||||
* 나머지는 버튼으로 그때그때 켠다. */
|
||||
const BACKGROUND_DEFAULT_ON: Record<BackgroundLayer, boolean> = {
|
||||
white: true,
|
||||
satellite: true,
|
||||
hybrid: false,
|
||||
};
|
||||
|
||||
const GIS_DEFAULT_ON: Record<GisLayer, boolean> = {
|
||||
지적도: false,
|
||||
행정구역_시군구: true,
|
||||
행정구역_읍면동: true,
|
||||
등고선: false,
|
||||
도엽_등고선: false,
|
||||
도엽_하천중심선: true,
|
||||
도엽_표고점: false,
|
||||
도엽_성절토: false,
|
||||
도엽_옹벽석축: false,
|
||||
};
|
||||
|
||||
/** 등고 라벨(계곡선 수치) 기본 표시 여부. */
|
||||
const CONTOUR_LABEL_DEFAULT_ON = false;
|
||||
|
||||
const GIS_LAYER_COLORS: Record<GisLayer, string> = {
|
||||
지적도: "#f97316",
|
||||
행정구역_시군구: "#7c3aed",
|
||||
@@ -55,7 +79,6 @@ const GIS_LAYER_COLORS: Record<GisLayer, string> = {
|
||||
도엽_표고점: "#f9a8d4",
|
||||
도엽_성절토: "#f43f5e",
|
||||
도엽_옹벽석축: "#0f766e",
|
||||
도엽_유수방향: "#0891b2",
|
||||
};
|
||||
|
||||
// 등고 라벨 표기 대상 레이어와 표고 속성 키 (gpkg=CTRLN_HG, 도엽=등고수치)
|
||||
@@ -152,10 +175,11 @@ export function createSurfaceMapViewer(): SurfaceMapViewer {
|
||||
let normalizer: Normalizer | null = null;
|
||||
// 사전 투영된 렌더용 레이어. 원본 GeoJSON은 변형하지 않으며 투영 후에는 참조를 잡아두지 않는다.
|
||||
const preparedLayers = new Map<GisLayer, PreparedLayer>();
|
||||
const activeBackgrounds = new Set<BackgroundLayer>(BACKGROUND_LAYERS);
|
||||
// gpkg 등고선은 기본 꺼짐(도엽 등고선이 기본 표기), 등고 라벨은 기본 켜짐 (2026-07-26 사용자 지시)
|
||||
const activeGisLayers = new Set<GisLayer>(GIS_LAYERS.filter((layer) => layer !== "등고선"));
|
||||
let showContourLabels = true;
|
||||
const activeBackgrounds = new Set<BackgroundLayer>(
|
||||
BACKGROUND_LAYERS.filter((layer) => BACKGROUND_DEFAULT_ON[layer]),
|
||||
);
|
||||
const activeGisLayers = new Set<GisLayer>(GIS_LAYERS.filter((layer) => GIS_DEFAULT_ON[layer]));
|
||||
let showContourLabels = CONTOUR_LABEL_DEFAULT_ON;
|
||||
let scale = 1;
|
||||
let offsetX = 0;
|
||||
let offsetY = 0;
|
||||
@@ -215,7 +239,6 @@ export function createSurfaceMapViewer(): SurfaceMapViewer {
|
||||
도엽_표고점: L("B04_Surface_Map_SheetElevPoint"),
|
||||
도엽_성절토: L("B04_Surface_Map_SheetCutFill"),
|
||||
도엽_옹벽석축: L("B04_Surface_Map_SheetWall"),
|
||||
도엽_유수방향: L("B04_Surface_Map_SheetFlowDir"),
|
||||
};
|
||||
GIS_LAYERS.forEach((layer) => {
|
||||
gisButtons.append(
|
||||
@@ -223,12 +246,13 @@ export function createSurfaceMapViewer(): SurfaceMapViewer {
|
||||
);
|
||||
});
|
||||
|
||||
// 등고 라벨 보기/숨기기 (기본 켜짐 — 등고선·도엽 등고선의 계곡선 수치 표기)
|
||||
// 등고 라벨 보기/숨기기 (등고선·도엽 등고선의 계곡선 수치 표기)
|
||||
const contourLabelButton = document.createElement("button");
|
||||
contourLabelButton.type = "button";
|
||||
contourLabelButton.className = "b04-map__layer-button is-active";
|
||||
contourLabelButton.className =
|
||||
"b04-map__layer-button" + (CONTOUR_LABEL_DEFAULT_ON ? " is-active" : "");
|
||||
contourLabelButton.textContent = L("B04_Surface_Map_ContourLabel");
|
||||
contourLabelButton.setAttribute("aria-pressed", "true");
|
||||
contourLabelButton.setAttribute("aria-pressed", String(CONTOUR_LABEL_DEFAULT_ON));
|
||||
contourLabelButton.addEventListener("click", () => {
|
||||
showContourLabels = !showContourLabels;
|
||||
contourLabelButton.classList.toggle("is-active", showContourLabels);
|
||||
|
||||
@@ -82,7 +82,7 @@ export function createWatershedOverlay(onChange: () => void): WatershedOverlay {
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = "b04-map__layer-button b04-map__layer-button--gis";
|
||||
button.textContent = "배수유역 재산정";
|
||||
button.textContent = "유역 분석";
|
||||
button.style.setProperty("--b04-layer-color", "#dc2626");
|
||||
button.setAttribute("aria-pressed", "false");
|
||||
button.title =
|
||||
@@ -473,13 +473,13 @@ export function createWatershedOverlay(onChange: () => void): WatershedOverlay {
|
||||
// 저장분이 아직 없는 것은 오류가 아니다 — 무엇을 눌러야 하는지 알려 준다.
|
||||
say(
|
||||
refresh
|
||||
? `배수유역 재산정 실패: ${message}`
|
||||
: "저장된 배수유역 분석이 없습니다. [배수유역 재산정]을 누르세요.",
|
||||
? `유역 분석 실패: ${message}`
|
||||
: "저장된 배수유역 분석이 없습니다. [유역 분석]을 누르세요.",
|
||||
);
|
||||
} finally {
|
||||
busy = false;
|
||||
button.disabled = false;
|
||||
button.textContent = "배수유역 재산정";
|
||||
button.textContent = "유역 분석";
|
||||
onChange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,14 +475,39 @@ export function createDrainagePanel(): DrainagePanel {
|
||||
boundaryEditor.setEditMode(boundaryMode);
|
||||
});
|
||||
|
||||
/** 확보한 배경 지도(브이월드) 전체가 보이도록 맞춘다.
|
||||
/** 노선 전체가 보이도록 배율·중심을 맞춘다(초기 보기 = 도로 기준 줌인).
|
||||
*
|
||||
* 노선 범위에 맞춰 확대하면 배경을 넓게 받아도 화면에 보이는 범위가 늘 같았다
|
||||
* (2026-08-01 사용자 지적). 노선 주변 지형까지 함께 보고 판단하도록 배경 전체를 띄운다. */
|
||||
* B05는 노선 주변 배수유역을 보는 화면이라 도로에 맞춰 확대한 상태로 연다
|
||||
* (2026-08-01 사용자 지시). 배경 전체를 보려면 휠로 축소하면 된다.
|
||||
* 노선이 없으면 배경 전체를 그대로 보여준다. */
|
||||
function fitToRoute(): void {
|
||||
scale = 1;
|
||||
offsetX = 0;
|
||||
offsetY = 0;
|
||||
if (!meta || routePoints.length < 2) return;
|
||||
const rect = viewport.getBoundingClientRect();
|
||||
const width = Math.max(rect.width, 1);
|
||||
const height = Math.max(rect.height, 1);
|
||||
const mapRect = computeMapRect(meta, width, height);
|
||||
let minX = Infinity;
|
||||
let minY = Infinity;
|
||||
let maxX = -Infinity;
|
||||
let maxY = -Infinity;
|
||||
routePoints.forEach((point) => {
|
||||
if (point.x < minX) minX = point.x;
|
||||
if (point.x > maxX) maxX = point.x;
|
||||
if (point.y < minY) minY = point.y;
|
||||
if (point.y > maxY) maxY = point.y;
|
||||
});
|
||||
const routeWidth = Math.max(maxX - minX, 1);
|
||||
const routeHeight = Math.max(maxY - minY, 1);
|
||||
scale = Math.min(meta.width_meters / routeWidth, meta.height_meters / routeHeight) * 0.85;
|
||||
const centerX = (minX + maxX) / 2;
|
||||
const centerY = (minY + maxY) / 2;
|
||||
const baseX = mapRect.x + ((centerX - meta.x_min) / meta.width_meters) * mapRect.width;
|
||||
const baseY = mapRect.y + (1 - (centerY - meta.y_min) / meta.height_meters) * mapRect.height;
|
||||
offsetX = -(baseX - width / 2) * scale;
|
||||
offsetY = -(baseY - height / 2) * scale;
|
||||
}
|
||||
|
||||
async function loadLayers(): Promise<void> {
|
||||
|
||||
@@ -662,7 +662,7 @@ export const ui_locales = {
|
||||
B04_Surface_Map_Contour: ["등고선", "Contour lines"],
|
||||
B04_Surface_Map_SheetContour: ["도엽 등고선", "Sheet contours"],
|
||||
B04_Surface_Map_ContourLabel: ["등고 라벨", "Contour labels"],
|
||||
B04_Surface_Map_SheetStream: ["세류(하천중심선)", "Stream centerline"],
|
||||
B04_Surface_Map_SheetStream: ["세류(전체)", "Streams (all)"],
|
||||
B04_Surface_Map_SheetElevPoint: ["표고점", "Spot elevation"],
|
||||
B04_Surface_Map_SheetCutFill: ["성절토", "Cut/fill slope"],
|
||||
B04_Surface_Map_SheetWall: ["옹벽석축", "Retaining wall"],
|
||||
|
||||
Reference in New Issue
Block a user