Similar to the answer from @nothingisnecessary the following uses layer.bringToFront()
to maintain z-order when you have combined layer control
and asynchronous data loading.
we don't want to clear the layers and add them back to the map as this will add all layers, instead we want to respect the selected layers in the Layer Control with minimal overheads. bringToFront()
can do this but we must only call it on a layer group that has layers (content) within it.
Define the layers:
var dataLayers = {
Districts: new L.geoJSON(),
Farms: new L.featureGroup(),
Paddocks: new L.geoJSON(),
Surveys: new L.geoJSON()
};
L.control.layers(
// base maps
{
OSM: L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>', subdomains: ['a', 'b', 'c'] });,
},
dataLayers,
{
collapsed: false,
hideSingleBase: true
}).addTo(map);
Use the following function to enforce the z-order:
/**
* Ensure that layers are displayed in the correct Z-Order
* Instead of explicitly defining z-order on the groups the order of the calls to beingToFront controls the resulting zOrder
* @param {any} dataLayers Object that holds the references to the layer groups toggled by the layer control
**/
function fixZOrder(dataLayers) {
// only similar approach is to remove and re-add back to the map
// use the order in the dataLayers object to define the z-order
Object.keys(dataLayers).forEach(function (key) {
// check if the layer has been added to the map, if it hasn't then do nothing
// we only need to sort the layers that have visible data
// Note: this is similar but faster than trying to use map.hasLayer()
var layerGroup = dataLayers[key];
if (layerGroup._layers
&& Object.keys(layerGroup._layers).length > 0
&& layerGroup._layers[Object.keys(layerGroup._layers)[0]]._path
&& layerGroup._layers[Object.keys(layerGroup._layers)[0]]._path.parentNode)
layerGroup.bringToFront();
});
}
When using the Layer control, when a Layer is toggled into view, it will be on top of the other layers, we need to re-apply the order logic when a layer is added. This can be done by binding to the overlayadd
event on the map and calling the fixZOrder
function:
map.on('overlayadd', function (e) {
fixZOrder(dataLayers);
}
If you load your data asynchronously, you may also need to call fixZOrder
when your data load has completed, new layers added at runtime will be rendered on top of all other layers.