- 겹 단추 = 공용 지도 도구줄(createMapTools) 한 줄 · 묶음 셋(바탕 · 물 · 길 · 구역) · 넘치면 가로 밀기 · 오른쪽 도구줄 자리 = 겹 줄 폭(--d03-layers-w) - 새 겹 처음 값 = 끔 · 켬끔 기억(aislo:pref:d03.layers) · 받기 실패 = 그 겹만 꺼짐 + 알림 - 범례 = 켠 겹마다 한 줄(급경사 비율 · 보호구역 종류별 곳 · ha · 띠 ha · % · 물 면 · 건물 · 임도 짐작 수) - 면 겹 채움 · 겹 정의 = D03_PlanAnalysis_UI_LayerDefs.ts(700줄 한도로 나눔) - 부품 상자: 아이콘 shield · borderOuter · 그림 색 --draw-map-* 열넷 - 음영기복 빈 칸 투명(HILLSHADE_VERSION 2) - 시험 test_553_4_de_parts 의 D03 겹 단추 대조 고침 — 겹 단추가 createToolbar 에서 공용 지도 도구줄로 · 겹 열셋으로 바뀌어 옛 대조가 낡음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
136 lines
4.7 KiB
TypeScript
136 lines
4.7 KiB
TypeScript
/* =============================================================================
|
|
* D03_PlanAnalysis_UI_LayerDefs.ts
|
|
* D03 바탕 겹 정의(PLAN 569-2 · 581-1) — 겹 단추 묶음 · 처음 값 · 보호구역 색 · 면 겹 채우기.
|
|
* 부르는 곳 = `D03_PlanAnalysis_UI_Layers.ts`(받기 · 그리기 차례 · 범례).
|
|
* ========================================================================== */
|
|
|
|
import type { IconName } from "@ui/ui_template_icons";
|
|
import {
|
|
normalizedToScreen,
|
|
type PreparedLayer,
|
|
type ViewState,
|
|
} from "../B04_PreProcess/B04_PreProcess_UI_MapRender";
|
|
|
|
export type PlanLayerKey =
|
|
| "satellite"
|
|
| "hillshade"
|
|
| "contour"
|
|
| "slope"
|
|
| "stream"
|
|
| "water"
|
|
| "road"
|
|
| "forestRoad"
|
|
| "cadastral"
|
|
| "zones"
|
|
| "bands"
|
|
| "building"
|
|
| "place";
|
|
|
|
export interface LayerDef {
|
|
key: PlanLayerKey;
|
|
icon: IconName;
|
|
title: string;
|
|
on: boolean;
|
|
}
|
|
|
|
/** 단추 묶음(사이 나눔선) — 바탕 · 물 · 길 · 구역. 「지금」 겹 처음 값 = 끔(`_분석_440-C` 1-4). */
|
|
export const GROUPS: readonly (readonly LayerDef[])[] = [
|
|
[
|
|
{ key: "satellite", icon: "satellite", title: "위성사진", on: true },
|
|
{ key: "hillshade", icon: "sun", title: "음영기복(2 m 지형 · 산줄기 · 골)", on: false },
|
|
{ key: "contour", icon: "mountain", title: "도엽 등고선(굵은 선 = 계곡선 25 m)", on: true },
|
|
{ key: "slope", icon: "angle", title: "급경사 색(15° · 35° · 40° 이상)", on: false },
|
|
],
|
|
[
|
|
{ key: "stream", icon: "droplet", title: "세류선(가는 파랑) · 하천(굵은 파랑)", on: true },
|
|
{ key: "water", icon: "ripple", title: "물 면(도엽 실폭하천 · 저수지 등)", on: false },
|
|
{ key: "road", icon: "road", title: "기존 도로(도엽 도로중심선)", on: false },
|
|
{
|
|
key: "forestRoad",
|
|
icon: "route",
|
|
title: "기존 임도 짐작(도엽 도로 소로 · 미분류 = 주황 점선 · 정식 임도망도 아님)",
|
|
on: false,
|
|
},
|
|
],
|
|
[
|
|
{ key: "cadastral", icon: "borderAll", title: "지적도(참고용 · 법적 효력 없음)", on: false },
|
|
{
|
|
key: "zones",
|
|
icon: "shield",
|
|
title: "보호 · 규제 구역(브이월드 여덟 종 · 참고용)",
|
|
on: false,
|
|
},
|
|
{
|
|
key: "bands",
|
|
icon: "borderOuter",
|
|
title: "계류 100 m · 도로 300 m 띠(타당성평가)",
|
|
on: false,
|
|
},
|
|
{ key: "building", icon: "building", title: "건물(도엽 · 하류 민가 · 인가)", on: false },
|
|
{ key: "place", icon: "mapPin", title: "지명(도엽 계곡 · 령 · 부락)", on: false },
|
|
],
|
|
];
|
|
export const LAYERS: readonly LayerDef[] = GROUPS.flat();
|
|
/** 보호구역 종류 → 그림 색 값(서버 `ZONE_KINDS` 열쇠). */
|
|
export const ZONE_COLORS: Record<string, string> = {
|
|
forest: "--draw-map-zone-forest",
|
|
baekdu: "--draw-map-zone-baekdu",
|
|
water: "--draw-map-zone-water",
|
|
park: "--draw-map-zone-park",
|
|
heritage: "--draw-map-zone-heritage",
|
|
wetland: "--draw-map-zone-wetland",
|
|
wildlife: "--draw-map-zone-wildlife",
|
|
greenbelt: "--draw-map-zone-greenbelt",
|
|
};
|
|
/** 도로 중 기존 임도로 짐작하는 구분. */
|
|
export const FOREST_ROAD_KINDS = new Set(["소로", "미분류"]);
|
|
/** 물 면 = 도엽 수계(E) 면 셋. */
|
|
export const WATER_KEYS = ["실폭하천", "수계면E003", "수계면E005"];
|
|
|
|
export const hectare = (m2: number): string => `${(m2 / 10000).toFixed(1)} ha`;
|
|
|
|
/** 면 겹 채움 — 지물마다 한 길(evenodd = 구멍) · 화면 밖 지물 거름(돌린 지도 귀퉁이까지 여유). */
|
|
export function fillLayer(
|
|
context: CanvasRenderingContext2D,
|
|
layer: PreparedLayer,
|
|
view: ViewState,
|
|
fill: string,
|
|
alpha: number,
|
|
edge?: { color: string; width: number; dash?: number[] },
|
|
): void {
|
|
const [ox, oy] = normalizedToScreen(view, 0, 0);
|
|
const [ex, ey] = normalizedToScreen(view, 1, 1);
|
|
const ax = ex - ox;
|
|
const ay = ey - oy;
|
|
const pad = Math.max(view.width, view.height) / 2;
|
|
context.fillStyle = fill;
|
|
if (edge) {
|
|
context.strokeStyle = edge.color;
|
|
context.lineWidth = edge.width;
|
|
context.setLineDash(edge.dash ?? []);
|
|
}
|
|
for (const feature of layer.features) {
|
|
if (
|
|
feature.maxX * ax + ox < -pad ||
|
|
feature.minX * ax + ox > view.width + pad ||
|
|
feature.maxY * ay + oy < -pad ||
|
|
feature.minY * ay + oy > view.height + pad
|
|
)
|
|
continue;
|
|
context.beginPath();
|
|
for (const { coords } of feature.parts) {
|
|
context.moveTo(coords[0] * ax + ox, coords[1] * ay + oy);
|
|
for (let i = 2; i < coords.length; i += 2)
|
|
context.lineTo(coords[i] * ax + ox, coords[i + 1] * ay + oy);
|
|
context.closePath();
|
|
}
|
|
context.globalAlpha = alpha;
|
|
context.fill("evenodd");
|
|
if (edge) {
|
|
context.globalAlpha = 0.9;
|
|
context.stroke();
|
|
}
|
|
}
|
|
context.setLineDash([]);
|
|
}
|