Skip to content

Commit 2093414

Browse files
committed
Fix: fill-extrusion null-height Warnungen mit coalesce beheben (v1.1.1)
1 parent 67b6578 commit 2093414

4 files changed

Lines changed: 77 additions & 21 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.0.0/), Ver
55

66
---
77

8+
## [1.1.1] – 2026-04-16
9+
10+
### Gefixt
11+
12+
- **MapLibre-Warnungen "Expected value to be of type number, but found null"**`fill-extrusion`-Layer (3D-Gebäude) verwendeten `['get', 'height']` / `['get', 'min_height']` ohne `null`-Absicherung. OSM-Gebäude ohne Höhendaten liefern `null`, was MapLibres `interpolate`-Expression nicht akzeptiert. Neuer Helper `vmFixExtrusionLayers()` patcht alle `fill-extrusion`-Layer im geladenen Style (inkl. OFM-eigene Layer) mit `['coalesce', ['get', 'height'], 0]` als Fallback. Wird als früher `styledata`-Handler ohne `isStyleLoaded()`-Guard registriert, damit der Fix vor dem ersten Tile-Render greift.
13+
14+
---
15+
816
## [1.1.0] – 2026-03-27
917

1018
### Hinzugefügt

assets/build/vectormaps.js

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)