mirror of
https://github.com/gadgethd/ukmesh.git
synced 2026-09-10 09:05:34 +00:00
Fix terrain toggle, preference restore, and low-zoom crash
- Load terrain source and hillshade dynamically (only when 3D mode is on) to prevent tile loading at idle, fixing low-zoom WebGL crash - Restore terrain correctly on page reload by applying inside map load handler - Clean up source, hillshade, and sky layers fully when terrain is toggled off - Raise minZoom to 6 to prevent crash at extreme zoom-out - Reduce terrain exaggeration to 3x as a stable middle ground Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
||||
MAP_STYLE,
|
||||
SEVEN_DAYS_MS,
|
||||
TERRAIN_CONFIG,
|
||||
TERRAIN_DEM_SOURCE,
|
||||
} from './mapConfig.js';
|
||||
import {
|
||||
buildClashLinesGeoJSON,
|
||||
@@ -74,6 +75,7 @@ export function MapLibreMap({
|
||||
const linkMetricsRef = useRef(linkStateStore.getState().linkMetrics);
|
||||
const inferredNodesRef = useRef(inferredNodes);
|
||||
const showLinksRef = useRef(showLinks);
|
||||
const showTerrainRef = useRef(showTerrain);
|
||||
const showClientNodesRef = useRef(showClientNodes);
|
||||
const showHexClashesRef = useRef(showHexClashes);
|
||||
const maxHexClashHopsRef = useRef(maxHexClashHops);
|
||||
@@ -208,29 +210,13 @@ export function MapLibreMap({
|
||||
center: [DEFAULT_CENTER[1], DEFAULT_CENTER[0]], // [lon, lat]
|
||||
zoom: DEFAULT_ZOOM,
|
||||
maxPitch: 0,
|
||||
minZoom: 6,
|
||||
attributionControl: false,
|
||||
});
|
||||
|
||||
map.on('load', () => {
|
||||
mapLoadedRef.current = true;
|
||||
|
||||
// ── Sky layer (for 3D terrain mode) ────────────────────────────────────
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
map.addLayer({ id: 'sky', type: 'sky', paint: { 'sky-type': 'atmosphere', 'sky-atmosphere-sun': [0, 90], 'sky-atmosphere-sun-intensity': 15 } } as any);
|
||||
|
||||
// ── Hillshade layer ────────────────────────────────────────────────────
|
||||
map.addLayer({
|
||||
id: 'hillshade',
|
||||
type: 'hillshade',
|
||||
source: 'terrain-dem',
|
||||
paint: {
|
||||
'hillshade-exaggeration': 0.7,
|
||||
'hillshade-shadow-color': '#000000',
|
||||
'hillshade-highlight-color': '#ffffff',
|
||||
'hillshade-illumination-anchor': 'viewport',
|
||||
},
|
||||
});
|
||||
|
||||
// ── Node dots source + layer ───────────────────────────────────────────
|
||||
map.addSource('nodes', { type: 'geojson', data: EMPTY_FC });
|
||||
|
||||
@@ -365,6 +351,20 @@ export function MapLibreMap({
|
||||
mapRef.current = map;
|
||||
onMapReady?.(map);
|
||||
refreshMapSources();
|
||||
|
||||
// Restore terrain if it was saved in preferences
|
||||
if (showTerrainRef.current) {
|
||||
map.addSource('terrain-dem', TERRAIN_DEM_SOURCE);
|
||||
map.addLayer({
|
||||
id: 'hillshade', type: 'hillshade', source: 'terrain-dem', minzoom: 7,
|
||||
paint: { 'hillshade-exaggeration': 0.7, 'hillshade-shadow-color': '#000000', 'hillshade-highlight-color': '#ffffff', 'hillshade-illumination-anchor': 'viewport' },
|
||||
}, 'node-dots');
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
map.addLayer({ id: 'sky', type: 'sky', paint: { 'sky-type': 'atmosphere', 'sky-atmosphere-sun': [0, 90], 'sky-atmosphere-sun-intensity': 15 } } as any);
|
||||
map.setMaxPitch(85);
|
||||
if (map.getZoom() >= 7) map.setTerrain(TERRAIN_CONFIG);
|
||||
map.easeTo({ pitch: 45, duration: 600 });
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
@@ -387,16 +387,27 @@ export function MapLibreMap({
|
||||
}, [showLinks, scheduleRefresh]);
|
||||
|
||||
useEffect(() => {
|
||||
showTerrainRef.current = showTerrain;
|
||||
const map = mapRef.current;
|
||||
if (!map || !mapLoadedRef.current) return;
|
||||
if (showTerrain) {
|
||||
if (!map.getSource('terrain-dem')) map.addSource('terrain-dem', TERRAIN_DEM_SOURCE);
|
||||
if (!map.getLayer('hillshade')) map.addLayer({
|
||||
id: 'hillshade', type: 'hillshade', source: 'terrain-dem', minzoom: 7,
|
||||
paint: { 'hillshade-exaggeration': 0.7, 'hillshade-shadow-color': '#000000', 'hillshade-highlight-color': '#ffffff', 'hillshade-illumination-anchor': 'viewport' },
|
||||
}, 'node-dots');
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if (!map.getLayer('sky')) map.addLayer({ id: 'sky', type: 'sky', paint: { 'sky-type': 'atmosphere', 'sky-atmosphere-sun': [0, 90], 'sky-atmosphere-sun-intensity': 15 } } as any);
|
||||
map.setMaxPitch(85);
|
||||
map.setTerrain(TERRAIN_CONFIG);
|
||||
if (map.getZoom() >= 7) map.setTerrain(TERRAIN_CONFIG);
|
||||
map.easeTo({ pitch: 45, duration: 600 });
|
||||
} else {
|
||||
map.setTerrain(null);
|
||||
if (map.getLayer('hillshade')) map.removeLayer('hillshade');
|
||||
if (map.getLayer('sky')) map.removeLayer('sky');
|
||||
if (map.getSource('terrain-dem')) map.removeSource('terrain-dem');
|
||||
map.easeTo({ pitch: 0, duration: 400 });
|
||||
setTimeout(() => map.setMaxPitch(0), 400);
|
||||
map.setTerrain(null);
|
||||
}
|
||||
}, [showTerrain]);
|
||||
|
||||
|
||||
@@ -14,7 +14,15 @@ export const EMPTY_FC: GeoJSON.FeatureCollection = {
|
||||
features: [],
|
||||
};
|
||||
|
||||
export const TERRAIN_CONFIG = { source: 'terrain-dem', exaggeration: 4 };
|
||||
export const TERRAIN_CONFIG = { source: 'terrain-dem', exaggeration: 3 };
|
||||
|
||||
export const TERRAIN_DEM_SOURCE: maplibregl.RasterDEMSourceSpecification = {
|
||||
type: 'raster-dem',
|
||||
tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'],
|
||||
encoding: 'terrarium',
|
||||
tileSize: 256,
|
||||
maxzoom: 15,
|
||||
};
|
||||
|
||||
export const MAP_STYLE: maplibregl.StyleSpecification = {
|
||||
version: 8,
|
||||
@@ -32,13 +40,6 @@ export const MAP_STYLE: maplibregl.StyleSpecification = {
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> © <a href="https://carto.com/attributions">CARTO</a>',
|
||||
maxzoom: 19,
|
||||
},
|
||||
'terrain-dem': {
|
||||
type: 'raster-dem',
|
||||
tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'],
|
||||
encoding: 'terrarium',
|
||||
tileSize: 256,
|
||||
maxzoom: 15,
|
||||
},
|
||||
},
|
||||
layers: [
|
||||
{ id: 'background', type: 'raster', source: 'carto-dark' },
|
||||
|
||||
Reference in New Issue
Block a user