Fetch mapillary data in tiles and cache

This commit is contained in:
Bryan Housel
2016-02-08 17:14:46 -05:00
parent f173441fe3
commit caf464e3d3
2 changed files with 139 additions and 48 deletions
+42 -41
View File
@@ -1,8 +1,13 @@
iD.MapillaryImageLayer = function (context) {
var mapillary = iD.services.mapillary(),
iD.MapillaryImageLayer = function(context) {
var mapillary = iD.services.mapillary()
.on('loadedImages.imageLayer', imagesLoaded),
imageData = rbush(),
urlImage = 'http://mapillary.com/map/im/',
urlThumb = 'https://d1cuyjsrcm0gby.cloudfront.net/',
enable = false,
currentImage,
svg, div, request;
svg, thumbnail;
function show(image) {
svg.selectAll('g')
@@ -10,13 +15,13 @@ iD.MapillaryImageLayer = function (context) {
return currentImage && d.key === currentImage.key;
});
div.classed('hidden', false)
thumbnail.classed('hidden', false)
.classed('temp', image !== currentImage);
div.selectAll('img')
thumbnail.selectAll('img')
.attr('src', urlThumb + image.key + '/thumb-320.jpg');
div.selectAll('a')
thumbnail.selectAll('a')
.attr('href', urlImage + image.key);
}
@@ -26,7 +31,7 @@ iD.MapillaryImageLayer = function (context) {
svg.selectAll('g')
.classed('selected', false);
div.classed('hidden', true);
thumbnail.classed('hidden', true);
}
function transform(d) {
@@ -35,22 +40,30 @@ iD.MapillaryImageLayer = function (context) {
return t;
}
function render(err, data) {
if (err) return;
function imagesLoaded(data) {
var images = [],
sequence, loc;
var images = [];
for (var i = 0; i < data.features.length; i++) {
var sequence = data.features[i];
sequence = data.features[i];
for (var j = 0; j < sequence.geometry.coordinates.length; j++) {
images.push({
loc = sequence.geometry.coordinates[j];
images.push([loc[0], loc[1], loc[0], loc[1], {
key: sequence.properties.keys[j],
ca: sequence.properties.cas[j],
loc: sequence.geometry.coordinates[j]
});
if (images.length >= 1000) break;
}]);
}
}
imageData.load(images);
}
function render() {
var images = imageData
.search(context.map().extent().rectangle())
.map(function(d) { return d[4]; });
var g = svg.selectAll('g')
.data(images, function(d) { return d.key; });
@@ -73,6 +86,7 @@ iD.MapillaryImageLayer = function (context) {
.remove();
}
function layer(selection) {
svg = selection.selectAll('svg')
.data([0]);
@@ -100,49 +114,36 @@ iD.MapillaryImageLayer = function (context) {
svg.style('display', enable ? 'block' : 'none');
div = context.container().selectAll('.mapillary-image')
thumbnail = context.container().selectAll('.mapillary-image')
.data([0]);
var enter = div.enter().append('div')
var enter = thumbnail.enter().append('div')
.attr('class', 'mapillary-image');
enter.append('button')
.on('click', hide)
.append('div')
.call(iD.svg.Icon('#icon-close'));
.attr('class', 'icon close');
enter.append('img');
enter
.append('a')
var link = enter.append('a')
.attr('class', 'link')
.attr('target', '_blank')
.call(iD.svg.Icon('#icon-out-link', 'inline'))
.append('span')
.attr('target', '_blank');
link.append('span')
.attr('class', 'icon icon-pre-text out-link');
link.append('span')
.text(t('mapillary_images.view_on_mapillary'));
if (!enable) {
hide();
svg.selectAll('g')
.remove();
return;
svg.selectAll('g').remove();
} else {
render();
mapillary.loadImages(context.projection, svg.dimensions());
}
// Update existing images while waiting for new ones to load.
svg.selectAll('g')
.attr('transform', transform);
var extent = context.map().extent();
if (request)
request.abort();
request = d3.json(urlSearch + '?client_id=' + clientId + '&min_lat=' +
extent[0][1] + '&max_lat=' + extent[1][1] + '&min_lon=' +
extent[0][0] + '&max_lon=' + extent[1][0] + '&max_results=100&geojson=true',
);
}
layer.enable = function(_) {
+97 -7
View File
@@ -1,18 +1,107 @@
iD.services.mapillary = function() {
var mapillary = {},
apiBase = 'https://a.mapillary.com/v2/',
urlSearch = 'search/s/geojson',
dispatch = d3.dispatch('loadedImages', 'loadedSigns', 'loadedThumbnail'),
endpoint = 'https://a.mapillary.com/v2/',
urlImage = 'https://www.mapillary.com/map/im/',
urlThumb = 'https://d1cuyjsrcm0gby.cloudfront.net/',
clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi';
clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi',
tileZoom = 17;
mapillary.images = function(location, callback) {
var cache = iD.services.mapillary.cache;
function abortRequest(i) {
i.abort();
}
function getTiles(projection, dimensions) {
var s = projection.scale() * 2 * Math.PI,
z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
ts = 256 * Math.pow(2, z - tileZoom),
origin = [
s / 2 - projection.translate()[0],
s / 2 - projection.translate()[1]];
return d3.geo.tile()
.scaleExtent([tileZoom, tileZoom])
.scale(s)
.size(dimensions)
.translate(projection.translate())()
.map(function(tile) {
var x = tile[0] * ts - origin[0],
y = tile[1] * ts - origin[1];
return {
id: tile.toString(),
extent: iD.geo.Extent(
projection.invert([x, y + ts]),
projection.invert([x + ts, y]))
};
});
}
function loadTiles(which, url, projection, dimensions) {
var cache = iD.services.mapillary.cache,
tiles = getTiles(projection, dimensions);
_.filter(which.inflight, function(v, k) {
var wanted = _.find(tiles, function(tile) { return k === tile.id; });
if (!wanted) delete which.inflight[k];
return !wanted;
}).map(abortRequest);
tiles.forEach(function(tile) {
var id = tile.id,
extent = tile.extent;
if (which.loaded[id] || which.inflight[id]) return;
which.inflight[id] = d3.json(url +
iD.util.qsString({
geojson: 'true',
client_id: clientId,
min_lat: extent[0][1],
max_lat: extent[1][1],
min_lon: extent[0][0],
max_lon: extent[1][0]
}), function(err, data) {
which.loaded[id] = true;
delete which.inflight[id];
if (err) return;
if (which === cache.images)
dispatch.loadedImages(data);
else if (which === cache.signs)
dispatch.loadedSigns(data);
}
);
});
}
mapillary.loadImages = function(projection, dimensions) {
var cache = iD.services.mapillary.cache,
url = endpoint + 'search/s/geojson?';
loadTiles(cache.images, url, projection, dimensions);
};
mapillary.loadSigns = function(projection, dimensions) {
var cache = iD.services.mapillary.cache,
url = endpoint + 'search/im/geojson/or?';
loadTiles(cache.signs, url, projection, dimensions);
};
mapillary.reset = function() {
iD.services.mapillary.cache = rbush();
var cache = iD.services.mapillary.cache;
if (cache) {
_.forEach(cache.images.inflight, abortRequest);
_.forEach(cache.signs.inflight, abortRequest);
}
iD.services.mapillary.cache = {
images: { inflight: {}, loaded: {}, rbush: rbush() },
signs: { inflight: {}, loaded: {}, rbush: rbush() }
};
return mapillary;
};
@@ -21,5 +110,6 @@ iD.services.mapillary = function() {
mapillary.reset();
}
return mapillary;
return d3.rebind(mapillary, dispatch, 'on');
};