9

I would like to be able to change the order of the layers in leaflet.

I tried implementing two leaflet plugins in order to change the layer order.

First I tried leaflet-control-orderlayers, which seems to work, but does not support layerGroups, here is my filed bug.

Next I tried mapbbcode, which does support layerGroups, but does not seem to work or be maintained.

Does anyone have any suggestions for how to implement this feature?

8

You can do this in a couple ways (at least; this is how I do it):

  1. layer.bringToFront() and layer.bringToBack() but these will only do one layer at a time, and only pushes it to front or back, not in between. So you would need to put your layers in the desired order, start with the layer you want to be on bottom, and call layer.bringToFront() on each layer.

  2. You can also do this by removing and re-adding the layer. This seems sorta wasteful, but since the map must redraw when repositioning layers anyway, it is generally not that big of a deal.

Here is a fairly complex fiddle that illustrates the issue

Basically you remove all layers and then re-add them in ascending z-index order. So loop through all your overlay layers, and call map.removeLayer(layer), then sort them by your desired z-index, then re-add them using layer.addTo(map).

0

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: '&copy; <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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.