- 공용 부품 ui_template_gl_map(지도 세우기 · 자료 · 켬끔 · 색 다시 · 카메라) — D03 GL 껍데기를 올림 · D03 은 겹 꼴만(바뀜 없음) - TM 주인 따라가기(B04_PreProcess_UI_MapGl · logic/_MapGl_Frame) — 화면 가운데 1차 맞춤 닮음꼴 카메라 + 남는 늘림(웹 메르카토르 가로세로 0.43 %)은 지도 칸 CSS 행렬 · 칸 둘레 여유 8 px - B04 하단 지도 — 위성 조각(줌인 선명) · 백지도 · 혼합 · 도엽 · 지적 · 행정 · 등고선 겹 GL · 등고 글 · 배수유역 · 계획선 · 관 = 위 캔버스 - B05 배수유역도 — 위성 · 세부유역 채움(짝홀 다각형) · 분수령 · 도엽 GL · 번호 · 상류 세류 · 관 · 강도 = 위 캔버스 - B05 평면 노선 편집 — 바탕칠 · LAS · 도엽 등고선(간격 거름 · 1 m 선) · 하천(LAS 상자 자름) GL · 노선 둘레 띠 = 지도 칸 clip-path · 고른 등고선 · 글 · 노선 · 꼭짓점 = 위 캔버스 - 켬끔 칸(GPU · 세 화면 한 취향 aislo:pref:map.canvas) · WebGL 못 씀 · 잃음 = 옛 캔버스 + 알림 · 누름 · 끌기 판정 손 안 댐 - B04 층 단추 글 = MapLayers gisLayerLabel(지도 본체 700 줄) - 지킴 시험 test_589_2_gl_frame(카메라 대 캔버스 0.5 px · 칸 행렬 늘이기만 · 되돌림 1 mm · 상자 자르기 · 짝홀 다각형) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
112 lines
4.0 KiB
TypeScript
112 lines
4.0 KiB
TypeScript
/* =============================================================================
|
|
* B04_PreProcess_UI_MapViewer_Gl.ts
|
|
* B04 하단 지도 GL 바탕(PLAN 589-2) — 백지도 · 혼합(한 장 그림) · 위성(조각 · 줌인 선명) · 도엽 · 지적 · 행정 ·
|
|
* 등고선 겹을 MapLibre 로. 등고 글 · 배수유역 · 계획선 · 측점 · 흐름 강도 · 세부유역 · 관 = 위 캔버스 그대로.
|
|
* 지도 본체(`_MapViewer`)는 켬끔 · 자료 · 따라가기만 부름(700 줄).
|
|
* ========================================================================== */
|
|
|
|
import { getVWorldMapUrl, type VWorldMeta } from "./B04_PreProcess_Api_Fetch";
|
|
import {
|
|
BACKGROUND_LAYERS,
|
|
GIS_LAYERS,
|
|
gisLayerColor,
|
|
type BackgroundLayer,
|
|
type GisLayer,
|
|
} from "./B04_PreProcess_UI_MapLayers";
|
|
import { createLayerToggle } from "./B04_PreProcess_UI_LayerToggle";
|
|
import {
|
|
createTmGl,
|
|
GL_TOGGLE_TITLE,
|
|
lineSpecs,
|
|
metaCorners,
|
|
rasterSpec,
|
|
satelliteData,
|
|
} from "./B04_PreProcess_UI_MapGl";
|
|
import {
|
|
normalizedToScreen,
|
|
type GeoJsonCollection,
|
|
type Normalizer,
|
|
type ViewState,
|
|
} from "./B04_PreProcess_UI_MapRender";
|
|
|
|
type Key = BackgroundLayer | GisLayer;
|
|
const isContour = (layer: GisLayer): boolean => layer === "등고선" || layer === "도엽_등고선";
|
|
/** 캔버스와 같은 차례 — 등고선이 맨 밑. */
|
|
const ORDER = [...GIS_LAYERS].sort((a, b) => (isContour(a) ? -1 : isContour(b) ? 1 : 0));
|
|
|
|
export interface SurfaceMapGl {
|
|
/** 지금 GL 로 그리나 — 참이면 캔버스는 바탕 겹을 쉼 · 그림(img)은 숨김. */
|
|
on: () => boolean;
|
|
/** 켠 겹. */
|
|
sync: (backgrounds: ReadonlySet<BackgroundLayer>, layers: ReadonlySet<GisLayer>) => void;
|
|
/** 받은 겹(원본 경위도 GeoJSON) — null = 비움. */
|
|
setLayer: (layer: GisLayer, data: GeoJsonCollection | null) => void;
|
|
/** 프로젝트 · 메타 — 그림 · 조각 주소(null = 다 비움). */
|
|
setMeta: (projectId: string | null, meta: VWorldMeta | null) => void;
|
|
follow: (meta: VWorldMeta | null, normalizer: Normalizer | null, view: ViewState) => void;
|
|
dispose: () => void;
|
|
}
|
|
|
|
/** `buttons` = 켬끔 칩 자리 · `onChange` = 켬끔이 바뀜(그림 숨김 · 다시 그림). */
|
|
export function createSurfaceMapGl(
|
|
viewport: HTMLElement,
|
|
buttons: HTMLElement,
|
|
onChange: () => void,
|
|
): SurfaceMapGl {
|
|
const toggle = createLayerToggle({
|
|
label: "GPU",
|
|
title: GL_TOGGLE_TITLE,
|
|
onChange: () => tm.toggle(),
|
|
});
|
|
toggle.root.dataset.layer = "gl";
|
|
buttons.append(toggle.root);
|
|
const tm = createTmGl<Key>({
|
|
parent: viewport,
|
|
specs: () => [
|
|
...BACKGROUND_LAYERS.map((layer) => rasterSpec<Key>(layer)),
|
|
...ORDER.flatMap((layer) =>
|
|
lineSpecs<Key>(layer, gisLayerColor(layer), isContour(layer) ? 0.7 : 1.5, {
|
|
marker: layer === "도엽_표고점" ? "x" : "dot",
|
|
}),
|
|
),
|
|
],
|
|
themeNames: ["--color-surface", "--map-cadastral", "--map-sheet-contour", "--map-sheet-stream"],
|
|
onChange: (on) => {
|
|
toggle.set(on);
|
|
onChange();
|
|
},
|
|
});
|
|
toggle.set(tm.on());
|
|
return {
|
|
on: tm.on,
|
|
sync(backgrounds, layers) {
|
|
for (const layer of BACKGROUND_LAYERS) tm.gl.setVisible(layer, backgrounds.has(layer));
|
|
for (const layer of GIS_LAYERS) tm.gl.setVisible(layer, layers.has(layer));
|
|
},
|
|
setLayer: (layer, data) => tm.gl.setData(layer, data),
|
|
setMeta(projectId, meta) {
|
|
tm.gl.setData("satellite", projectId ? satelliteData(projectId) : null);
|
|
for (const layer of ["white", "hybrid"] as const)
|
|
tm.gl.setData(
|
|
layer,
|
|
projectId && meta
|
|
? {
|
|
url: location.origin + getVWorldMapUrl(projectId, layer),
|
|
corners: metaCorners(meta),
|
|
}
|
|
: null,
|
|
);
|
|
if (!meta) for (const layer of GIS_LAYERS) tm.gl.setData(layer, null);
|
|
},
|
|
follow: (meta, normalizer, view) =>
|
|
tm.follow(
|
|
meta,
|
|
normalizer,
|
|
(nx, ny) => normalizedToScreen(view, nx, ny),
|
|
view.width,
|
|
view.height,
|
|
),
|
|
dispose: tm.dispose,
|
|
};
|
|
}
|