Fetch Esri tilemap at high zoom to determine max zoom

The tilemap is only fetched if the user is at z > 18 and will not fetch again
unless the user has moved more than 1km away from the previous fetch
This commit is contained in:
Bryan Housel
2018-06-28 23:20:08 -04:00
parent eaa9d8d246
commit b6fb3a345d
3 changed files with 80 additions and 70 deletions

View File

@@ -26,6 +26,15 @@ export function rendererBackground(context) {
function background(selection) {
// If we are displaying an Esri basemap at high zoom,
// check its tilemap to see how high the zoom can go
if (context.map().zoom() > 18) {
var basemap = baseLayer.source();
if (basemap && /^EsriWorldImagery/.test(basemap.id)) {
var center = context.map().center();
basemap.fetchTilemap(center);
}
}
var baseFilter = '';
if (detected.cssfilters) {
@@ -114,16 +123,17 @@ export function rendererBackground(context) {
background.updateImagery = function() {
if (context.inIntro()) return;
var b = background.baseLayerSource(),
o = _overlayLayers
.filter(function (d) { return !d.source().isLocatorOverlay() && !d.source().isHidden(); })
.map(function (d) { return d.source().id; })
.join(','),
meters = geoOffsetToMeters(b.offset()),
epsilon = 0.01,
x = +meters[0].toFixed(2),
y = +meters[1].toFixed(2),
q = utilStringQs(window.location.hash.substring(1));
var b = background.baseLayerSource();
var o = _overlayLayers
.filter(function (d) { return !d.source().isLocatorOverlay() && !d.source().isHidden(); })
.map(function (d) { return d.source().id; })
.join(',');
var meters = geoOffsetToMeters(b.offset());
var epsilon = 0.01;
var x = +meters[0].toFixed(2);
var y = +meters[1].toFixed(2);
var q = utilStringQs(window.location.hash.substring(1));
var id = b.id;
if (id === 'custom') {
@@ -215,13 +225,12 @@ export function rendererBackground(context) {
if (!osm) return background;
var blacklists = context.connection().imageryBlacklists();
var template = d.template();
var fail = false;
var tested = 0;
var regex;
var template = d.template(),
fail = false,
tested = 0,
regex, i;
for (i = 0; i < blacklists.length; i++) {
for (var i = 0; i < blacklists.length; i++) {
try {
regex = new RegExp(blacklists[i]);
fail = regex.test(template);
@@ -270,7 +279,6 @@ export function rendererBackground(context) {
background.toggleOverlayLayer = function(d) {
var layer;
for (var i = 0; i < _overlayLayers.length; i++) {
layer = _overlayLayers[i];
if (layer.source() === d) {
@@ -350,12 +358,12 @@ export function rendererBackground(context) {
return geoExtent([args[2], args[1]]);
}
var dataImagery = data.imagery || [],
q = utilStringQs(window.location.hash.substring(1)),
requested = q.background || q.layer,
extent = parseMap(q.map),
first,
best;
var dataImagery = data.imagery || [];
var q = utilStringQs(window.location.hash.substring(1));
var requested = q.background || q.layer;
var extent = parseMap(q.map);
var first;
var best;
// Add all the available imagery sources
_backgroundSources = dataImagery.map(function(source) {

View File

@@ -9,7 +9,13 @@ import {
import { json as d3_json } from 'd3-request';
import { t } from '../util/locale';
import { geoExtent, geoPolygonIntersectsPolygon } from '../geo';
import {
geoExtent,
geoPolygonIntersectsPolygon,
geoSphericalDistance
} from '../geo';
import { jsonpRequest } from '../util/jsonp_request';
import { utilDetect } from '../util/detect';
@@ -111,19 +117,20 @@ export function rendererBackgroundSource(data) {
var lat = Math.atan(sinh(Math.PI * (1 - 2 * y / zoomSize)));
switch (this.projection) {
case 'EPSG:4326': // todo: alternative codes of WGS 84?
return {
x: lon * 180 / Math.PI,
y: lat * 180 / Math.PI
};
default: // EPSG:3857 and synonyms
var mercCoords = d3_geoMercatorRaw(lon, lat);
return {
x: 20037508.34 / Math.PI * mercCoords[0],
y: 20037508.34 / Math.PI * mercCoords[1]
};
case 'EPSG:4326': // todo: alternative codes of WGS 84?
return {
x: lon * 180 / Math.PI,
y: lat * 180 / Math.PI
};
default: // EPSG:3857 and synonyms
var mercCoords = d3_geoMercatorRaw(lon, lat);
return {
x: 20037508.34 / Math.PI * mercCoords[0],
y: 20037508.34 / Math.PI * mercCoords[1]
};
}
}).bind(this);
var minXmaxY = tileToProjectedCoords(coord[0], coord[1], coord[2]);
var maxXminY = tileToProjectedCoords(coord[0]+1, coord[1]+1, coord[2]);
return template
@@ -207,13 +214,13 @@ rendererBackgroundSource.Bing = function(data, dispatch) {
data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
var bing = rendererBackgroundSource(data),
key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
key + '&jsonp={callback}',
cache = {},
inflight = {},
providers = [];
var bing = rendererBackgroundSource(data);
var key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'; // Same as P2 and JOSM
var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
key + '&jsonp={callback}';
var cache = {};
var inflight = {};
var providers = [];
jsonpRequest(url, function(json) {
providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
@@ -246,10 +253,10 @@ rendererBackgroundSource.Bing = function(data, dispatch) {
bing.getMetadata = function(center, tileCoord, callback) {
var tileId = tileCoord.slice(0, 3).join('/'),
zoom = Math.min(tileCoord[2], 21),
centerPoint = center[1] + ',' + center[0], // lat,lng
url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint +
var tileId = tileCoord.slice(0, 3).join('/');
var zoom = Math.min(tileCoord[2], 21);
var centerPoint = center[1] + ',' + center[0]; // lat,lng
var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint +
'?zl=' + zoom + '&key=' + key + '&jsonp={callback}';
if (inflight[tileId]) return;
@@ -292,13 +299,18 @@ rendererBackgroundSource.Bing = function(data, dispatch) {
rendererBackgroundSource.Esri = function(data) {
var esri = rendererBackgroundSource(data),
cache = {},
inflight = {};
var esri = rendererBackgroundSource(data);
var cache = {};
var inflight = {};
var _prevCenter;
// use a tilemap service to set maximum zoom for esri tiles dynamically
// https://developers.arcgis.com/documentation/tiled-elevation-service/
esri.fetchTilemap = function(center) {
// skip if we have already fetched a tilemap within 5km
if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5000) return;
_prevCenter = center;
// tiles are available globally to zoom level 19, afterward they may or may not be present
var z = 20;
@@ -316,30 +328,28 @@ rendererBackgroundSource.Esri = function(data) {
d3_json(tilemapUrl, function (err, tilemap) {
if (err || !tilemap) return;
var tiles = true;
for (var i=0; i<tilemap.data.length; i++) {
var hasTiles = true;
for (var i = 0; i < tilemap.data.length; i++) {
// 0 means an individual tile in the grid doesn't exist
if (!tilemap.data[i]) {
tiles = false;
hasTiles = false;
break;
}
}
// if any tiles are missing at level 20 we restrict maxZoom to 19
if (!tiles) {
esri.scaleExtent[1] = 19;
}
esri.scaleExtent[1] = (hasTiles ? 20 : 19);
});
};
esri.getMetadata = function(center, tileCoord, callback) {
var tileId = tileCoord.slice(0, 3).join('/'),
zoom = Math.min(tileCoord[2], esri.scaleExtent[1]),
centerPoint = center[0] + ',' + center[1], // long, lat (as it should be)
unknown = t('info_panels.background.unknown'),
metadataLayer,
vintage = {},
metadata = {};
var tileId = tileCoord.slice(0, 3).join('/');
var zoom = Math.min(tileCoord[2], esri.scaleExtent[1]);
var centerPoint = center[0] + ',' + center[1]; // long, lat (as it should be)
var unknown = t('info_panels.background.unknown');
var metadataLayer;
var vintage = {};
var metadata = {};
if (inflight[tileId]) return;

View File

@@ -34,14 +34,6 @@ export function uiNotice(context) {
function disableTooHigh() {
var canEdit = context.map().zoom() >= context.minEditableZoom();
div.style('display', canEdit ? 'none' : 'block');
// if an Esri basemap is being displayed and native zoom past 19 is enabled, check the tilemap
if (canEdit) {
var basemap = context.background().baseLayerSource();
if (/^EsriWorldImagery/.test(basemap.id) && basemap.scaleExtent[1] > 19) {
var center = context.map().center();
basemap.fetchTilemap(center);
}
}
}
context.map()