mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-17 22:24:49 +02:00
Fetch mapillary data in tiles and cache
This commit is contained in:
@@ -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(_) {
|
||||
|
||||
@@ -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');
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user