How to change base layer using JS and leaflet layers control
Asked Answered
S

5

7

I have to modify existing application, where leaflet layers control is used - I need to display one of the base layers when the map is initiated. Is there a way, how to call some function from the layers control from JS script - something like control.select(1) ....? If not, how can add a tile layer in the same way as it is done by the control - when I add new L.TileLayer during map init, it's not overwritten by manual layers control selection change?

Subscript answered 17/11, 2015 at 14:35 Comment(0)
K
9

You could try to emulate a user click on the Leaflet Layers Control, but there is a much more simple way to achieve what you initially describe.

Normally by simply adding a layer to the map (e.g. myTileLayer.addTo(map)), if that layer is part of the base layers or overlays of the Layers Control, the latter will automatically update its status (if you added a base layer, the radio buttons will be selected accordingly; for an overlay, the corresponding checkbox will be ticked).

Now I am not sure I understood properly your last part ("when I add new L.TileLayer during map init, it's not overwritten by manual layers control selection change").

If you mean you have an unexpected behaviour because the Tile Layer you added is not changed by the Layers Control, it may be due to the fact that you are not re-using a Tile Layer that the Layers Control knows: do not use new L.TileLayer, but re-use one of the base layers or overlays.

For example:

var baselayers = {
    "Tile Layer 1": L.tileLayer(/* ... */),
    "Tile Layer 2": L.tileLayer(/* ... */),
    "Tile Layer 3": L.tileLayer(/* ... */)
};

var overlays = {};

L.control.layers(baselayers, overlays).addTo(map);

baseLayers["Tile Layer 1"].addTo(map);
Kathie answered 17/11, 2015 at 16:28 Comment(1)
Thanks, that's more/less what I have discovered and tried to describe in my answer above - but you wrote it in much better way ;)Subscript
T
4

There are several ways to handle this problem.

1) You can select second baselayer by clicking on the radio input in layer control. This can be done programatically like this (not recommended):

var layerControlElement = document.getElementsByClassName('leaflet-control-layers')[0];
layerControlElement.getElementsByTagName('input')[1].click();

2) Just change the order of baseLayers passed into L.Control.Layers during initialization.

3) Extend L.Control.Layers so that it accepts some new option {"selectedBaseLayerIndex": 1}

Timoshenko answered 17/11, 2015 at 16:35 Comment(2)
Thanks, I tried this "click" approach, but I wasn't able to find appropriate object for the click event. This is nice idea.Subscript
For jquery lovers: $('.leaflet-control-layers input').get(i).click() will do the same as the 1st point of this answer.Ending
W
1

If you are using jQuery you can simulate a click on the Layers control to change the base layer:

$('.leaflet-control-layers-selector')[0].click()

If you want to switch to the second map layer use the next index [1]

Wriest answered 3/5, 2018 at 17:48 Comment(2)
While this probably works, it is a workaround at best. Use the Leaflet API instead.Latterday
for the weirdest reason the "best" answer only worked once per map. tx for providing an alternative even if @StijndeWitt has a good point...Earthlight
T
1

Thank you ghybs. You help me to understand leaflet.

I keep base-map preference in FireBase and get it back on connection to store via Redux.
Now my Map component re-render with tileLayer from Redux.
Before I tried to pass it on props... But with leaflet, like ghybs says, you have to add it again to the map, even if you gave it with something like :

const mapRef = useRef(); //Useful to reach Map leaflet element
layerRef.current = L.control
    .layers(baseMaps, null, { position: "topleft", sortLayers: true})
    .addTo(map);

And after, I hook my tileLayer :

useEffect(() => {
    const { leafletElement: map } = mapRef.current; //Don't forget the current...
    baseMaps[tileLayer].addTo(map);
}, [tileLayer]);
return (
    <Map
        onbaselayerchange={(ev) => handleBaseLayerChange(ev.name)}
        layers={defaultLayer(tileLayer)}
        ref={mapRef}
        {...fieldProps}>
        <CustomersMarkers layer={layerRef} customers={customers} />
    </Map>
);
Toul answered 6/9, 2020 at 21:22 Comment(0)
S
0

I found this after digging in the leaflet code:

1) find the layer you want to display in control's structure _layers 2) call map.addLayer(_layers[your_layer_index].layer) 3) find your layer in control's structure _form 4) set it's checked attribute to true

Subscript answered 17/11, 2015 at 16:23 Comment(1)
While I'm sure it works, in general (and I'm sure also in this case), object properties starting with an underscore (_) are private and it is considered bad practice to access them from outside the component. In other words, when you access _layers and _form, you are bypassing the Leaflet API. Leaflet developers might change the implementation, for example rename those properties. Because they are private this would not be a breaking change af far as the Leaflet devs are concerned but that will break this code. Use the API instead.Latterday

© 2022 - 2024 — McMap. All rights reserved.