Search code examples
javascriptleafletlayerz-order

Changing z-order of layer in Leaflet


I created an example of layers using as base this code:

http://bl.ocks.org/ragnarheidar/a711faa1a94be4dae48f

The piece of code responsible to creating the layers is the following:

function getColor(d) 
{
    return marker_colors[d];
}   

function marker_style(i) 
{
    return {
        fillColor: getColor(i),
        radius: 5,
        weight: 1,
        opacity: 1,
        color: 'white',
        dashArray: '3',
        fillOpacity: 0.7
    };
}

//data URL variables
var start_date = '2013-08-01'; //YYYY-MM-DD
var end_date = '2013-08-08';   //YYYY-MM-DD
var c_type = 'Noise';          // Complaint Type

// Build the data URL
var URL = "http://data.cityofnewyork.us/resource/erm2-nwe9.json"; 
URL += "?";                                                   
URL += "$where=";                                             
URL += "(latitude IS NOT NULL)";                              
URL += " AND ";
URL += "(complaint_type='" + c_type + "')";                    
URL += " AND ";
URL += "(created_date>='" + start_date + "') AND (created_date<='" + end_date + "')"; 
URL += "&$group=complaint_type,descriptor,latitude,longitude";                        
URL += "&$select=descriptor,latitude,longitude,complaint_type";                       
URL = encodeURI(URL);                                                                 
console.log(URL);                                                                       

var noise_description = ["Air Condition/Ventilation Equipment", 
                        "Alarms",
                        "Banging/Pounding", 
                        "Barking Dog", 
                        "Car/Truck Horn", 
                        "Car/Truck Music", 
                        "Construction Equipment", 
                        "Construction Before/After Hours", 
                        "Engine Idling", 
                        "Ice Cream Truck", 
                        "Jack Hammering", 
                        "Lawn Care Equipment",
                        "Loud Music/Party",
                        "Loud Talking",
                        "Loud Television",
                        "Manufacturing Noise",
                        "Private Carting Noise",
                        "Others"];

var marker_colors = ['#7f3b08',
                    '#a50026',
                    '#d73027',
                    '#f46d43',
                    '#fdae61',
                    '#fee090',
                    '#ffffbf',
                    '#ffffff',
                    '#e0f3f8',
                    '#abd9e9',
                    '#74add1',
                    '#4575b4',
                    '#313695',
                    '#d8daeb',
                    '#b2abd2',
                    '#8073ac',
                    '#542788',
                    '#2d004b'];

//  Load GeoJSON from an external file
$.getJSON(URL, function(data)
{
        var markers = []
        var layers = []
        for (var i = 0; i < noise_description.length; i++) 
        {
            markers[i] = [];
        }

        var all_markers = [];

        $.each(data, function(index, rec)
        {
            var marker;
            for (var i = 0; i < noise_description.length; i++) 
            {
                if (rec.descriptor.indexOf(noise_description[i]) > -1) 
                {
                    marker = L.circleMarker([rec.latitude, rec.longitude], marker_style(i));
                    markers[i].push(marker); 
                    all_markers.push(marker); 
                    break;
                }
            }

        });

        // Create layer of all markers but do not add to map
        var all_layers = L.featureGroup(all_markers);       
        // Create specific layers of markers and add to map
        for (var i = 0; i < markers.length; i++) 
        {
            layers[i] = L.featureGroup(markers[i]).addTo(map);;
        }
        map.fitBounds(all_layers.getBounds());

        // Create object containing all marker layers 
        var overlays = {}; 
        for (var i = 0; i < noise_description.length; i++) 
        {
            overlays[noise_description[i]] = layers[i];
        }

        //add layer control using above object
        L.control.layers(null,overlays).addTo(map);
    });

That's the last part of my code, but it's being showed behind another layer (this behavior changes with some refreshment of the page):

enter image description here

I'm wondering how to control this.


Solution

  • All vectors in Leaflet 0.x (I guess you are using Leaflet v0.7.7 from your previous question) are added to a single SVG container in the overlayPane.

    This includes your first areas (I think you did not include that code in the current question?) as well as your Circle Markers.

    Their stack order depend on their insertion order. So because you load them asynchronously, depending on the time it takes for the server to send the data, your Circle Markers may be below or above your areas.

    You could either chain your 2 asynchronous requests to predefine in which order they execute. You would simply start the next query once the first one has completed. But you would delay the data display.

    Or you could force some vectors to be brought on top / bottom using bringToFront / bringToBack methods. You would have to loop through your feature group and apply it on each individual layer, like:

    all_layers.eachLayer(function (layer) {
        layer.bringToFront();
    });
    

    The situation is different in Leaflet 1.0, where you can create your own panes and specify their z-index (possibly through CSS). Then you can insert your layers (including vectors) in any desired pane.