nevrome nevrome - 3 months ago 16
CoffeeScript Question

Leaflet layer ordering after zooming

I have problems to understand how layer ordering in leaflet works and I'm completly new to Javascript/Coffeescript.

The code I'm working on is part of a Ruby&Rails app and can be found here. The idea is to


  • setup a osm basemap

  • add a heatmap of points

  • let the user select a rectangular area as a selection tool for further stuff to happen inside the Rails app

  • react to user zooming by changing the heatmap to a marker-cluster setup



The problem: Zooming causes the layers to be redrawn. So the user selection rectangle ends up under the transparent layers of the heatmap. I want it to stay on top. I tried to apply featuregroup.bringToBack() and featuregroup.bringToFront()m but it's not working as expected.

I wrote some example code with jsfiddle for this stackoverflow question to illustrate the problem and my approach in a more simple way. You need leaflet.js, leaflet.css and leaflet-heat.js for this to work:

# prepare basemap
osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png'
osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors'
osm = L.tileLayer(osmUrl,
maxZoom: 18
attribution: osmAttrib)

# initialize the map with basemap
map = L.map('map').setView([
17
75
], 5).addLayer(osm)

# coordinate vectors
lat = [14, 15, 16, 18, 19, 20]
lng = [72, 73, 74, 76, 77, 78]

# function: layer arrangement in relation to zoom state
arrange_layers = ->
if map.getZoom() > 5
console.log "1"
heatItem.bringToFront()
if map.getZoom() <= 5
console.log "2"
heatItem.bringToBack()
return

#function: react to user zooming
map.on 'zoomend', (e) ->
arrange_layers()
console.log map.getZoom();
return

# add circles to map
for lati in lat
for lngi in lng
L.circle([
lati
lngi
], 50000,
color: 'black'
fillColor: '#black'
fillOpacity: 0.5).addTo(map)

# add heatmap to map
heatItem = new (L.FeatureGroup)
heat = L.heatLayer([
[
15
73
3000
]
[
19
77
10000
]
], radius: 25).addTo(heatItem)
heatItem.addTo(map)


Edit:

The solution for my problem was to change to Leaflet 1.0 and add some custom panes with defined z value. Now I can control the layer order. The corrected example code looks like this and depends on leaflet.js, leaflet.css and leaflet-heat.js:

# prepare basemap
osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png'
osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors'
osm = L.tileLayer(osmUrl,
maxZoom: 18
attribution: osmAttrib)

# initialize the map with basemap
map = L.map('map').setView([
17
75
], 5).addLayer(osm)

# coordinate vectors
lat = [14, 15, 16, 18, 19, 20]
lng = [72, 73, 74, 76, 77, 78]

# create pane
map.createPane 'circles'
map.getPane('circles').style.zIndex = 450

# add circles to map
for lati in lat
for lngi in lng
L.circle([
lati
lngi
], 50000,
color: 'black'
fillColor: '#black'
fillOpacity: 0.5
pane: 'circles').addTo(map)

# add heatmap to map
heatItem = new (L.FeatureGroup)
heat = L.heatLayer([
[
15
73
3000
]
[
19
77
10000
]
], radius: 25).addTo(heatItem)
heatItem.addTo(map)

Answer

Unfortunately, Leaflet.heat plugin creates a layer that sits in a <canvas> Element which cannot be ordered through .bringToFront() or .bringToBack() methods.

Your heat layer does not provide these methods, so your heatItem.bringToBack() will have no effect, even if it does not output any error.

You could give a try with Leaflet 1.0, with which you can use map.createPane() to create "panes" (layer containers) that you can order.

By the way, your JSFiddle uses Leaflet 0.7.2 (current stable version is 0.7.7) with former CDN that does not support https protocol. Updated JSFiddle: https://jsfiddle.net/emwmc4xw/98/


EDIT

I do not know if Leaflet.heat can take a pane option (you could look at its code).

As a workaround, you can define it on all your other layers, like your circles. Then you can set their zIndex above or below 400, which is where is the default overlayPane, where the Leaflet.heat canvas and your circles go by default if no pane is specified.

Updated JSFiddle: https://jsfiddle.net/emwmc4xw/120/

Comments