@@ -411,8 +411,8 @@ class VectorMapPicker {
411411 'minzoom' : 15 ,
412412 'paint' : {
413413 'fill-extrusion-color' : '#aaa' ,
414- 'fill-extrusion-height' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'get' , 'height' ] ] ,
415- 'fill-extrusion-base' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'get' , 'min_height' ] ] ,
414+ 'fill-extrusion-height' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'coalesce' , [ ' get', 'height' ] , 0 ] ] ,
415+ 'fill-extrusion-base' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'coalesce' , [ ' get', 'min_height' ] , 0 ] ] ,
416416 'fill-extrusion-opacity' : 0.6
417417 }
418418 } ) ;
@@ -454,8 +454,8 @@ class VectorMapPicker {
454454 'minzoom' : 15 ,
455455 'paint' : {
456456 'fill-extrusion-color' : '#aaa' ,
457- 'fill-extrusion-height' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'get' , 'height' ] ] ,
458- 'fill-extrusion-base' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'get' , 'min_height' ] ] ,
457+ 'fill-extrusion-height' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'coalesce' , [ ' get', 'height' ] , 0 ] ] ,
458+ 'fill-extrusion-base' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'coalesce' , [ ' get', 'min_height' ] , 0 ] ] ,
459459 'fill-extrusion-opacity' : .6
460460 }
461461 } ) ;
@@ -464,6 +464,7 @@ class VectorMapPicker {
464464 map . on ( 'load' , ( ) => {
465465 new maplibregl . Marker ( { color : "#ff0000" } ) . setLngLat ( [ 10.4515 , 51.1656 ] ) . addTo ( map ) ;
466466 add3dBuildings ( ) ;
467+ vmFixExtrusionLayers ( map ) ;
467468 // Demo-Karte auf aktuelle Sprache setzen
468469 vmSetLanguage ( map , _demoCurrentLang ) ;
469470 // Flug nach Mainhattan (Frankfurt Bankenviertel)
@@ -482,6 +483,9 @@ class VectorMapPicker {
482483 // Nach Stil-Wechsel werden sie stattdessen via map.once('idle', ...) aufgerufen.
483484 // Auf Satellitenbild gibt es keinen Vektor-Layer → kein 3D möglich.
484485 const _isSatellite = ( ) => map . isStyleLoaded ( ) && ! ! map . getSource ( 'satellite' ) ;
486+ // Früh patchen: sobald Style-Layer verfügbar — OHNE isStyleLoaded()-Guard
487+ // verhindert Warnungen beim ersten Tile-Render (bevor load-Event feuert)
488+ map . on ( 'styledata' , ( ) => { if ( ! _isSatellite ( ) ) vmFixExtrusionLayers ( map ) ; } ) ;
485489 map . on ( 'styledata' , ( ) => {
486490 if ( ! map . isStyleLoaded ( ) ) return ;
487491 if ( ! _isSatellite ( ) ) add3dBuildings ( ) ;
@@ -742,6 +746,47 @@ function vmTransformRequest(url) {
742746 return { url } ;
743747}
744748
749+ /**
750+ * Ersetzt ['get', prop] (auch tief in Expressions) durch ['coalesce', ['get', prop], 0].
751+ * Verhindert MapLibre-Warnungen "Expected value to be of type number, but found null"
752+ * when OSM buildings lack height/min_height attributes.
753+ * @param {* } expr
754+ * @param {string } prop
755+ * @returns {* }
756+ */
757+ function vmWrapGetWithCoalesce ( expr , prop ) {
758+ if ( ! Array . isArray ( expr ) ) return expr ;
759+ if ( expr [ 0 ] === 'get' && expr [ 1 ] === prop ) return [ 'coalesce' , expr , 0 ] ;
760+ return expr . map ( e => vmWrapGetWithCoalesce ( e , prop ) ) ;
761+ }
762+
763+ /**
764+ * Patcht alle fill-extrusion-Layer im geladenen Style (inkl. OFM-eigene)
765+ * so dass fehlende height/min_height-Werte mit 0 ersetzt werden.
766+ * @param {maplibregl.Map } map
767+ */
768+ function vmFixExtrusionLayers ( map ) {
769+ const layers = map . getStyle ( ) ?. layers ;
770+ if ( ! layers ) return ;
771+ for ( const layer of layers ) {
772+ if ( layer . type !== 'fill-extrusion' ) continue ;
773+ try {
774+ const h = map . getPaintProperty ( layer . id , 'fill-extrusion-height' ) ;
775+ const b = map . getPaintProperty ( layer . id , 'fill-extrusion-base' ) ;
776+ if ( h !== undefined && h !== null ) {
777+ const patched = vmWrapGetWithCoalesce ( h , 'height' ) ;
778+ if ( JSON . stringify ( patched ) !== JSON . stringify ( h ) )
779+ map . setPaintProperty ( layer . id , 'fill-extrusion-height' , patched ) ;
780+ }
781+ if ( b !== undefined && b !== null ) {
782+ const patched = vmWrapGetWithCoalesce ( b , 'min_height' ) ;
783+ if ( JSON . stringify ( patched ) !== JSON . stringify ( b ) )
784+ map . setPaintProperty ( layer . id , 'fill-extrusion-base' , patched ) ;
785+ }
786+ } catch ( _ ) { }
787+ }
788+ }
789+
745790/**
746791 * Wendet ein Theme-Farbobjekt auf eine geladene MapLibre-Karte an.
747792 * Iteriert alle Layer und überschreibt Farb-Properties nach Source-Layer und Typ.
@@ -1108,7 +1153,7 @@ function vmBuildMap(el) {
11081153 const nearbyLocate = el . hasAttribute ( 'nearby-locate' ) ;
11091154
11101155 map . on ( 'load' , ( ) => {
1111- if ( ! isRaster ) vmSetLanguage ( map , lang ) ;
1156+ if ( ! isRaster ) { vmSetLanguage ( map , lang ) ; vmFixExtrusionLayers ( map ) ; }
11121157 if ( has3d && ! isRaster ) vmAdd3dBuildings ( map ) ;
11131158 vmAddMarkers ( el , map ) ;
11141159 vmLoadGeoJson ( el , map ) ;
@@ -1123,7 +1168,7 @@ function vmBuildMap(el) {
11231168 } else {
11241169 map . on ( 'load' , ( ) => {
11251170 // Sprache setzen (nur bei Vektor-Stilen)
1126- if ( ! isRaster ) vmSetLanguage ( map , lang ) ;
1171+ if ( ! isRaster ) { vmSetLanguage ( map , lang ) ; vmFixExtrusionLayers ( map ) ; }
11271172 if ( has3d && ! isRaster ) vmAdd3dBuildings ( map ) ;
11281173 vmAddMarkers ( el , map ) ;
11291174 vmLoadGeoJson ( el , map ) ;
@@ -1168,6 +1213,9 @@ function vmBuildMap(el) {
11681213 } ) ;
11691214 }
11701215
1216+ // Früh patchen: sobald Style-Layer verfügbar — OHNE isStyleLoaded()-Guard
1217+ if ( ! isRaster ) map . on ( 'styledata' , ( ) => vmFixExtrusionLayers ( map ) ) ;
1218+
11711219 // styledata: 3D-Gebäude + Theme-Wiederherstellung (z.B. nach Satellit-Toggle)
11721220 // Debounce-Flag verhindert Endlosschleife: setPaintProperty feuert selbst styledata
11731221 map . on ( 'styledata' , ( ) => {
@@ -1202,8 +1250,8 @@ function vmAdd3dBuildings(map) {
12021250 minzoom : 15 ,
12031251 paint : {
12041252 'fill-extrusion-color' : '#aaa' ,
1205- 'fill-extrusion-height' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'get' , 'height' ] ] ,
1206- 'fill-extrusion-base' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'get' , 'min_height' ] ] ,
1253+ 'fill-extrusion-height' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'coalesce' , [ ' get', 'height' ] , 0 ] ] ,
1254+ 'fill-extrusion-base' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 15 , 0 , 15.05 , [ 'coalesce' , [ ' get', 'min_height' ] , 0 ] ] ,
12071255 'fill-extrusion-opacity' : 0.6 ,
12081256 } ,
12091257 } ) ;
@@ -2324,8 +2372,8 @@ function vmStartBerlinOverfly(map) {
23242372 minzoom : 14 ,
23252373 paint : {
23262374 'fill-extrusion-color' : '#a8b4c0' ,
2327- 'fill-extrusion-height' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 14 , 0 , 14.5 , [ 'get' , 'height' ] ] ,
2328- 'fill-extrusion-base' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 14 , 0 , 14.5 , [ 'get' , 'min_height' ] ] ,
2375+ 'fill-extrusion-height' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 14 , 0 , 14.5 , [ 'coalesce' , [ ' get', 'height' ] , 0 ] ] ,
2376+ 'fill-extrusion-base' : [ 'interpolate' , [ 'linear' ] , [ 'zoom' ] , 14 , 0 , 14.5 , [ 'coalesce' , [ ' get', 'min_height' ] , 0 ] ] ,
23292377 'fill-extrusion-opacity' : 0.8 ,
23302378 } ,
23312379 } ) ;
0 commit comments