new setting for selecting terrain source

This commit is contained in:
vcoppe
2026-01-16 19:16:28 +01:00
parent f7c0805161
commit 2eb6ef6f03
5 changed files with 72 additions and 25 deletions

View File

@@ -22,7 +22,7 @@ import {
Binoculars, Binoculars,
Toilet, Toilet,
} from 'lucide-static'; } from 'lucide-static';
import { type StyleSpecification } from 'mapbox-gl'; import { type RasterDEMSourceSpecification, type StyleSpecification } from 'mapbox-gl';
import ignFrTopo from './custom/ign-fr-topo.json'; import ignFrTopo from './custom/ign-fr-topo.json';
import ignFrPlan from './custom/ign-fr-plan.json'; import ignFrPlan from './custom/ign-fr-plan.json';
import ignFrSatellite from './custom/ign-fr-satellite.json'; import ignFrSatellite from './custom/ign-fr-satellite.json';
@@ -1453,3 +1453,18 @@ export const overpassQueryData: Record<string, OverpassQueryData> = {
symbol: 'Anchor', symbol: 'Anchor',
}, },
}; };
export const terrainSources: { [key: string]: RasterDEMSourceSpecification } = {
'mapbox-dem': {
type: 'raster-dem',
url: 'mapbox://mapbox.mapbox-terrain-dem-v1',
tileSize: 512,
maxzoom: 14,
},
mapterhorn: {
type: 'raster-dem',
url: 'https://tiles.mapterhorn.com/tilejson.json',
},
};
export const defaultTerrainSource = 'mapbox-dem';

View File

@@ -13,6 +13,7 @@
overlays, overlays,
overlayTree, overlayTree,
overpassTree, overpassTree,
terrainSources,
} from '$lib/assets/layers'; } from '$lib/assets/layers';
import { getLayers, isSelected, toggle } from '$lib/components/map/layer-control/utils'; import { getLayers, isSelected, toggle } from '$lib/components/map/layer-control/utils';
import { i18n } from '$lib/i18n.svelte'; import { i18n } from '$lib/i18n.svelte';
@@ -31,6 +32,7 @@
currentOverpassQueries, currentOverpassQueries,
customLayers, customLayers,
opacities, opacities,
terrainSource,
} = settings; } = settings;
const { isLayerFromExtension, getLayerName } = extensionAPI; const { isLayerFromExtension, getLayerName } = extensionAPI;
@@ -233,6 +235,23 @@
</ScrollArea> </ScrollArea>
</Accordion.Content> </Accordion.Content>
</Accordion.Item> </Accordion.Item>
<Accordion.Item value="terrain-source">
<Accordion.Trigger>{i18n._('layers.terrain')}</Accordion.Trigger>
<Accordion.Content class="flex flex-col gap-3 overflow-visible">
<Select.Root bind:value={$terrainSource} type="single">
<Select.Trigger class="mr-1 w-full" size="sm">
{i18n._(`layers.label.${$terrainSource}`)}
</Select.Trigger>
<Select.Content class="h-fit max-h-[40dvh] overflow-y-auto">
{#each Object.keys(terrainSources) as id}
<Select.Item value={id}>
{i18n._(`layers.label.${id}`)}
</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</Accordion.Content>
</Accordion.Item>
</Accordion.Root> </Accordion.Root>
</ScrollArea> </ScrollArea>
</Sheet.Header> </Sheet.Header>

View File

@@ -3,8 +3,16 @@ import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
import { get, writable, type Writable } from 'svelte/store'; import { get, writable, type Writable } from 'svelte/store';
import { settings } from '$lib/logic/settings'; import { settings } from '$lib/logic/settings';
import { tick } from 'svelte'; import { tick } from 'svelte';
import { terrainSources } from '$lib/assets/layers';
const { treeFileView, elevationProfile, bottomPanelSize, rightPanelSize, distanceUnits } = settings; const {
treeFileView,
elevationProfile,
bottomPanelSize,
rightPanelSize,
distanceUnits,
terrainSource,
} = settings;
let fitBoundsOptions: mapboxgl.MapOptions['fitBoundsOptions'] = { let fitBoundsOptions: mapboxgl.MapOptions['fitBoundsOptions'] = {
maxZoom: 15, maxZoom: 15,
@@ -123,34 +131,14 @@ export class MapboxGLMap {
}); });
map.addControl(scaleControl); map.addControl(scaleControl);
map.on('style.load', () => { map.on('style.load', () => {
map.addSource('mapbox-dem', {
type: 'raster-dem',
url: 'mapbox://mapbox.mapbox-terrain-dem-v1',
tileSize: 512,
maxzoom: 14,
});
if (map.getPitch() > 0) {
map.setTerrain({
source: 'mapbox-dem',
exaggeration: 1,
});
}
map.setFog({ map.setFog({
color: 'rgb(186, 210, 235)', color: 'rgb(186, 210, 235)',
'high-color': 'rgb(36, 92, 223)', 'high-color': 'rgb(36, 92, 223)',
'horizon-blend': 0.1, 'horizon-blend': 0.1,
'space-color': 'rgb(156, 240, 255)', 'space-color': 'rgb(156, 240, 255)',
}); });
map.on('pitch', () => { map.on('pitch', this.setTerrain.bind(this));
if (map.getPitch() > 0) { this.setTerrain();
map.setTerrain({
source: 'mapbox-dem',
exaggeration: 1,
});
} else {
map.setTerrain(null);
}
});
}); });
map.on('style.import.load', () => { map.on('style.import.load', () => {
const basemap = map.getStyle().imports?.find((imprt) => imprt.id === 'basemap'); const basemap = map.getStyle().imports?.find((imprt) => imprt.id === 'basemap');
@@ -162,6 +150,7 @@ export class MapboxGLMap {
this._map.set(map); // only set the store after the map has loaded this._map.set(map); // only set the store after the map has loaded
window._map = map; // entry point for extensions window._map = map; // entry point for extensions
this.resize(); this.resize();
this.setTerrain();
scaleControl.setUnit(get(distanceUnits)); scaleControl.setUnit(get(distanceUnits));
this._onLoadCallbacks.forEach((callback) => callback(map)); this._onLoadCallbacks.forEach((callback) => callback(map));
@@ -177,6 +166,7 @@ export class MapboxGLMap {
scaleControl.setUnit(units); scaleControl.setUnit(units);
}) })
); );
this._unsubscribes.push(terrainSource.subscribe(() => this.setTerrain()));
} }
onLoad(callback: (map: mapboxgl.Map) => void) { onLoad(callback: (map: mapboxgl.Map) => void) {
@@ -217,6 +207,24 @@ export class MapboxGLMap {
} }
} }
} }
setTerrain() {
const map = get(this._map);
if (map) {
const source = get(terrainSource);
if (!map.getSource(source)) {
map.addSource(source, terrainSources[source]);
}
if (map.getPitch() > 0) {
map.setTerrain({
source: source,
exaggeration: 1,
});
} else {
map.setTerrain(null);
}
}
}
} }
export const map = new MapboxGLMap(); export const map = new MapboxGLMap();

