在 Leaflet 中使用多个图块层时避免加载不可见图块

Avoid loading of invisible tiles when using multiple tile layers in Leaflet

我正在使用 Leaflet 和两个图块图层。第一个,我称之为 basement tile layer,为整个世界提供瓷砖。第二个覆盖由弹跳选项定义的特定区域中的地下室瓷砖层。我将其称为 叠加图块层 。在代码中,这类似于以下内容:

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

// OpenstreetMap tile layer as basement
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
  attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

// overlaying tile layer for specific region defined by bounds
L.tileLayer('http://{s}.examples.com/overlay/{z}/{x}/{y}.png', {
  bounds: L.latLngBounds(L.latLng(59.321966, 18.05943), L.latLng(59.328469, 18.076167));
}).addTo(map);

叠加的图块图层不透明。因此,对于边界区域,只有覆盖图块层的图块是可见的。不需要地下室瓷砖层提供的瓷砖。但是我还没有找到一种方法来阻止 Leaflet 加载这些不必要的图块。如果有任何提示,我会很高兴。

我考虑过使用图块事件来中断加载不需要的图块。但据记录的图块事件无法操纵图块加载。

这里是 JSFiddle 演示行为。如你所见tile 14/4825/6155.png 是从 openstreetmap.org 加载的,即使它是不可见的。

在我的用例中,另一种想法使它变得更加复杂:叠加地图具有严格的边界,因为它是由历史地图生成的 sheet。因此,图块在叠加地图的边界处是透明的。在这些区域中,必须加载地下室地图的瓦片。

感谢@FrankPhillips 在评论中的提示,我发现我可以覆盖 L.GridLayer 中的 _isValidTile 方法来实现该功能。我可以添加一个 hole 选项作为 bounce 选项的对立面。

L.ExtendedTileLayer = L.TileLayer.extend({    
    _isValidTile: function (coords) {
        var crs = this._map.options.crs;

        if (!crs.infinite) {
            // don't load tile if it's out of bounds and not wrapped

            /*
             * this._globalTileRange is not defined
             * not quite sure why
             */
            var globalTileRange = this._map.getPixelWorldBounds( coords.z );

            var bounds = globalTileRange;
            if ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||
                (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }
        }

        var tileBounds = this._tileCoordsToBounds(coords);

        // don't load tile if it doesn't intersect the bounds in options
        if (this.options.bounds &&
            ! L.latLngBounds(this.options.bounds).intersects(tileBounds)) {
            return false;
        }

        // don't load tile if it does intersect the hole in options
        if (this.options.hole &&
            L.latLngBounds(this.options.hole).intersects(tileBounds)) {
            return false;
        }

        return true;
    },
});

var map = L.map('map', {
    center: [40.777838, -73.968654], 
    zoom: 14
});

new L.ExtendedTileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
    attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
    hole: L.latLngBounds(
        L.latLng(40.791853, -73.967128),
        L.latLng(40.781455, -73.955713)
    )
}).addTo(map);

L.tileLayer('http://tile.stamen.com/toner/{z}/{x}/{y}.png', {
    attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.',
    bounds: L.latLngBounds(
        L.latLng(40.791853, -73.967128),
        L.latLng(40.781455, -73.955713)
    )
}).addTo(map);

updated JSFiddle展示它的工作。

_isValidTile 大多只是从 Leaflet 原版复制而来。我不得不重新实现 this._globalTileRange 因为它是未定义的。代码仅适用于 leaflet-src.js,因为 _isValidTime 在生产构建中被丑化了。