Skip to content

Commit bb9e235

Browse files
committed
Hillside shading fix
1 parent ca011f8 commit bb9e235

1 file changed

Lines changed: 44 additions & 10 deletions

File tree

js/map.js

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -472,15 +472,15 @@ async function initMap() {
472472
resetViewEl.id = 'reset-view-btn';
473473
resetViewEl.title = 'Reset to top-down view';
474474
resetViewEl.textContent = '⊙';
475-
resetViewEl.style.cssText = 'background:rgba(0,0,0,.6);color:#fff;font-size:14px;border:none;border-radius:4px;cursor:pointer;padding:2px 8px;font-family:monospace;display:none;line-height:1';
475+
resetViewEl.style.cssText = 'background:rgba(0,0,0,.6);color:#fff;font-size:11px;border:none;border-radius:4px;cursor:pointer;padding:3px 6px;font-family:monospace;display:none;box-sizing:border-box;height:19px';
476476
resetViewEl.addEventListener('click', () => { map.easeTo({ bearing: 0, duration: 500 }); });
477477
pitchWrap.appendChild(pitchEl);
478478
pitchWrap.appendChild(resetViewEl);
479479
document.getElementById('map').appendChild(pitchWrap);
480480
const exaggerationEl = document.createElement('div');
481481
exaggerationEl.id = 'exaggeration-ctrl';
482482
exaggerationEl.style.cssText = 'position:absolute;bottom:24px;left:310px;background:rgba(0,0,0,.6);color:#fff;font-size:11px;padding:2px 8px;border-radius:4px;z-index:10;font-family:monospace;display:none;align-items:center;gap:6px';
483-
exaggerationEl.innerHTML = '⛰ <input type="range" id="exaggeration-slider" min="1" max="3" step="0.1" value="1.5" style="width:70px;accent-color:#fff;vertical-align:middle"> <span id="exaggeration-val">1.5×</span>';
483+
exaggerationEl.innerHTML = '⛰ <input type="range" id="exaggeration-slider" min="1" max="3" step="0.1" value="1.2" style="width:70px;accent-color:#fff;vertical-align:middle"> <span id="exaggeration-val">1.2×</span>';
484484
document.getElementById('map').appendChild(exaggerationEl);
485485
document.getElementById('exaggeration-slider').addEventListener('input', (e) => {
486486
const val = parseFloat(e.target.value);
@@ -614,9 +614,13 @@ async function initMap() {
614614
// Elevation — only in 3D Terrain mode
615615
let elevationStr = '';
616616
if (_mapStyle === 'terrain3d') {
617-
const elev = map.queryTerrainElevation([lng, lat]);
618-
if (elev !== null && elev !== undefined) {
619-
elevationStr = `${Math.round(elev).toLocaleString()}m`;
617+
try {
618+
const elev = map.queryTerrainElevation([lng, lat]);
619+
if (elev !== null && elev !== undefined) {
620+
elevationStr = `${Math.round(elev).toLocaleString()}m`;
621+
}
622+
} catch(e) {
623+
// Elevation error when zoom exceeds source maxzoom — ignore
620624
}
621625
}
622626

@@ -760,6 +764,15 @@ function _applyTerrainAndProjection() {
760764

761765
// Set projection FIRST — before any camera moves — so easeTo never runs under the wrong projection
762766
if (map.setProjection) {
767+
// Add atmospheric fog for depth perception in 3D modes
768+
if (map.setFog) {
769+
map.setFog({
770+
color: 'white',
771+
'high-color': '#add8e6',
772+
'horizon-blend': 0.3,
773+
atmosphere: 0.5
774+
});
775+
}
763776
map.setProjection({ type: isGlobe ? 'globe' : 'mercator' });
764777
}
765778

@@ -769,12 +782,17 @@ function _applyTerrainAndProjection() {
769782
map.addSource('terrain-dem', {
770783
type: 'raster-dem',
771784
tiles: ['https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png'],
772-
tileSize: 512, maxzoom: 15, encoding: 'terrarium'
785+
tileSize: 512, maxzoom: 17, encoding: 'terrarium'
773786
});
774787
}
775788
const sliderEl = document.getElementById('exaggeration-slider');
776-
const exaggeration = sliderEl ? parseFloat(sliderEl.value) : 1.5;
789+
const exaggeration = sliderEl ? parseFloat(sliderEl.value) : 1.2;
777790
map.setTerrain({ source: 'terrain-dem', exaggeration });
791+
map.setPaintProperty('terrain-dem', 'raster-blur', 3);
792+
// Add sky layer for atmospheric background in 3D
793+
if (map.getLayer('sky') === undefined) {
794+
map.addLayer({ id: 'sky', type: 'sky', paint: { 'sky-type': 'gradient', 'sky-gradient': ['interpolate', ['linear'], ['sky-radial-progress'], 0, 'rgba(255,255,255,0)', 0.5, '#87cefa', 1, '#4682b4'] } });
795+
}
778796
if (!map.getLayer('terrain-hillshade')) {
779797
// Insert below the first road/label layer so hillshading shows through
780798
const firstSymbol = map.getStyle().layers.find(l => l.type === 'line' || l.type === 'symbol');
@@ -783,14 +801,30 @@ function _applyTerrainAndProjection() {
783801
type: 'hillshade',
784802
source: 'terrain-dem',
785803
paint: {
786-
'hillshade-exaggeration': 0.75,
787-
'hillshade-illumination-direction': 315,
788-
'hillshade-illumination-anchor': 'map',
804+
'hillshade-exaggeration': 1.0,
805+
'hillshade-illumination-direction': 270,
806+
'hillshade-illumination-anchor': 'viewport',
789807
'hillshade-shadow-color': '#1a2a35',
790808
'hillshade-highlight-color': '#f0f4f8',
791809
'hillshade-accent-color': '#2d4a5a',
792810
}
793811
}, firstSymbol?.id);
812+
// Add 3D building extrusion if OpenMapTiles source is present
813+
if (map.getSource('openmaptiles') && !map.getLayer('3d-buildings')) {
814+
map.addLayer({
815+
id: '3d-buildings',
816+
source: 'openmaptiles',
817+
'source-layer': 'building',
818+
type: 'fill-extrusion',
819+
minzoom: 15,
820+
paint: {
821+
'fill-extrusion-color': '#ddd',
822+
'fill-extrusion-height': ['get', 'height'],
823+
'fill-extrusion-base': ['get', 'min_height'],
824+
'fill-extrusion-opacity': 0.6
825+
}
826+
}, 'terrain-hillshade');
827+
}
794828
}
795829
map.easeTo({ pitch: 50, bearing: 0, duration: 800 });
796830
} else {

0 commit comments

Comments
 (0)