in modules/services/mapillary.js [87:227]
function loadNextTilePage(which, currZoom, url, tile) {
var cache = _mlyCache[which];
var rect = tile.extent.rectangle();
var maxPages = maxPageAtZoom(currZoom);
var nextPage = cache.nextPage[tile.id] || 0;
var nextURL = cache.nextURL[tile.id] || url +
utilQsString({
per_page: maxResults,
page: nextPage,
client_id: clientId,
bbox: [rect[0], rect[1], rect[2], rect[3]].join(','),
});
if (nextPage > maxPages) return;
var id = tile.id + ',' + String(nextPage);
if (cache.loaded[id] || cache.inflight[id]) return;
var controller = new AbortController();
cache.inflight[id] = controller;
var options = {
method: 'GET',
signal: controller.signal,
headers: { 'Content-Type': 'application/json' }
};
fetch(nextURL, options)
.then(function(response) {
if (!response.ok) {
throw new Error(response.status + ' ' + response.statusText);
}
var linkHeader = response.headers.get('Link');
if (linkHeader) {
var pagination = parsePagination(linkHeader);
if (pagination.next) {
cache.nextURL[tile.id] = pagination.next;
}
}
return response.json();
})
.then(function(data) {
cache.loaded[id] = true;
delete cache.inflight[id];
if (!data || !data.features || !data.features.length) {
throw new Error('No Data');
}
var features = data.features.map(function(feature) {
var loc = feature.geometry.coordinates;
var d;
// An image (shown as a green dot on the map) is a single street photo with extra
// information such as location, camera angle (CA), camera model, and so on.
// Each image feature is a GeoJSON Point
if (which === 'images') {
d = {
loc: loc,
key: feature.properties.key,
ca: feature.properties.ca,
captured_at: feature.properties.captured_at,
captured_by: feature.properties.username,
pano: feature.properties.pano
};
cache.forImageKey[d.key] = d; // cache imageKey -> image
// Mapillary organizes images as sequences. A sequence of images are continuously captured
// by a user at a give time. Sequences are shown on the map as green lines.
// Each sequence feature is a GeoJSON LineString
} else if (which === 'sequences') {
var sequenceKey = feature.properties.key;
cache.lineString[sequenceKey] = feature; // cache sequenceKey -> lineString
feature.properties.coordinateProperties.image_keys.forEach(function(imageKey) {
cache.forImageKey[imageKey] = sequenceKey; // cache imageKey -> sequenceKey
});
return false; // because no `d` data worth loading into an rbush
// An image detection is a semantic pixel area on an image. The area could indicate
// sky, trees, sidewalk in the image. A detection can be a polygon, a bounding box, or a point.
// Each image_detection feature is a GeoJSON Point (located where the image was taken)
} else if (which === 'image_detections') {
d = {
key: feature.properties.key,
image_key: feature.properties.image_key,
value: feature.properties.value,
package: feature.properties.package,
shape: feature.properties.shape
};
// cache imageKey -> image_detections
if (!cache.forImageKey[d.image_key]) {
cache.forImageKey[d.image_key] = [];
}
cache.forImageKey[d.image_key].push(d);
return false; // because no `d` data worth loading into an rbush
// A map feature is a real world object that can be shown on a map. It could be any object
// recognized from images, manually added in images, or added on the map.
// Each map feature is a GeoJSON Point (located where the feature is)
} else if (which === 'map_features' || which === 'points') {
d = {
loc: loc,
key: feature.properties.key,
value: feature.properties.value,
package: feature.properties.package,
detections: feature.properties.detections
};
}
return {
minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1], data: d
};
}).filter(Boolean);
if (cache.rtree && features) {
cache.rtree.load(features);
}
if (data.features.length === maxResults) { // more pages to load
cache.nextPage[tile.id] = nextPage + 1;
loadNextTilePage(which, currZoom, url, tile);
} else {
cache.nextPage[tile.id] = Infinity; // no more pages to load
}
if (which === 'images' || which === 'sequences') {
dispatch.call('loadedImages');
} else if (which === 'map_features') {
dispatch.call('loadedSigns');
} else if (which === 'points') {
dispatch.call('loadedMapFeatures');
}
})
.catch(function() {
cache.loaded[id] = true;
delete cache.inflight[id];
});
}