窗格是什么?

在Leaflet中,map panes可以自动将图层分组,但是开发人员觉察不到,这使得浏览器能够更有效地一次处理多个图层,而不是一次处理一个图层。

Map panes 使用z-index CSS property 属性来控制某些图层显示在其他图层之上。默认的顺序如下:

  • TileLayers and GridLayers
  • Paths, like lines, polylines, circles, or GeoJSON layers.
  • Marker shadows
  • Marker icons
  • Popups

这也是为什么在Leaflet地图中,popups会显示在其他图层之上,markers总是显示在切片图层之上等等的原因。

Leaflet 1.0.0 之后增加了一个新特性(0.7.X没有)可以自定义map panes,用于调整默认的顺序。

默认值不总是合适的

在某些特殊情况下,默认的图层排序并不总是合适的。我们用下面的底图和标注图层的例子解释一下:


没有标注的底图

透明的标注图层

标注图层在底图之上

如果我们为Leaflet的地图添加了上述的底图和标注图层,任何的多边形或者标记都会显示在这两个图层的上方,不过让标注图层显示在最上面可能是更好地选择。我们应该怎样实现呢?

查看本实例

自定义窗格

对于底图和GeoJSON之类的覆盖图层,我们可以使用其默认设置,但是对于标注图层我们就需要自定义一个窗格了,以使其显示在GeoJSON图层之上。

自定义地图窗格都是在原有地图的基础上创建的,所以我们首先应该创建一个L.Map的地图实例和它所需的窗格:

var map = L.map('map');
map.createPane('labels');

下一步就是设置窗格的z-index的值了。查看窗格的默认值,将新窗格的z-index值设置为650可以使标注图层显示在markers图层之上popups图层之下。使用getPane()方法可以获取pane的Html元素,然后修改它的z-index值。

map.getPane('labels').style.zIndex = 650;

让图像层位于其他图层之上的问题之一就是切片会捕获点击或触摸等事件。如果用户点击了地图的某个区域,浏览器会认为用户点击的是图像层,而非GeoJSON层或者标记层。我们可以使用 CSS的pointer-events属性来解决这个问题:

map.getPane('labels').style.pointerEvents = 'none';

新窗格已经创建好了,我们可以添加图层了,注意要在标注图层上使用pane选项:

var positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', {
        attribution: '©OpenStreetMap, ©CartoDB'
}).addTo(map);

var positronLabels = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', {
        attribution: '©OpenStreetMap, ©CartoDB',
        pane: 'labels'
}).addTo(map);

var geojson = L.geoJson(GeoJsonData, geoJsonOptions).addTo(map);

最后,为GeoJSON图层添加一些交互功能:

geojson.eachLayer(function (layer) {
    layer.bindPopup(layer.feature.properties.name);
});

map.fitBounds(geojson.getBounds());

这样示例地图就完成了!