Imagery vintage improvements:

- Cache vintage lookups from Bing API
- Actually sample a tile at the center of the viewport,
  rather than just divinding tiles/2 (not a good guess)
- Refactor the start-end range code into one place
This commit is contained in:
Bryan Housel
2017-07-03 15:12:59 -04:00
parent 1d8898778e
commit b9df6df03f
3 changed files with 74 additions and 45 deletions
+33 -9
View File
@@ -12,6 +12,17 @@ function localeDateString(s) {
return d.toLocaleDateString();
}
function vintageRange(vintage) {
var s;
if (vintage.start || vintage.end) {
s = (vintage.start || '?');
if (vintage.start !== vintage.end) {
s += ' - ' + (vintage.end || '?');
}
}
return s;
}
export function rendererBackgroundSource(data) {
var source = _.clone(data),
@@ -114,11 +125,13 @@ export function rendererBackgroundSource(data) {
source.copyrightNotices = function() {};
source.getVintage = function(center, zoom, callback) {
callback(null, {
source.getVintage = function(center, tileCoord, callback) {
var vintage = {
start: localeDateString(source.startDate),
end: localeDateString(source.endDate)
});
};
vintage.range = vintageRange(vintage);
callback(null, vintage);
};
@@ -136,6 +149,7 @@ rendererBackgroundSource.Bing = function(data, dispatch) {
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 = {},
providers = [];
jsonpRequest(url, function(json) {
@@ -168,22 +182,32 @@ rendererBackgroundSource.Bing = function(data, dispatch) {
};
bing.getVintage = function(center, zoom, callback) {
zoom = Math.min(zoom, 21);
var centerPoint = center[1] + ',' + center[0],
bing.getVintage = 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 +
'?zl=' + zoom + '&key=' + key + '&jsonp={callback}';
if (!cache[tileId]) {
cache[tileId] = {};
}
if (cache[tileId] && cache[tileId].vintage) {
return callback(null, cache[tileId].vintage);
}
jsonpRequest(url, function(result) {
var err = (!result && 'Unknown Error') || result.errorDetails;
if (err) {
return callback(err);
} else {
return callback(null, {
var vintage = {
start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
});
};
vintage.range = vintageRange(vintage);
cache[tileId].vintage = vintage;
return callback(null, vintage);
}
});
};
+35 -19
View File
@@ -1,7 +1,8 @@
import * as d3 from 'd3';
import { t } from '../util/locale';
import { d3geoTile } from '../lib/d3.geo.tile';
import { utilPrefixCSSProperty } from '../util/index';
import { geoEuclideanDistance } from '../geo';
import { utilPrefixCSSProperty } from '../util';
import { rendererBackgroundSource } from './background_source.js';
@@ -98,7 +99,7 @@ export function rendererTileLayer(context) {
tile().forEach(function(d) {
addSource(d);
if (d[3] === '') return;
if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
if (typeof d[3] !== 'string') return; // Workaround for #2295
requests.push(d);
if (cache[d[3]] === false && lookUp(d)) {
requests.push(addSource(lookUp(d)));
@@ -119,6 +120,7 @@ export function rendererTileLayer(context) {
source.offset()[1] * Math.pow(2, z)
];
function load(d) {
cache[d[3]] = true;
d3.select(this)
@@ -146,9 +148,11 @@ export function rendererTileLayer(context) {
'scale(' + scale + ',' + scale + ')';
}
function debugCoordinates(d) {
function tileCenter(d) {
var _ts = tileSize * Math.pow(2, z - d[2]);
var scale = tileSizeAtZoom(d, z);
// FIXME: this scale * tileSize/number stuff is hacky, and more for displaying the debug text.
// It's not really the center of the tile, but it is guaranteed to be somewhere in the tile.
return [
((d[0] * _ts) - tileOrigin[0] + pixelOffset[0] + scale * (tileSize / 4)),
((d[1] * _ts) - tileOrigin[1] + pixelOffset[1] + scale * (tileSize / 2))
@@ -156,16 +160,35 @@ export function rendererTileLayer(context) {
}
function debugTransform(d) {
var coord = debugCoordinates(d);
var coord = tileCenter(d);
return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
}
// Pick a representative tile near the center of the viewport
// (This is useful for sampling the imagery vintage)
var dims = tile.size(),
mapCenter = [dims[0] / 2, dims[1] / 2],
minDist = Math.max(dims[0], dims[1]),
nearCenter;
requests.forEach(function(d) {
var c = tileCenter(d);
var dist = geoEuclideanDistance(c, mapCenter);
if (dist < minDist) {
minDist = dist;
nearCenter = d;
}
});
var image = selection.selectAll('img')
.data(requests, function(d) { return d[3]; });
image.exit()
.style(transformProp, imageTransform)
.classed('tile-removing', true)
.classed('tile-center', false)
.each(function() {
var tile = d3.select(this);
window.setTimeout(function() {
@@ -184,7 +207,9 @@ export function rendererTileLayer(context) {
.merge(image)
.style(transformProp, imageTransform)
.classed('tile-debug', showDebug)
.classed('tile-removing', false);
.classed('tile-removing', false)
.classed('tile-center', function(d) { return d === nearCenter; });
var debug = selection.selectAll('.tile-label-debug')
@@ -219,20 +244,11 @@ export function rendererTileLayer(context) {
.selectAll('.tile-label-debug-vintage')
.each(function(d) {
var span = d3.select(this);
var center = context.projection.invert(debugCoordinates(d));
source.getVintage(center, d[2], function(err, result) {
var vintage = '';
if (result) {
if (result.start || result.end) {
vintage = (result.start || '?');
if (result.start !== result.end) {
vintage += ' - ' + (result.end || '?');
}
}
}
span
.text(vintage || t('infobox.imagery.vintage') + ': ' + t('infobox.imagery.unknown'));
var center = context.projection.invert(tileCenter(d));
source.getVintage(center, d, function(err, result) {
span.text((result && result.range) ||
t('infobox.imagery.vintage') + ': ' + t('infobox.imagery.unknown')
);
});
});
}
+6 -17
View File
@@ -64,31 +64,20 @@ export function uiPanelImagery(context) {
var debouncedGetVintage = _.debounce(getVintage, 250);
function getVintage(selection) {
var tile = d3.select('.layer-background img');
var tile = d3.select('.layer-background img.tile-center'); // tile near viewport center
if (tile.empty()) return;
var tiledata = tile.datum(),
zoom = tiledata[2] || Math.floor(context.map().zoom()),
var d = tile.datum(),
zoom = (d && d.length >= 3 && d[2]) || Math.floor(context.map().zoom()),
center = context.map().center();
currZoom = String(zoom);
selection.selectAll('.zoom')
.text(currZoom);
background.baseLayerSource().getVintage(center, currZoom, function(err, result) {
if (!result) {
currVintage = t('infobox.imagery.unknown');
} else {
if (result.start || result.end) {
currVintage = (result.start || '?');
if (result.start !== result.end) {
currVintage += ' - ' + (result.end || '?');
}
} else {
currVintage = t('infobox.imagery.unknown');
}
}
if (!d || !d.length >= 3) return;
background.baseLayerSource().getVintage(center, d, function(err, result) {
currVintage = (result && result.range) || t('infobox.imagery.unknown');
selection.selectAll('.vintage')
.text(currVintage);
});