fix: show 3d buildings only when the map is tilted

This commit is contained in:
Jovan Krunić
2026-10-08 17:17:26 +02:00
parent 812897c4d1
commit 77da21a41c
@@ -1,6 +1,13 @@
import {Directive, HostListener} from '@angular/core'; import {Directive, HostListener} from '@angular/core';
import {Map, MapMouseEvent, MapStyleDataEvent} from 'maplibre-gl'; import {Map, MapMouseEvent, MapStyleDataEvent} from 'maplibre-gl';
/** Layer ids in the map style */
const BUILDING_LAYER = 'building';
const BUILDING_3D_LAYER = 'building-3d';
/**
* Switches between flat and 3D buildings depending on whether the map is tilted
*/
@Directive({ @Directive({
selector: 'mgl-map[auto-3d]', selector: 'mgl-map[auto-3d]',
standalone: true, standalone: true,
@@ -16,21 +23,37 @@ export class MapAuto3dDirective {
this.updatePitch(event.target); this.updatePitch(event.target);
} }
/**
* Shows the 3D buildings only while the map is tilted; flat buildings otherwise
*/
updatePitch(map: Map) { updatePitch(map: Map) {
if (map.getPitch() === 0) { if (!map.getLayer(BUILDING_3D_LAYER)) return;
const layer = map.getLayer('building-3d');
if (layer && layer?.visibility !== 'none') { const flat = map.getPitch() === 0;
layer.visibility = 'none';
map.setPaintProperty('building', 'fill-opacity', 1); const visibility = flat ? 'none' : 'visible';
map.setLayerZoomRange('building', 13, 24); // Nothing to do if the 3D layer is already in the target state. This check matters
} // because `pitch` fires on every frame while tilting. `getLayoutProperty` returns
// undefined when the style doesn't set `visibility`; MapLibre then treats the layer as visible.
if ((map.getLayoutProperty(BUILDING_3D_LAYER, 'visibility') ?? 'visible') === visibility) return;
map.setLayoutProperty(BUILDING_3D_LAYER, 'visibility', visibility);
if (!map.getLayer(BUILDING_LAYER)) return;
if (flat) {
map.setPaintProperty(BUILDING_LAYER, 'fill-opacity', 1);
map.setLayerZoomRange(BUILDING_LAYER, 13, 24);
} else { } else {
const layer = map.getLayer('building-3d'); // when tilted, fade the flat buildings out where the 3D ones take over
if (layer && layer?.visibility !== 'visible') { map.setPaintProperty(BUILDING_LAYER, 'fill-opacity', [
layer.visibility = 'visible'; 'interpolate',
map.setPaintProperty('building', 'fill-opacity', ['interpolate', ['linear'], ['zoom'], 15, 1, 16, 0]); ['linear'],
map.setLayerZoomRange('building', 13, 16); ['zoom'],
} 15,
1,
16,
0,
]);
map.setLayerZoomRange(BUILDING_LAYER, 13, 16);
} }
} }
} }