mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-17 22:24:49 +02:00
Improve layer transitions, debounce redraws, other goodness
This commit is contained in:
@@ -1,28 +1,51 @@
|
||||
iD.MapillaryImageLayer = function(context) {
|
||||
var mapillary = iD.services.mapillary(),
|
||||
debouncedRedraw = _.debounce(function () { context.pan([0,0]); }, 1000),
|
||||
rtree = rbush(),
|
||||
enabled = false,
|
||||
selectedImage,
|
||||
layer;
|
||||
|
||||
|
||||
function show(image) {
|
||||
function showThumbnail(imageKey) {
|
||||
var thumb = mapillary.selectedThumbnail();
|
||||
layer.selectAll('g')
|
||||
.classed('selected', function(d) {
|
||||
return selectedImage && d.key === selectedImage.key;
|
||||
});
|
||||
.classed('selected', function(d) { return d.key === thumb; });
|
||||
|
||||
mapillary.showThumbnail(context.container(), image);
|
||||
mapillary.showThumbnail(context.container(), imageKey);
|
||||
}
|
||||
|
||||
function hide() {
|
||||
selectedImage = undefined;
|
||||
function hideThumbnail() {
|
||||
layer.selectAll('g')
|
||||
.classed('selected', false);
|
||||
|
||||
mapillary.hideThumbnail(context.container());
|
||||
}
|
||||
|
||||
function showLayer() {
|
||||
layer
|
||||
.style('display', 'block')
|
||||
.style('opacity', 0)
|
||||
.transition()
|
||||
.duration(500)
|
||||
.style('opacity', 1)
|
||||
.each('end', debouncedRedraw);
|
||||
}
|
||||
|
||||
function hideLayer() {
|
||||
debouncedRedraw.cancel();
|
||||
hideThumbnail();
|
||||
layer
|
||||
.transition()
|
||||
.duration(500)
|
||||
.style('opacity', 0)
|
||||
.each('end', function() {
|
||||
layer
|
||||
.style('display', 'none')
|
||||
.selectAll('g')
|
||||
.remove();
|
||||
});
|
||||
}
|
||||
|
||||
function transform(d) {
|
||||
var t = iD.svg.PointTransform(context.projection)(d);
|
||||
if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
|
||||
@@ -30,34 +53,36 @@ iD.MapillaryImageLayer = function(context) {
|
||||
}
|
||||
|
||||
function imagesLoaded(data) {
|
||||
if (!data.features.length) return;
|
||||
|
||||
var images = [],
|
||||
sequence, loc;
|
||||
image, loc;
|
||||
|
||||
for (var i = 0; i < data.features.length; i++) {
|
||||
sequence = data.features[i];
|
||||
for (var j = 0; j < sequence.geometry.coordinates.length; j++) {
|
||||
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: loc
|
||||
}]);
|
||||
}
|
||||
image = data.features[i];
|
||||
loc = image.geometry.coordinates;
|
||||
images.push([loc[0], loc[1], loc[0], loc[1], {
|
||||
key: image.properties.key,
|
||||
ca: image.properties.ca,
|
||||
loc: loc
|
||||
}]);
|
||||
}
|
||||
|
||||
rtree.load(images);
|
||||
debouncedRedraw();
|
||||
}
|
||||
|
||||
function update() {
|
||||
var images = rtree
|
||||
function drawMarkers() {
|
||||
var data = rtree
|
||||
.search(context.map().extent().rectangle())
|
||||
.map(function(d) { return d[4]; });
|
||||
|
||||
var g = layer.selectAll('g')
|
||||
.data(images, function(d) { return d.key; });
|
||||
var markers = layer.selectAll('g')
|
||||
.data(data, function(d) { return d.key; });
|
||||
|
||||
// Enter
|
||||
var enter = g.enter().append('g')
|
||||
var enter = markers.enter()
|
||||
.append('g')
|
||||
.attr('class', 'image');
|
||||
|
||||
enter.append('path')
|
||||
@@ -71,9 +96,11 @@ iD.MapillaryImageLayer = function(context) {
|
||||
.attr('r', '6');
|
||||
|
||||
// Update
|
||||
g.attr('transform', transform);
|
||||
markers
|
||||
.attr('transform', transform);
|
||||
|
||||
g.exit()
|
||||
// Exit
|
||||
markers.exit()
|
||||
.remove();
|
||||
}
|
||||
|
||||
@@ -85,40 +112,30 @@ iD.MapillaryImageLayer = function(context) {
|
||||
// Enter
|
||||
layer.enter()
|
||||
.append('svg')
|
||||
.on('click', function() {
|
||||
var image = d3.event.target.__data__;
|
||||
if (selectedImage === image) {
|
||||
hide();
|
||||
.style('display', enabled ? 'block' : 'none')
|
||||
.on('click', function() { // deselect/select
|
||||
var imageKey = d3.event.target.__data__.key;
|
||||
if (imageKey === mapillary.selectedThumbnail()) {
|
||||
hideThumbnail();
|
||||
} else {
|
||||
selectedImage = image;
|
||||
show(image);
|
||||
mapillary.selectedThumbnail(imageKey);
|
||||
showThumbnail(imageKey);
|
||||
}
|
||||
})
|
||||
.on('mouseover', function() {
|
||||
show(d3.event.target.__data__);
|
||||
showThumbnail(d3.event.target.__data__.key);
|
||||
})
|
||||
.on('mouseout', function() {
|
||||
if (selectedImage) {
|
||||
show(selectedImage);
|
||||
var thumb = mapillary.selectedThumbnail();
|
||||
if (thumb) {
|
||||
showThumbnail(thumb);
|
||||
} else {
|
||||
hide();
|
||||
hideThumbnail();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Update
|
||||
layer
|
||||
.style('display', enabled ? 'block' : 'none');
|
||||
|
||||
if (!enabled) {
|
||||
hide();
|
||||
layer.selectAll('g')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('opacity', 0)
|
||||
.remove();
|
||||
} else {
|
||||
update();
|
||||
if (enabled) {
|
||||
drawMarkers();
|
||||
mapillary.loadImages(context.projection, layer.dimensions());
|
||||
}
|
||||
}
|
||||
@@ -126,6 +143,11 @@ iD.MapillaryImageLayer = function(context) {
|
||||
render.enable = function(_) {
|
||||
if (!arguments.length) return enabled;
|
||||
enabled = _;
|
||||
if (enabled) {
|
||||
showLayer();
|
||||
} else {
|
||||
hideLayer();
|
||||
}
|
||||
return render;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,29 +1,54 @@
|
||||
iD.MapillarySignLayer = function(context) {
|
||||
var mapillary = iD.services.mapillary(),
|
||||
debouncedRedraw = _.debounce(function () { context.pan([0,0]); }, 1000),
|
||||
rtree = rbush(),
|
||||
enabled = false,
|
||||
selectedImage,
|
||||
layer;
|
||||
|
||||
|
||||
function show(image) {
|
||||
function showThumbnail(imageKey) {
|
||||
var thumb = mapillary.selectedThumbnail();
|
||||
layer.selectAll('.icon-sign')
|
||||
.classed('selected', function(d) {
|
||||
return selectedImage && d.key === selectedImage.key;
|
||||
});
|
||||
.classed('selected', function(d) { return d.key === thumb; });
|
||||
|
||||
mapillary.showThumbnail(context.container(), image);
|
||||
mapillary.showThumbnail(context.container(), imageKey);
|
||||
}
|
||||
|
||||
function hide() {
|
||||
selectedImage = undefined;
|
||||
function hideThumbnail() {
|
||||
layer.selectAll('.icon-sign')
|
||||
.classed('selected', false);
|
||||
|
||||
mapillary.hideThumbnail(context.container());
|
||||
}
|
||||
|
||||
function showLayer() {
|
||||
layer
|
||||
.style('display', 'block')
|
||||
.style('opacity', 0)
|
||||
.transition()
|
||||
.duration(500)
|
||||
.style('opacity', 1)
|
||||
.each('end', debouncedRedraw);
|
||||
}
|
||||
|
||||
function hideLayer() {
|
||||
debouncedRedraw.cancel();
|
||||
hideThumbnail();
|
||||
layer
|
||||
.transition()
|
||||
.duration(500)
|
||||
.style('opacity', 0)
|
||||
.each('end', function() {
|
||||
layer
|
||||
.style('display', 'none')
|
||||
.selectAll('.icon-sign')
|
||||
.remove();
|
||||
});
|
||||
}
|
||||
|
||||
function signsLoaded(data) {
|
||||
if (!data.features.length) return;
|
||||
|
||||
var signs = [],
|
||||
sign, loc;
|
||||
|
||||
@@ -38,84 +63,78 @@ iD.MapillarySignLayer = function(context) {
|
||||
}
|
||||
|
||||
rtree.load(signs);
|
||||
debouncedRedraw();
|
||||
}
|
||||
|
||||
function drawSigns() {
|
||||
var data = rtree
|
||||
.search(context.map().extent().rectangle())
|
||||
.map(function(d) { return d[4]; });
|
||||
|
||||
function update() {
|
||||
var signs = rtree
|
||||
.search(context.map().extent().rectangle())
|
||||
.map(function(d) { return d[4]; });
|
||||
|
||||
var signGroups = layer.selectAll('.mapillary-sign')
|
||||
.data(signs, function(d) { return d.key; });
|
||||
var signs = layer.select('.mapillary-sign-offset')
|
||||
.selectAll('.icon-sign')
|
||||
.data(data, function(d) { return d.key; });
|
||||
|
||||
// Enter
|
||||
var enter = signGroups.enter()
|
||||
.append('g')
|
||||
.attr('class', 'mapillary-sign')
|
||||
.attr('transform', 'translate(-15, -15)')
|
||||
signs.enter()
|
||||
.append('foreignObject')
|
||||
.attr('class', 'icon-sign')
|
||||
.append('xhtml:body')
|
||||
.html(mapillary.signHTML);
|
||||
|
||||
enter
|
||||
.on('click', function(d) {
|
||||
if (d === selectedImage) {
|
||||
hide();
|
||||
.html(mapillary.signHTML)
|
||||
.on('click', function(d) { // deselect/select
|
||||
if (d.key === mapillary.selectedThumbnail()) {
|
||||
hideThumbnail();
|
||||
} else {
|
||||
selectedImage = d;
|
||||
show(d);
|
||||
mapillary.selectedThumbnail(d.key);
|
||||
showThumbnail(d.key);
|
||||
}
|
||||
})
|
||||
.on('mouseover', show)
|
||||
.on('mouseover', function(d) {
|
||||
showThumbnail(d.key);
|
||||
})
|
||||
.on('mouseout', function() {
|
||||
if (selectedImage) {
|
||||
show(selectedImage);
|
||||
var thumb = mapillary.selectedThumbnail();
|
||||
if (thumb) {
|
||||
showThumbnail(thumb);
|
||||
} else {
|
||||
hide();
|
||||
hideThumbnail();
|
||||
}
|
||||
});
|
||||
|
||||
// Update
|
||||
signGroups
|
||||
.select('.icon-sign')
|
||||
signs
|
||||
.attr('transform', iD.svg.PointTransform(context.projection));
|
||||
|
||||
signGroups.exit()
|
||||
// Exit
|
||||
signs.exit()
|
||||
.remove();
|
||||
}
|
||||
|
||||
|
||||
function render(selection) {
|
||||
layer = selection.selectAll('svg')
|
||||
.data([0]);
|
||||
|
||||
// Enter
|
||||
layer.enter()
|
||||
.append('svg');
|
||||
.append('svg')
|
||||
.style('display', enabled ? 'block' : 'none')
|
||||
.append('g')
|
||||
.attr('class', 'mapillary-sign-offset')
|
||||
.attr('transform', 'translate(-15, -15)'); // center signs on loc
|
||||
|
||||
// Update
|
||||
layer
|
||||
.style('display', enabled ? 'block' : 'none');
|
||||
|
||||
if (!enabled) {
|
||||
hide();
|
||||
layer.selectAll('.mapillary-sign')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('opacity', 0)
|
||||
.remove();
|
||||
} else {
|
||||
update();
|
||||
if (enabled) {
|
||||
drawSigns();
|
||||
mapillary.loadSigns(context, context.projection, layer.dimensions());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render.enable = function(_) {
|
||||
if (!arguments.length) return enabled;
|
||||
enabled = _;
|
||||
if (enabled) {
|
||||
showLayer();
|
||||
} else {
|
||||
hideLayer();
|
||||
}
|
||||
return render;
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@ iD.services.mapillary = function() {
|
||||
urlImage = 'https://www.mapillary.com/map/im/',
|
||||
urlThumb = 'https://d1cuyjsrcm0gby.cloudfront.net/',
|
||||
clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi',
|
||||
tileZoom = 17;
|
||||
tileZoom = 14,
|
||||
selectedThumbnail;
|
||||
|
||||
|
||||
function loadSignDefs(context) {
|
||||
if (!iD.services.mapillary.sign_defs) {
|
||||
@@ -67,6 +69,9 @@ iD.services.mapillary = function() {
|
||||
|
||||
if (which.loaded[id] || which.inflight[id]) return;
|
||||
|
||||
var what = (which === cache.images ? 'images' : 'signs');
|
||||
console.log('requesting ' + what + ' tile ' + id);
|
||||
|
||||
which.inflight[id] = d3.json(url +
|
||||
iD.util.qsString({
|
||||
geojson: 'true',
|
||||
@@ -91,7 +96,7 @@ iD.services.mapillary = function() {
|
||||
|
||||
mapillary.loadImages = function(projection, dimensions) {
|
||||
var cache = iD.services.mapillary.cache,
|
||||
url = apibase + 'search/s/geojson?';
|
||||
url = apibase + 'search/im/geojson?';
|
||||
loadTiles(cache.images, url, projection, dimensions);
|
||||
};
|
||||
|
||||
@@ -112,8 +117,8 @@ iD.services.mapillary = function() {
|
||||
return iD.services.mapillary.sign_defs[country][type];
|
||||
};
|
||||
|
||||
mapillary.showThumbnail = function(selection, image) {
|
||||
if (!(image && image.key)) return;
|
||||
mapillary.showThumbnail = function(selection, imageKey) {
|
||||
if (!imageKey) return;
|
||||
|
||||
var thumbnail = selection.selectAll('.mapillary-image')
|
||||
.data([0]);
|
||||
@@ -123,7 +128,9 @@ iD.services.mapillary = function() {
|
||||
.attr('class', 'mapillary-image');
|
||||
|
||||
enter.append('button')
|
||||
.on('click', function () { mapillary.hideThumbnail(selection) })
|
||||
.on('click', function () {
|
||||
mapillary.hideThumbnail(selection);
|
||||
})
|
||||
.append('div')
|
||||
.call(iD.svg.Icon('#icon-close'));
|
||||
|
||||
@@ -143,14 +150,15 @@ iD.services.mapillary = function() {
|
||||
.style('opacity', 1);
|
||||
|
||||
thumbnail.selectAll('img')
|
||||
.attr('src', urlThumb + image.key + '/thumb-320.jpg');
|
||||
.attr('src', urlThumb + imageKey + '/thumb-320.jpg');
|
||||
|
||||
thumbnail.selectAll('a')
|
||||
.attr('href', urlImage + image.key);
|
||||
.attr('href', urlImage + imageKey);
|
||||
|
||||
};
|
||||
|
||||
mapillary.hideThumbnail = function(selection) {
|
||||
selectedThumbnail = null;
|
||||
selection.selectAll('.mapillary-image')
|
||||
.transition()
|
||||
.duration(200)
|
||||
@@ -158,6 +166,11 @@ iD.services.mapillary = function() {
|
||||
.remove();
|
||||
};
|
||||
|
||||
mapillary.selectedThumbnail = function(imageKey) {
|
||||
if (!arguments.length) return selectedThumbnail;
|
||||
selectedThumbnail = imageKey;
|
||||
};
|
||||
|
||||
mapillary.reset = function() {
|
||||
var cache = iD.services.mapillary.cache;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user