iD.MapillaryLayer = function (context) { var enable = false, currentImage, svg, div, request; function show(image) { svg.selectAll('g') .classed('selected', function(d) { return currentImage && d.key === currentImage.key; }); div.classed('hidden', false) .classed('temp', image !== currentImage); div.selectAll('img') .attr('src', 'https://d1cuyjsrcm0gby.cloudfront.net/' + image.key + '/thumb-320.jpg'); div.selectAll('a') .attr('href', 'http://mapillary.com/map/im/' + image.key); } function hide() { currentImage = undefined; svg.selectAll('g') .classed('selected', false); div.classed('hidden', true); } function transform(image) { var t = 'translate(' + context.projection(image.loc) + ')'; if (image.ca) t += 'rotate(' + image.ca + ',0,0)'; return t; } function render(selection) { svg = selection.selectAll('svg') .data([0]); svg.enter().append('svg') .on('click', function() { var image = d3.event.target.__data__; if (currentImage === image) { hide(); } else { currentImage = image; show(image); } }) .on('mouseover', function() { show(d3.event.target.__data__); }) .on('mouseout', function() { if (currentImage) { show(currentImage); } else { hide(); } }); svg.style('display', enable ? 'block' : 'none'); div = context.container().selectAll('.mapillary-image') .data([0]); var enter = div.enter().append('div') .attr('class', 'mapillary-image'); enter.append('button') .on('click', hide) .append('div') .attr('class', 'icon close'); enter.append('img'); var link = enter.append('a') .attr('class', 'link') .attr('target', '_blank'); link.append('span') .attr('class', 'icon icon-pre-text out-link'); link.append('span') .text(t('mapillary.view_on_mapillary')); if (!enable) { hide(); svg.selectAll('g') .remove(); return; } // 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('https://a.mapillary.com/v2/search/s/geojson?client_id=NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzoxNjQ3MDY4ZTUxY2QzNGI2&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', function (error, data) { if (error) return; var images = []; for (var i = 0; i < data.features.length; i++) { var sequence = data.features[i]; for (var j = 0; j < sequence.geometry.coordinates.length; j++) { images.push({ key: sequence.properties.keys[j], ca: sequence.properties.cas[j], loc: sequence.geometry.coordinates[j] }); if (images.length >= 1000) break; } } var g = svg.selectAll('g') .data(images, function(d) { return d.key; }); var enter = g.enter().append('g') .attr('class', 'image'); enter.append('path') .attr('class', 'viewfield') .attr('transform', 'scale(1.5,1.5),translate(-8, -13)') .attr('d', 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z'); enter.append('circle') .attr('dx', '0') .attr('dy', '0') .attr('r', '6'); g.attr('transform', transform); g.exit() .remove(); }); } render.enable = function(_) { if (!arguments.length) return enable; enable = _; return render; }; render.dimensions = function(_) { if (!arguments.length) return svg.dimensions(); svg.dimensions(_); return render; }; return render; };