From 167dd77ce079a54dfa7f78f480e6952d908c095f Mon Sep 17 00:00:00 2001 From: john gravois Date: Thu, 5 Oct 2017 13:39:01 -0700 Subject: [PATCH] use zoom level 22 as default maxZoom for World Imagery instead of artificially capping the zoom for World Imagery at 19, interrogate the esri tilemap when zooming begins to see whether all tiles in an 8x8 grid at the next zoom level are present. if they aren't, use leaflet's new built in option to downsample the existing tiles. --- src/Layers/BasemapLayer.js | 53 +++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/Layers/BasemapLayer.js b/src/Layers/BasemapLayer.js index edc8bb777..c4ecdda24 100644 --- a/src/Layers/BasemapLayer.js +++ b/src/Layers/BasemapLayer.js @@ -102,7 +102,9 @@ export var BasemapLayer = TileLayer.extend({ urlTemplate: tileProtocol + '//{s}.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', options: { minZoom: 1, - maxZoom: 19, + maxZoom: 22, + maxNativeZoom: 22, + downsampled: false, subdomains: ['server', 'services'], attribution: 'DigitalGlobe, GeoEye, i-cubed, USDA, USGS, AEX, Getmapping, Aerogrid, IGN, IGP, swisstopo, and the GIS User Community' } @@ -215,6 +217,11 @@ export var BasemapLayer = TileLayer.extend({ map.on('moveend', _updateMapAttribution); + // Esri World Imagery is cached all the way to zoom 22 in select regions + if (this._url.indexOf('World_Imagery') !== -1) { + map.on('zoomanim', _fetchTilemap, this); + } + TileLayer.prototype.onAdd.call(this, map); }, @@ -239,6 +246,50 @@ export var BasemapLayer = TileLayer.extend({ } }); +function _fetchTilemap (evt) { + var map = evt.target; + if (!map) { return; } + + var oldZoom = map.getZoom(); + var newZoom = evt.zoom; + var newCenter = map.wrapLatLng(evt.center); + + if (newZoom > oldZoom && newZoom > 13 && !this.options.downsampled) { + // convert wrapped lat/long into tile coordinates and use them to generate the tilemap url + var tilePoint = map.project(newCenter, newZoom).divideBy(256).floor(); + + // use new coords to determine the tilemap url + var tileUrl = Util.template(this._url, Util.extend({ + s: this._getSubdomain(tilePoint), + x: tilePoint.x, + y: tilePoint.y, + z: newZoom + }, this.options)); + + // 8x8 grids are cached + var tilemapUrl = tileUrl.replace(/tile/, 'tilemap') + '/8/8'; + + // an array of booleans in the response indicate missing tiles + L.esri.request(tilemapUrl, {}, function (err, response) { + if (!err) { + for (var i = 0; i < response.data.length; i++) { + if (!response.data[i]) { + // if necessary, resample a lower zoom + this.options.maxNativeZoom = newZoom - 1; + this.options.downsampled = true; + break; + } + // if no tiles are missing, reset the original maxZoom + this.options.maxNativeZoom = 22; + } + } + }, this); + } else if (newZoom < 13) { + // if the user moves to a new region, time for a fresh test + this.options.downsampled = false; + } +} + export function basemapLayer (key, options) { return new BasemapLayer(key, options); }