refactor(map): Map3D 모듈 분리 + 버그 4건 수정 + 수심 색상 개선
Map3D.tsx 단일 파일(5752줄)에서 1200줄을 16개 모듈로 추출하여
탐색성과 유지보수성 개선.
모듈 구조:
- types.ts, constants.ts: 타입/상수 정의
- lib/: setUtils, geometry, featureIds, mlExpressions, shipUtils,
tooltips, globeShipIcon, mapCore, dashifyLine, layerHelpers, zoneUtils
- layers/: bathymetry, seamark
- hooks/: useHoverState
버그 수정:
- fix: Globe 선박 라벨 미표시 (permitted boolean→number + filter 갱신)
- fix: placement TypeError (isStyleLoaded 가드 + epoch change 시 remove 제거)
- fix: Globe easeTo 미지원 경고 (globe 모드에서 flyTo 사용)
- fix: 수심지도 얕은 구간 색상 미구분 (색상 팔레트 개선)
개선:
- 베이스맵 water 레이어 색상을 수심 그라데이션과 자연스럽게 연결
- 프로젝션 전환 settle 로직 최적화 (더블프레임→싱글프레임)
- glyphs URL 추가로 symbol 레이어 텍스트 렌더링 지원
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:57:38 +09:00
|
|
|
import maplibregl, {
|
|
|
|
|
type LayerSpecification,
|
|
|
|
|
type StyleSpecification,
|
|
|
|
|
type VectorSourceSpecification,
|
|
|
|
|
} from 'maplibre-gl';
|
|
|
|
|
import type { BaseMapId, BathyZoomRange, MapProjectionId } from '../types';
|
|
|
|
|
import { getLayerId, getMapTilerKey } from '../lib/mapCore';
|
|
|
|
|
|
|
|
|
|
const BATHY_ZOOM_RANGES: BathyZoomRange[] = [
|
|
|
|
|
{ id: 'bathymetry-fill', mercator: [6, 24], globe: [8, 24] },
|
|
|
|
|
{ id: 'bathymetry-borders', mercator: [6, 24], globe: [8, 24] },
|
|
|
|
|
{ id: 'bathymetry-borders-major', mercator: [4, 24], globe: [8, 24] },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export function injectOceanBathymetryLayers(style: StyleSpecification, maptilerKey: string) {
|
|
|
|
|
const oceanSourceId = 'maptiler-ocean';
|
|
|
|
|
|
|
|
|
|
if (!style.sources) style.sources = {} as StyleSpecification['sources'];
|
|
|
|
|
if (!style.layers) style.layers = [];
|
|
|
|
|
|
|
|
|
|
if (!style.sources[oceanSourceId]) {
|
|
|
|
|
style.sources[oceanSourceId] = {
|
|
|
|
|
type: 'vector',
|
|
|
|
|
url: `https://api.maptiler.com/tiles/ocean/tiles.json?key=${encodeURIComponent(maptilerKey)}`,
|
|
|
|
|
} satisfies VectorSourceSpecification as unknown as StyleSpecification['sources'][string];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const depth = ['to-number', ['get', 'depth']] as unknown as number[];
|
|
|
|
|
const depthLabel = ['concat', ['to-string', ['*', depth, -1]], 'm'] as unknown as string[];
|
|
|
|
|
|
|
|
|
|
// Bug #3 fix: shallow depths now use brighter teal tones to distinguish from deep ocean
|
|
|
|
|
const bathyFillColor = [
|
|
|
|
|
'interpolate',
|
|
|
|
|
['linear'],
|
|
|
|
|
depth,
|
|
|
|
|
-11000,
|
|
|
|
|
'#00040b',
|
|
|
|
|
-8000,
|
|
|
|
|
'#010610',
|
|
|
|
|
-6000,
|
|
|
|
|
'#020816',
|
|
|
|
|
-4000,
|
|
|
|
|
'#030c1c',
|
|
|
|
|
-2000,
|
|
|
|
|
'#041022',
|
|
|
|
|
-1000,
|
|
|
|
|
'#051529',
|
|
|
|
|
-500,
|
|
|
|
|
'#061a30',
|
|
|
|
|
-200,
|
|
|
|
|
'#071f36',
|
|
|
|
|
-100,
|
|
|
|
|
'#08263d',
|
|
|
|
|
-50,
|
|
|
|
|
'#0e3d5e',
|
|
|
|
|
-20,
|
|
|
|
|
'#145578',
|
|
|
|
|
-10,
|
|
|
|
|
'#1a6e8e',
|
|
|
|
|
0,
|
|
|
|
|
'#2097a6',
|
|
|
|
|
] as const;
|
|
|
|
|
|
|
|
|
|
const bathyFill: LayerSpecification = {
|
|
|
|
|
id: 'bathymetry-fill',
|
|
|
|
|
type: 'fill',
|
|
|
|
|
source: oceanSourceId,
|
|
|
|
|
'source-layer': 'contour',
|
2026-02-16 01:10:45 +09:00
|
|
|
minzoom: 5,
|
refactor(map): Map3D 모듈 분리 + 버그 4건 수정 + 수심 색상 개선
Map3D.tsx 단일 파일(5752줄)에서 1200줄을 16개 모듈로 추출하여
탐색성과 유지보수성 개선.
모듈 구조:
- types.ts, constants.ts: 타입/상수 정의
- lib/: setUtils, geometry, featureIds, mlExpressions, shipUtils,
tooltips, globeShipIcon, mapCore, dashifyLine, layerHelpers, zoneUtils
- layers/: bathymetry, seamark
- hooks/: useHoverState
버그 수정:
- fix: Globe 선박 라벨 미표시 (permitted boolean→number + filter 갱신)
- fix: placement TypeError (isStyleLoaded 가드 + epoch change 시 remove 제거)
- fix: Globe easeTo 미지원 경고 (globe 모드에서 flyTo 사용)
- fix: 수심지도 얕은 구간 색상 미구분 (색상 팔레트 개선)
개선:
- 베이스맵 water 레이어 색상을 수심 그라데이션과 자연스럽게 연결
- 프로젝션 전환 settle 로직 최적화 (더블프레임→싱글프레임)
- glyphs URL 추가로 symbol 레이어 텍스트 렌더링 지원
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:57:38 +09:00
|
|
|
maxzoom: 24,
|
|
|
|
|
paint: {
|
|
|
|
|
'fill-color': bathyFillColor,
|
2026-02-16 01:10:45 +09:00
|
|
|
'fill-opacity': ['interpolate', ['linear'], ['zoom'], 0, 0.9, 5, 0.88, 8, 0.84, 10, 0.78],
|
refactor(map): Map3D 모듈 분리 + 버그 4건 수정 + 수심 색상 개선
Map3D.tsx 단일 파일(5752줄)에서 1200줄을 16개 모듈로 추출하여
탐색성과 유지보수성 개선.
모듈 구조:
- types.ts, constants.ts: 타입/상수 정의
- lib/: setUtils, geometry, featureIds, mlExpressions, shipUtils,
tooltips, globeShipIcon, mapCore, dashifyLine, layerHelpers, zoneUtils
- layers/: bathymetry, seamark
- hooks/: useHoverState
버그 수정:
- fix: Globe 선박 라벨 미표시 (permitted boolean→number + filter 갱신)
- fix: placement TypeError (isStyleLoaded 가드 + epoch change 시 remove 제거)
- fix: Globe easeTo 미지원 경고 (globe 모드에서 flyTo 사용)
- fix: 수심지도 얕은 구간 색상 미구분 (색상 팔레트 개선)
개선:
- 베이스맵 water 레이어 색상을 수심 그라데이션과 자연스럽게 연결
- 프로젝션 전환 settle 로직 최적화 (더블프레임→싱글프레임)
- glyphs URL 추가로 symbol 레이어 텍스트 렌더링 지원
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:57:38 +09:00
|
|
|
},
|
|
|
|
|
} as unknown as LayerSpecification;
|
|
|
|
|
|
|
|
|
|
const bathyBandBorders: LayerSpecification = {
|
|
|
|
|
id: 'bathymetry-borders',
|
|
|
|
|
type: 'line',
|
|
|
|
|
source: oceanSourceId,
|
|
|
|
|
'source-layer': 'contour',
|
2026-02-16 01:10:45 +09:00
|
|
|
minzoom: 5,
|
refactor(map): Map3D 모듈 분리 + 버그 4건 수정 + 수심 색상 개선
Map3D.tsx 단일 파일(5752줄)에서 1200줄을 16개 모듈로 추출하여
탐색성과 유지보수성 개선.
모듈 구조:
- types.ts, constants.ts: 타입/상수 정의
- lib/: setUtils, geometry, featureIds, mlExpressions, shipUtils,
tooltips, globeShipIcon, mapCore, dashifyLine, layerHelpers, zoneUtils
- layers/: bathymetry, seamark
- hooks/: useHoverState
버그 수정:
- fix: Globe 선박 라벨 미표시 (permitted boolean→number + filter 갱신)
- fix: placement TypeError (isStyleLoaded 가드 + epoch change 시 remove 제거)
- fix: Globe easeTo 미지원 경고 (globe 모드에서 flyTo 사용)
- fix: 수심지도 얕은 구간 색상 미구분 (색상 팔레트 개선)
개선:
- 베이스맵 water 레이어 색상을 수심 그라데이션과 자연스럽게 연결
- 프로젝션 전환 settle 로직 최적화 (더블프레임→싱글프레임)
- glyphs URL 추가로 symbol 레이어 텍스트 렌더링 지원
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:57:38 +09:00
|
|
|
maxzoom: 24,
|
|
|
|
|
paint: {
|
|
|
|
|
'line-color': 'rgba(255,255,255,0.06)',
|
|
|
|
|
'line-opacity': ['interpolate', ['linear'], ['zoom'], 4, 0.12, 8, 0.18, 12, 0.22],
|
|
|
|
|
'line-blur': ['interpolate', ['linear'], ['zoom'], 4, 0.8, 10, 0.2],
|
|
|
|
|
'line-width': ['interpolate', ['linear'], ['zoom'], 4, 0.2, 8, 0.35, 12, 0.6],
|
|
|
|
|
},
|
|
|
|
|
} as unknown as LayerSpecification;
|
|
|
|
|
|
|
|
|
|
const bathyLinesMinor: LayerSpecification = {
|
|
|
|
|
id: 'bathymetry-lines',
|
|
|
|
|
type: 'line',
|
|
|
|
|
source: oceanSourceId,
|
|
|
|
|
'source-layer': 'contour_line',
|
2026-02-16 01:10:45 +09:00
|
|
|
minzoom: 7,
|
refactor(map): Map3D 모듈 분리 + 버그 4건 수정 + 수심 색상 개선
Map3D.tsx 단일 파일(5752줄)에서 1200줄을 16개 모듈로 추출하여
탐색성과 유지보수성 개선.
모듈 구조:
- types.ts, constants.ts: 타입/상수 정의
- lib/: setUtils, geometry, featureIds, mlExpressions, shipUtils,
tooltips, globeShipIcon, mapCore, dashifyLine, layerHelpers, zoneUtils
- layers/: bathymetry, seamark
- hooks/: useHoverState
버그 수정:
- fix: Globe 선박 라벨 미표시 (permitted boolean→number + filter 갱신)
- fix: placement TypeError (isStyleLoaded 가드 + epoch change 시 remove 제거)
- fix: Globe easeTo 미지원 경고 (globe 모드에서 flyTo 사용)
- fix: 수심지도 얕은 구간 색상 미구분 (색상 팔레트 개선)
개선:
- 베이스맵 water 레이어 색상을 수심 그라데이션과 자연스럽게 연결
- 프로젝션 전환 settle 로직 최적화 (더블프레임→싱글프레임)
- glyphs URL 추가로 symbol 레이어 텍스트 렌더링 지원
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:57:38 +09:00
|
|
|
paint: {
|
|
|
|
|
'line-color': [
|
|
|
|
|
'interpolate',
|
|
|
|
|
['linear'],
|
|
|
|
|
depth,
|
|
|
|
|
-11000,
|
|
|
|
|
'rgba(255,255,255,0.04)',
|
|
|
|
|
-6000,
|
|
|
|
|
'rgba(255,255,255,0.05)',
|
|
|
|
|
-2000,
|
|
|
|
|
'rgba(255,255,255,0.07)',
|
|
|
|
|
0,
|
|
|
|
|
'rgba(255,255,255,0.10)',
|
|
|
|
|
],
|
|
|
|
|
'line-opacity': ['interpolate', ['linear'], ['zoom'], 8, 0.18, 10, 0.22, 12, 0.28],
|
|
|
|
|
'line-blur': ['interpolate', ['linear'], ['zoom'], 8, 0.8, 11, 0.3],
|
|
|
|
|
'line-width': ['interpolate', ['linear'], ['zoom'], 8, 0.35, 10, 0.55, 12, 0.85],
|
|
|
|
|
},
|
|
|
|
|
} as unknown as LayerSpecification;
|
|
|
|
|
|
|
|
|
|
const majorDepths = [-50, -100, -200, -500, -1000, -2000, -4000, -6000, -8000, -9500];
|
|
|
|
|
const bathyMajorDepthFilter: unknown[] = [
|
|
|
|
|
'in',
|
|
|
|
|
['to-number', ['get', 'depth']],
|
|
|
|
|
['literal', majorDepths],
|
|
|
|
|
] as unknown[];
|
|
|
|
|
|
|
|
|
|
const bathyLinesMajor: LayerSpecification = {
|
|
|
|
|
id: 'bathymetry-lines-major',
|
|
|
|
|
type: 'line',
|
|
|
|
|
source: oceanSourceId,
|
|
|
|
|
'source-layer': 'contour_line',
|
2026-02-16 01:10:45 +09:00
|
|
|
minzoom: 7,
|
refactor(map): Map3D 모듈 분리 + 버그 4건 수정 + 수심 색상 개선
Map3D.tsx 단일 파일(5752줄)에서 1200줄을 16개 모듈로 추출하여
탐색성과 유지보수성 개선.
모듈 구조:
- types.ts, constants.ts: 타입/상수 정의
- lib/: setUtils, geometry, featureIds, mlExpressions, shipUtils,
tooltips, globeShipIcon, mapCore, dashifyLine, layerHelpers, zoneUtils
- layers/: bathymetry, seamark
- hooks/: useHoverState
버그 수정:
- fix: Globe 선박 라벨 미표시 (permitted boolean→number + filter 갱신)
- fix: placement TypeError (isStyleLoaded 가드 + epoch change 시 remove 제거)
- fix: Globe easeTo 미지원 경고 (globe 모드에서 flyTo 사용)
- fix: 수심지도 얕은 구간 색상 미구분 (색상 팔레트 개선)
개선:
- 베이스맵 water 레이어 색상을 수심 그라데이션과 자연스럽게 연결
- 프로젝션 전환 settle 로직 최적화 (더블프레임→싱글프레임)
- glyphs URL 추가로 symbol 레이어 텍스트 렌더링 지원
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:57:38 +09:00
|
|
|
maxzoom: 24,
|
|
|
|
|
filter: bathyMajorDepthFilter as unknown as unknown[],
|
|
|
|
|
paint: {
|
|
|
|
|
'line-color': 'rgba(255,255,255,0.16)',
|
|
|
|
|
'line-opacity': ['interpolate', ['linear'], ['zoom'], 8, 0.22, 10, 0.28, 12, 0.34],
|
|
|
|
|
'line-blur': ['interpolate', ['linear'], ['zoom'], 8, 0.4, 11, 0.2],
|
|
|
|
|
'line-width': ['interpolate', ['linear'], ['zoom'], 8, 0.6, 10, 0.95, 12, 1.3],
|
|
|
|
|
},
|
|
|
|
|
} as unknown as LayerSpecification;
|
|
|
|
|
|
|
|
|
|
const bathyBandBordersMajor: LayerSpecification = {
|
|
|
|
|
id: 'bathymetry-borders-major',
|
|
|
|
|
type: 'line',
|
|
|
|
|
source: oceanSourceId,
|
|
|
|
|
'source-layer': 'contour',
|
2026-02-16 01:10:45 +09:00
|
|
|
minzoom: 3,
|
refactor(map): Map3D 모듈 분리 + 버그 4건 수정 + 수심 색상 개선
Map3D.tsx 단일 파일(5752줄)에서 1200줄을 16개 모듈로 추출하여
탐색성과 유지보수성 개선.
모듈 구조:
- types.ts, constants.ts: 타입/상수 정의
- lib/: setUtils, geometry, featureIds, mlExpressions, shipUtils,
tooltips, globeShipIcon, mapCore, dashifyLine, layerHelpers, zoneUtils
- layers/: bathymetry, seamark
- hooks/: useHoverState
버그 수정:
- fix: Globe 선박 라벨 미표시 (permitted boolean→number + filter 갱신)
- fix: placement TypeError (isStyleLoaded 가드 + epoch change 시 remove 제거)
- fix: Globe easeTo 미지원 경고 (globe 모드에서 flyTo 사용)
- fix: 수심지도 얕은 구간 색상 미구분 (색상 팔레트 개선)
개선:
- 베이스맵 water 레이어 색상을 수심 그라데이션과 자연스럽게 연결
- 프로젝션 전환 settle 로직 최적화 (더블프레임→싱글프레임)
- glyphs URL 추가로 symbol 레이어 텍스트 렌더링 지원
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:57:38 +09:00
|
|
|
maxzoom: 24,
|
|
|
|
|
filter: bathyMajorDepthFilter as unknown as unknown[],
|
|
|
|
|
paint: {
|
|
|
|
|
'line-color': 'rgba(255,255,255,0.14)',
|
2026-02-16 01:10:45 +09:00
|
|
|
'line-opacity': ['interpolate', ['linear'], ['zoom'], 3, 0.10, 6, 0.16, 8, 0.2, 12, 0.26],
|
|
|
|
|
'line-blur': ['interpolate', ['linear'], ['zoom'], 3, 0.5, 6, 0.35, 10, 0.15],
|
|
|
|
|
'line-width': ['interpolate', ['linear'], ['zoom'], 3, 0.25, 6, 0.4, 8, 0.55, 12, 0.85],
|
refactor(map): Map3D 모듈 분리 + 버그 4건 수정 + 수심 색상 개선
Map3D.tsx 단일 파일(5752줄)에서 1200줄을 16개 모듈로 추출하여
탐색성과 유지보수성 개선.
모듈 구조:
- types.ts, constants.ts: 타입/상수 정의
- lib/: setUtils, geometry, featureIds, mlExpressions, shipUtils,
tooltips, globeShipIcon, mapCore, dashifyLine, layerHelpers, zoneUtils
- layers/: bathymetry, seamark
- hooks/: useHoverState
버그 수정:
- fix: Globe 선박 라벨 미표시 (permitted boolean→number + filter 갱신)
- fix: placement TypeError (isStyleLoaded 가드 + epoch change 시 remove 제거)
- fix: Globe easeTo 미지원 경고 (globe 모드에서 flyTo 사용)
- fix: 수심지도 얕은 구간 색상 미구분 (색상 팔레트 개선)
개선:
- 베이스맵 water 레이어 색상을 수심 그라데이션과 자연스럽게 연결
- 프로젝션 전환 settle 로직 최적화 (더블프레임→싱글프레임)
- glyphs URL 추가로 symbol 레이어 텍스트 렌더링 지원
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:57:38 +09:00
|
|
|
},
|
|
|
|
|
} as unknown as LayerSpecification;
|
|
|
|
|
|
|
|
|
|
const bathyLabels: LayerSpecification = {
|
|
|
|
|
id: 'bathymetry-labels',
|
|
|
|
|
type: 'symbol',
|
|
|
|
|
source: oceanSourceId,
|
|
|
|
|
'source-layer': 'contour_line',
|
|
|
|
|
minzoom: 10,
|
|
|
|
|
filter: bathyMajorDepthFilter as unknown as unknown[],
|
|
|
|
|
layout: {
|
|
|
|
|
'symbol-placement': 'line',
|
|
|
|
|
'text-field': depthLabel,
|
|
|
|
|
'text-font': ['Noto Sans Regular', 'Open Sans Regular'],
|
|
|
|
|
'text-size': ['interpolate', ['linear'], ['zoom'], 10, 12, 12, 14, 14, 15],
|
|
|
|
|
'text-allow-overlap': false,
|
|
|
|
|
'text-padding': 2,
|
|
|
|
|
'text-rotation-alignment': 'map',
|
|
|
|
|
},
|
|
|
|
|
paint: {
|
|
|
|
|
'text-color': 'rgba(226,232,240,0.72)',
|
|
|
|
|
'text-halo-color': 'rgba(2,6,23,0.82)',
|
|
|
|
|
'text-halo-width': 1.0,
|
|
|
|
|
'text-halo-blur': 0.6,
|
|
|
|
|
},
|
|
|
|
|
} as unknown as LayerSpecification;
|
|
|
|
|
|
|
|
|
|
const landformLabels: LayerSpecification = {
|
|
|
|
|
id: 'bathymetry-landforms',
|
|
|
|
|
type: 'symbol',
|
|
|
|
|
source: oceanSourceId,
|
|
|
|
|
'source-layer': 'landform',
|
|
|
|
|
minzoom: 8,
|
|
|
|
|
filter: ['has', 'name'] as unknown as unknown[],
|
|
|
|
|
layout: {
|
|
|
|
|
'text-field': ['get', 'name'] as unknown as unknown[],
|
|
|
|
|
'text-font': ['Noto Sans Italic', 'Noto Sans Regular', 'Open Sans Italic', 'Open Sans Regular'],
|
|
|
|
|
'text-size': ['interpolate', ['linear'], ['zoom'], 8, 11, 10, 12, 12, 13],
|
|
|
|
|
'text-allow-overlap': false,
|
|
|
|
|
'text-anchor': 'center',
|
|
|
|
|
'text-offset': [0, 0.0],
|
|
|
|
|
},
|
|
|
|
|
paint: {
|
|
|
|
|
'text-color': 'rgba(148,163,184,0.70)',
|
|
|
|
|
'text-halo-color': 'rgba(2,6,23,0.85)',
|
|
|
|
|
'text-halo-width': 1.0,
|
|
|
|
|
'text-halo-blur': 0.7,
|
|
|
|
|
},
|
|
|
|
|
} as unknown as LayerSpecification;
|
|
|
|
|
|
|
|
|
|
const layers = Array.isArray(style.layers) ? (style.layers as unknown as LayerSpecification[]) : [];
|
|
|
|
|
if (!Array.isArray(style.layers)) {
|
|
|
|
|
style.layers = layers as unknown as StyleSpecification['layers'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Brighten base-map water fills so shallow coasts, rivers & lakes blend naturally
|
|
|
|
|
// with the bathymetry gradient instead of appearing as near-black voids.
|
|
|
|
|
const waterRegex = /(water|sea|ocean|river|lake|coast|bay)/i;
|
|
|
|
|
const SHALLOW_WATER_FILL = '#14606e';
|
|
|
|
|
const SHALLOW_WATER_LINE = '#114f5c';
|
|
|
|
|
for (const layer of layers) {
|
|
|
|
|
const id = getLayerId(layer);
|
|
|
|
|
if (!id) continue;
|
|
|
|
|
const spec = layer as Record<string, unknown>;
|
|
|
|
|
const sourceLayer = String(spec['source-layer'] ?? '').toLowerCase();
|
|
|
|
|
const layerType = String(spec.type ?? '');
|
|
|
|
|
const isWater = waterRegex.test(id) || waterRegex.test(sourceLayer);
|
|
|
|
|
if (!isWater) continue;
|
|
|
|
|
|
|
|
|
|
const paint = (spec.paint ?? {}) as Record<string, unknown>;
|
|
|
|
|
if (layerType === 'fill') {
|
|
|
|
|
paint['fill-color'] = SHALLOW_WATER_FILL;
|
|
|
|
|
spec.paint = paint;
|
|
|
|
|
} else if (layerType === 'line') {
|
|
|
|
|
paint['line-color'] = SHALLOW_WATER_LINE;
|
|
|
|
|
spec.paint = paint;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const symbolIndex = layers.findIndex((l) => (l as { type?: unknown } | null)?.type === 'symbol');
|
|
|
|
|
const insertAt = symbolIndex >= 0 ? symbolIndex : layers.length;
|
|
|
|
|
|
|
|
|
|
const existingIds = new Set<string>();
|
|
|
|
|
for (const layer of layers) {
|
|
|
|
|
const id = getLayerId(layer);
|
|
|
|
|
if (id) existingIds.add(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const toInsert = [
|
|
|
|
|
bathyFill,
|
|
|
|
|
bathyBandBorders,
|
|
|
|
|
bathyBandBordersMajor,
|
|
|
|
|
bathyLinesMinor,
|
|
|
|
|
bathyLinesMajor,
|
|
|
|
|
bathyLabels,
|
|
|
|
|
landformLabels,
|
|
|
|
|
].filter((l) => !existingIds.has(l.id));
|
|
|
|
|
if (toInsert.length > 0) layers.splice(insertAt, 0, ...toInsert);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function applyBathymetryZoomProfile(map: maplibregl.Map, baseMap: BaseMapId, projection: MapProjectionId) {
|
|
|
|
|
if (!map || !map.isStyleLoaded()) return;
|
|
|
|
|
if (baseMap !== 'enhanced') return;
|
|
|
|
|
const isGlobe = projection === 'globe';
|
|
|
|
|
|
|
|
|
|
for (const range of BATHY_ZOOM_RANGES) {
|
|
|
|
|
if (!map.getLayer(range.id)) continue;
|
|
|
|
|
const [minzoom, maxzoom] = isGlobe ? range.globe : range.mercator;
|
|
|
|
|
try {
|
|
|
|
|
map.setLayoutProperty(range.id, 'visibility', 'visible');
|
|
|
|
|
} catch {
|
|
|
|
|
// ignore
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
map.setLayerZoomRange(range.id, minzoom, maxzoom);
|
|
|
|
|
} catch {
|
|
|
|
|
// ignore
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function resolveInitialMapStyle(signal: AbortSignal): Promise<string | StyleSpecification> {
|
|
|
|
|
const key = getMapTilerKey();
|
|
|
|
|
if (!key) return '/map/styles/osm-seamark.json';
|
|
|
|
|
|
|
|
|
|
const baseMapId = (import.meta.env.VITE_MAPTILER_BASE_MAP_ID || 'dataviz-dark').trim();
|
|
|
|
|
const styleUrl = `https://api.maptiler.com/maps/${encodeURIComponent(baseMapId)}/style.json?key=${encodeURIComponent(key)}`;
|
|
|
|
|
|
|
|
|
|
const res = await fetch(styleUrl, { signal, headers: { accept: 'application/json' } });
|
|
|
|
|
if (!res.ok) throw new Error(`MapTiler style fetch failed: ${res.status} ${res.statusText}`);
|
|
|
|
|
const json = (await res.json()) as StyleSpecification;
|
|
|
|
|
injectOceanBathymetryLayers(json, key);
|
|
|
|
|
return json;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function resolveMapStyle(baseMap: BaseMapId, signal: AbortSignal): Promise<string | StyleSpecification> {
|
|
|
|
|
if (baseMap === 'legacy') return '/map/styles/carto-dark.json';
|
|
|
|
|
return resolveInitialMapStyle(signal);
|
|
|
|
|
}
|