leaflet 用自定义pane实现图层顺序调整

在 Leaflet 中,map panes 隐式地将图层组合在一起,而开发者并不知道这一点。这种分组允许 Web 浏览器以比单独处理图层更有效的方式同时处理多个图层。

Map panes 使用 z-index CSS 属性来让某些图层始终显示在其他图层之上。默认的排序是:

  • TileLayer 和 GridLayer
  • Path, 如线、折线、圆或 GeoJSON 图层
  • Marker 阴影
  • Marker 图标
  • Popup

这就是为什么在 Leaflet 地图中,popups 总是显示在其他层的 “上面”,markers 总是显示在瓦片图层的上面,等等。

Leaflet 1.0.0 的一个新功能(0.7.x 中没有)是自定义 map panes,它允许自定义这个顺序。

默认情况并不总是正确的

在某些特定情况下,默认顺序不是地图的正确顺序。我们可以用 Carto basemaps 底图和标签来证明这一点:

如果我们用这两个图层创建一个 Leaflet 地图,任何标记或多边形都会显示在这两个图层的上面,但是把标签放在上面看起来更好,我们怎样才能做到这一点呢?

自定义 pane

我们可以使用默认的底图瓦片(tile)和一些像 GeoJSON 图层这样的覆盖物, 然后我们必须为标签定义一个自定义窗格(pane),以便它们显示在 GeoJSON 数据之上。

自定义 map panes 是在每个地图的基础上创建的,所以首先创建一个 L.Map 的实例和 pane:

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

下一步是设置窗格的z-index。查看默认值为650,这将使带有标签的 TileLayer 显示在标记的上面和弹窗窗口的下面。通过使用 getPane(),我们获得了对 HTMLElement 表示窗格的引用,并更改它的 z-index:

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

在其他地图层之上设置图像标签的一个问题是,这些标签会捕捉到点击和触摸事件。如果用户点击地图上的任何地方,网络浏览器会认为她点击的是标签瓦片,而不是 GeoJSON 或标记物。这个问题可以用 pointer-events CSS 属性来解决:

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

窗格(pane)准备就绪后,我们可以添加图层,注意使用标签瓦片(tile)上的 pane 选项:

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

var positronLabels = L.tileLayer('https://{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 层上的每个 feature 添加一些交互:

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

map.fitBounds(geojson.getBounds());

现在,示例地图已经完成了!

leaflet官网参考

下面放一个实例:

    addBoundLayer() {
      //设置自定义窗格pane层级zIndex
      let boundaryPane = this.map.createPane('boundaryPane')
      boundaryPane.style.zIndex = 200
      boundaryPane.style.pointerEvents = 'none'

      //加载geojson并显示
      getGeojsonByName({ name: 'shengze' }).then(data => {
        this.bondarylayer = L.geoJSON(data, {
          style: {
            color: '#555',
            fillOpacity: 0,
            weight: 2,
            dashArray: 10
          },
          pane: 'boundaryPane'//指定pane名字
        })
        this.map.addLayer(this.bondarylayer)
        this.drawBoundaryMask(data.geometries[0].coordinates[0])
      })
    },

 

posted @ 2022-12-07 14:55  JackGIS  阅读(1407)  评论(0编辑  收藏  举报