7
votes

Succinctly, I need groups of layers to be controlled by the leaflet layer control, two to three at a time. In this JSFiddle, when changing basemaps, the hydro overlay needs to persistently stay on top of the various basemaps.

If you run and use the layer control in the top right, you will notice how the hydro overlay will turn off when you switch to imagery and will stay off unless you switch to topographic and back to national geographic. This is the behavior I have been able to reliably reproduce. If you play with it, you can see some pretty weird stuff is going on.

Any input or suggestions for better ways to accomplish this are welcome. The solution does need to use the layer control to switch the basemap while keeping the hydro overlay on top. Otherwise, I am completely open to alternative solutions.

If you are curious before jumping over to the JSFiddle, here is the JavaScript...

// initialize map
var map = L.map('map', {
    center: [45.7067, -121.5217], // Hood River, OR
    zoom: 7
});

// hydrology overlay layer
var hydro = L.esri.tiledMapLayer('http://hydrology.esri.com/arcgis/rest/services/WorldHydroReferenceOverlay/MapServer');

// basemap layer groups so the hydro overlay always overlays the various basemaps
var nationalGeographic = L.layerGroup([
        hydro,
        L.esri.basemapLayer('NationalGeographic')
    ]),
    esriTopo = L.layerGroup([
        hydro,
        L.esri.basemapLayer('Topographic')
    ]),
    esriShadedRelief = L.layerGroup([
        L.esri.tiledMapLayer('ShadedReliefLabels'),
        hydro,
        L.esri.basemapLayer('ShadedRelief')
    ]),
    esriImagery = L.layerGroup([
        hydro,
        L.esri.basemapLayer('Imagery')
    ]);

// add default layers to map
map.addLayer(esriTopo);

// json object for layer switcher control basemaps
var baseLayers = {
    "National Geographic": nationalGeographic,
    "Esri Topographic": esriTopo,
    "Shaded Relief": esriShadedRelief,
    "Imagery": esriImagery
};

// add layer groups to layer switcher control
var controlLayers = L.control.layers(baseLayers).addTo(map);
2

2 Answers

6
votes

The solution turns out to be explicitly setting the z index of the hydro layer. Searching for the z index unearthed this discussion on StackOverflow with a reference to an excellent example by Bobby Sudekum. Although I did not implement Bobby's solution directly, it did lead me to deeper investigation of the properties and methods for Leaflet TileLayer in the API.

Specifically, the zIndex option turned out to be the solution. It is worth noting the zIndex is set to five for this to work. The Layer Control automatically sets the z-index of the layers it is controlling. Hence, the original problem was the hydro layer had no index, but the layers interacted with in the layer control did. As a result, the hydro layer fell to the back as soon as the Layer Control was interacted with and disappeared. Hence, with four basemap layers, the hydro layer must have a z index of five, one more than the count of basemap layers, to show up on top of any basemap layer chosen. Finally, I also implemented the detectRetina option, dramatically improving display on my MacBook Pro.

Here is the updated code accompanying an updated JSFiddle http://jsfiddle.net/FH9VF/11/.

// initialize map
var map = L.map('map', {
    center: [45.7067, -121.5217], // Hood River, OR
    zoom: 7
});

// hydrology overlay layer
var hydro = L.esri.tiledMapLayer('http://hydrology.esri.com/arcgis/rest/services/WorldHydroReferenceOverlay/MapServer', {
    zIndex: 5,
    detectRetina: true
});

// basemap layer groups so the hydro overlay always overlays the various basemaps
var nationalGeographic = L.esri.basemapLayer('NationalGeographic'),
    esriTopo = L.esri.basemapLayer('Topographic'),
    esriShadedRelief = L.esri.basemapLayer('ShadedRelief'),
    esriImagery = L.esri.basemapLayer('Imagery');

// add default layers to map
map.addLayer(esriTopo);
map.addLayer(hydro);

// json object for layer switcher control basemaps
var baseLayers = {
    "National Geographic": nationalGeographic,
    "Esri Topographic": esriTopo,
    "Shaded Relief": esriShadedRelief,
    "Imagery": esriImagery
};

// add layer groups to layer switcher control
var controlLayers = L.control.layers(baseLayers).addTo(map);
3
votes

You need to do something like this:

//define base layers
var osmUrl='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
var normalView = L.tileLayer(osmUrl, {styleId: 997, attribution: osmAttributes, maxZoom: 18 });
...

//define overlay layers
var markersLayer = new L.layerGroup();
var linesLayer = new L.layerGroup();
...

//create MAP with default base and overlay layers
var map = L.map('map', {
layers: [normalView, markersLayer]
}).setView([45.2516700, 19.8369400], 12);

//add layers to the base and overlay
var baseMaps = {
    "Normal view": normalView,
    "Night view": nightView,
    "MapQuest layer": mapQuest
};

var overlayMaps = {
    "Markers": markersLayer,
    "Lines": linesLayer,
    "3D layer": osmbView
};

//add layer control to the map
L.control.layers(baseMaps, overlayMaps).addTo(map);