@@ -14,6 +14,7 @@ import {
1414 validateMapExpression ,
1515} from "@geolibre/core" ;
1616import { addProtocol , config } from "maplibre-gl" ;
17+ import type { GeoJSON } from "geojson" ;
1718import type maplibregl from "maplibre-gl" ;
1819import type { PropertyValueSpecification } from "maplibre-gl" ;
1920import { FileSource , PMTiles , Protocol } from "pmtiles" ;
@@ -328,6 +329,18 @@ function applyExternalNativeFeatureFilters(
328329// range we keep applying the style range on every sync, including a later reset
329330// back to the full [0, 24] window.
330331const managedZoomRangeLayerIds = new Set < string > ( ) ;
332+ const geoJsonSourceData = new WeakMap < maplibregl . GeoJSONSource , GeoJSON > ( ) ;
333+
334+ function rememberGeoJsonData ( map : maplibregl . Map , sourceId : string , data : GeoJSON ) : void {
335+ const source = map . getSource ( sourceId ) ;
336+ if ( source ?. type === "geojson" ) geoJsonSourceData . set ( source as maplibregl . GeoJSONSource , data ) ;
337+ }
338+
339+ function setGeoJsonData ( source : maplibregl . GeoJSONSource , data : GeoJSON ) : void {
340+ if ( geoJsonSourceData . get ( source ) === data ) return ;
341+ source . setData ( data ) ;
342+ geoJsonSourceData . set ( source , data ) ;
343+ }
331344
332345function clampLayerZoom ( value : number , fallback : number ) : number {
333346 if ( ! Number . isFinite ( value ) ) return fallback ;
@@ -598,8 +611,9 @@ function ensureExternalGeoJsonNativeLayer(
598611 type : "geojson" ,
599612 data : layer . geojson ,
600613 } ) ;
614+ rememberGeoJsonData ( map , nativeSourceId , layer . geojson ) ;
601615 } else {
602- ( map . getSource ( nativeSourceId ) as maplibregl . GeoJSONSource ) . setData ( layer . geojson ) ;
616+ setGeoJsonData ( map . getSource ( nativeSourceId ) as maplibregl . GeoJSONSource , layer . geojson ) ;
603617 }
604618
605619 if ( nativeLayerIds . every ( ( id ) => map . getLayer ( id ) ) ) return ;
@@ -1438,6 +1452,10 @@ function setNativeLayerVisibility(
14381452 visibility : "visible" | "none" ,
14391453) : void {
14401454 try {
1455+ const canRead = typeof map . getLayoutProperty === "function" ;
1456+ const current = canRead ? map . getLayoutProperty ( nativeLayerId , "visibility" ) : undefined ;
1457+ if ( current === visibility || ( canRead && current === undefined && visibility === "visible" ) )
1458+ return ;
14411459 map . setLayoutProperty ( nativeLayerId , "visibility" , visibility ) ;
14421460 } catch {
14431461 // Custom layers from external controls may not accept layout updates.
@@ -1666,7 +1684,9 @@ function syncVectorControlPointSymbology(
16661684 // of the other rule-based paint overrides apply to control-owned layers.
16671685 const radius = proportionalRadiusExpression ( layer . style ) ;
16681686 if ( radius ) {
1669- map . setPaintProperty ( circleNativeId , "circle-radius" , radius ) ;
1687+ if ( ! styleValuesEqual ( map . getPaintProperty ?.( circleNativeId , "circle-radius" ) , radius ) ) {
1688+ map . setPaintProperty ( circleNativeId , "circle-radius" , radius ) ;
1689+ }
16701690 overriddenRadiusIdsFor ( map ) . add ( circleNativeId ) ;
16711691 } else {
16721692 restoreOverriddenCircleRadius ( map , circleNativeId , layer ) ;
@@ -1721,7 +1741,9 @@ function setExternalNativeLayerPaint(
17211741
17221742 for ( const [ property , value ] of Object . entries ( paint ) ) {
17231743 try {
1724- map . setPaintProperty ( nativeLayerId , property , value ) ;
1744+ if ( ! styleValuesEqual ( map . getPaintProperty ?.( nativeLayerId , property ) , value ) ) {
1745+ map . setPaintProperty ( nativeLayerId , property , value ) ;
1746+ }
17251747 } catch {
17261748 // External controls can create heterogeneous style layers. Ignore paint
17271749 // properties that do not apply to a specific native layer type.
@@ -1807,8 +1829,9 @@ function syncGeoJsonLayer(map: maplibregl.Map, layer: GeoLibreLayer, beforeId?:
18071829 ...( attribution ? { attribution } : { } ) ,
18081830 } ,
18091831 ) ;
1832+ rememberGeoJsonData ( map , src , layer . geojson ! ) ;
18101833 } else {
1811- ( map . getSource ( src ) as maplibregl . GeoJSONSource ) . setData ( layer . geojson ! ) ;
1834+ setGeoJsonData ( map . getSource ( src ) as maplibregl . GeoJSONSource , layer . geojson ! ) ;
18121835 }
18131836
18141837 applyVectorDataRenderLayers ( map , layer , src , profile , renderer , beforeId ) ;
@@ -3403,12 +3426,16 @@ function ensureLayer(
34033426 if ( map . getLayer ( id ) ) {
34043427 if ( spec . paint ) {
34053428 for ( const [ key , value ] of Object . entries ( spec . paint ) ) {
3406- map . setPaintProperty ( id , key , value ) ;
3429+ if ( ! styleValuesEqual ( map . getPaintProperty ?.( id , key ) , value ) ) {
3430+ map . setPaintProperty ( id , key , value ) ;
3431+ }
34073432 }
34083433 }
34093434 if ( spec . layout ) {
34103435 for ( const [ key , value ] of Object . entries ( spec . layout ) ) {
3411- map . setLayoutProperty ( id , key , value ) ;
3436+ if ( ! styleValuesEqual ( map . getLayoutProperty ?.( id , key ) , value ) ) {
3437+ map . setLayoutProperty ( id , key , value ) ;
3438+ }
34123439 }
34133440 }
34143441 if ( "filter" in spec ) {
@@ -3462,6 +3489,10 @@ function ensureLayer(
34623489 map . addLayer ( addSpec , validBeforeId ) ;
34633490}
34643491
3492+ export function styleValuesEqual ( current : unknown , next : unknown ) : boolean {
3493+ return Object . is ( current , next ) || JSON . stringify ( current ) === JSON . stringify ( next ) ;
3494+ }
3495+
34653496function setLayerZoomRange (
34663497 map : maplibregl . Map ,
34673498 id : string ,
0 commit comments