View File

@@ -8,6 +8,7 @@ import {
defaultOverlayTree, defaultOverlayTree,
defaultOverpassQueries, defaultOverpassQueries,
defaultOverpassTree, defaultOverpassTree,
defaultTerrainSource,
type CustomLayer, type CustomLayer,
} from '$lib/assets/layers'; } from '$lib/assets/layers';
import { browser } from '$app/environment'; import { browser } from '$app/environment';
@@ -154,6 +155,7 @@ export const settings = {
customLayers: new Setting<Record<string, CustomLayer>>('customLayers', {}), customLayers: new Setting<Record<string, CustomLayer>>('customLayers', {}),
customBasemapOrder: new Setting<string[]>('customBasemapOrder', []), customBasemapOrder: new Setting<string[]>('customBasemapOrder', []),
customOverlayOrder: new Setting<string[]>('customOverlayOrder', []), customOverlayOrder: new Setting<string[]>('customOverlayOrder', []),
terrainSource: new Setting('terrainSource', defaultTerrainSource),
directionMarkers: new Setting('directionMarkers', false), directionMarkers: new Setting('directionMarkers', false),
distanceMarkers: new Setting('distanceMarkers', false), distanceMarkers: new Setting('distanceMarkers', false),
streetViewSource: new Setting('streetViewSource', 'mapillary'), streetViewSource: new Setting('streetViewSource', 'mapillary'),

View File

@@ -282,6 +282,7 @@
"update": "Update layer" "update": "Update layer"
}, },
"opacity": "Overlay opacity", "opacity": "Overlay opacity",
"terrain": "Terrain source",
"label": { "label": {
"basemaps": "Basemaps", "basemaps": "Basemaps",
"overlays": "Overlays", "overlays": "Overlays",
@@ -379,7 +380,9 @@
"railway-station": "Railway Station", "railway-station": "Railway Station",
"tram-stop": "Tram Stop", "tram-stop": "Tram Stop",
"bus-stop": "Bus Stop", "bus-stop": "Bus Stop",
"ferry": "Ferry" "ferry": "Ferry",
"mapbox-dem": "Mapbox DEM",
"mapterhorn": "Mapterhorn"
} }
}, },
"chart": { "chart": {