Implement Mapillary layer in iD

- adding a temp wikipedia icon from http://upload.wikimedia.org/wikipedia/commons/4/45/Right-facing-Arrow-icon.jpg

Making the click update and rotate an image marker on the map with comapss direction. Needs to be centered etc.

now properly enabling/disabling the different Mapillary layers upon activation/deactivation

Upgrade to faster Mapillary API

better arrow icon, refactoring to have all single-image operations in the image-layer

dist build

adding mapillary translation

adjusting image link

trying to adjust the image link for github deploy

better layout

removing font-awesome, not needed.

https for calls

consistent quotes

taking care of more translation, fix case of no images found on Mapillary

more english translations

- scoping image calls to selection.
- .inspector-wrap and .panewrap are hard to scope, since they are outside the selection, same for the #mapillary-inspector.

-scoping calls in sequences layer

adding translation

fixing jslint errors

more jshint errors

adding mapillary to tests

trying to lay out single markers, please help with the geo translation, @jfirebaugh

- adding the image layer to the active iD SVG instead of background
- add a new mode for selecting Mapillary images
- first stab of adding the image pane in the sidebar itself in order to contain the selections (needs to be layouted)

cleaning

trying to mark and keep selected image between mouseovers

refactoring to contain mapillary into the iamge mode

refactoring to contain mapillary into the iamge mode

adding to test html

cleaning up

handling unset selected image

cleanup

better sidebar

moving image into the lower right

Minor visual adjustment mapillaryImage

better no_image text and toggling of selected image

handling of text disappearing

intendation

fixing test errors

making sequences be below images

open Mapillary links in new tabs

better arrows and selectability on arrows as a workaround for real navigation in panos

more contrast for the selected image

adjusting image style

- adjusting style, removing sequence lines
- adding photos as a mode with shortcut 'm'

- fix test errors

moving switch back to right sidebar, keeping keyboard shortcut.

cleanup

file rename to avoid GIT mess with casing.

- better scoping
- removed unused hover function

- making the checkbox follow mode changes

removing unused icon

handling automatic mode exit
This commit is contained in:
Peter Neubauer
2014-08-12 11:02:28 +02:00
committed by John Firebaugh
parent 9378cd152e
commit 29dde3f217
16 changed files with 406 additions and 1 deletions
+47
View File
@@ -340,6 +340,7 @@ a.hide {
right: -100%;
}
.pane {
position:absolute;
width:50%;
@@ -716,6 +717,52 @@ a:hover .icon.out-link { background-position: -500px -14px;}
bottom: 0;
}
#mapillaryImage {
position: absolute;
right: 0;
bottom: 30px;
padding: 8px;
background-color: #fff;
}
#mapillaryImage > div {
position: relative;
}
#mapillaryImage > a {
display: block;
width: 100%;
height: auto;
color: white;
position: relative;
}
#mapillaryImage .link {
background-color: black;
position: absolute;
bottom: 0;
width: 100%;
height: 20px;
text-align: center;
}
#mapillaryImage img {
width: 100%;
heigth: auto;
display: block;
}
#mapillaryImage.hidden {
visibility: hidden;
}
#mapillaryImage .close {
cursor: pointer;
position: absolute;
right: 0;
top: 0;
background-color: #f2f2f2;
}
.feature-list-pane .inspector-body {
top: 120px;
}
+40
View File
@@ -1140,6 +1140,46 @@ text.gpx {
fill:#FF26D4;
}
/* Mapillary Sequences */
.sequence {
stroke: red;
stroke-width: 4;
fill: none;
pointer-events: visibleStroke;
}
g.image.point.hover {
stroke-opacity: 0.3;
}
g.image.point{
stroke: orange;
stroke-width: 2;
fill: none;
cursor: pointer; /* Opera */
cursor: url(img/cursor-select-mapillary.png) 6 1, pointer; /* FF */
}
g.image.point path{
stroke-width: 3;
stroke: orange;
fill: orange;
/*marker-end:url(#mapillary_direction_arrow);*/
}
g.image.point circle{
fill: orange;
fill-opacity: 0.3;
}
g.image.point.selected circle{
fill: yellow;
fill-opacity: 0.9;
}
#mapillary_direction_arrow {
fill: orange;
}
/* Modes */
.mode-draw-line .vertex.active,
+9 -1
View File
@@ -13,13 +13,15 @@ en:
description: "Add restaurants, monuments, postal boxes or other points to the map."
tail: Click on the map to add a point.
browse:
title: Browse
description: Pan and zoom the map.
draw_area:
tail: Click to add nodes to your area. Click the first node to finish the area.
draw_line:
tail: "Click to add more nodes to the line. Click on other lines to connect to them, and double-click to end the line."
selectImage:
title: Photos
description: "Choose and fix a Mapillary image for mapping. Shortcut: 'm'"
operations:
add:
annotation:
@@ -293,6 +295,12 @@ en:
drag_drop: "Drag and drop a .gpx file on the page, or click the button to the right to browse"
zoom: "Zoom to GPX track"
browse: "Browse for a .gpx file"
mapillary:
tooltip: "Mapillary street photos"
title: "Mapillary"
view_on_mapillary: "View this image on Mapillary."
no_image_found: |
No image found on <a href="http://mapillary.com/" target="_blank">Mapillary</a>. Go and take some!
help:
title: "Help"
help: |
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

+10
View File
@@ -24,6 +24,10 @@
},
"draw_line": {
"tail": "Click to add more nodes to the line. Click on other lines to connect to them, and double-click to end the line."
},
"selectImage": {
"title": "Photos",
"description": "Choose and fix a Mapillary image for mapping. Shortcut: 'm'"
}
},
"operations": {
@@ -354,6 +358,12 @@
"zoom": "Zoom to GPX track",
"browse": "Browse for a .gpx file"
},
"mapillary": {
"tooltip": "Mapillary street photos",
"title": "Mapillary",
"view_on_mapillary": "View this image on Mapillary.",
"no_image_found": "No image found on <a href=\"http://mapillary.com/\" target=\"_blank\">Mapillary</a>. Go and take some!\n"
},
"help": {
"title": "Help",
"help": "# Help\n\nThis is an editor for [OpenStreetMap](http://www.openstreetmap.org/), the\nfree and editable map of the world. You can use it to add and update\ndata in your area, making an open-source and open-data map of the world\nbetter for everyone.\n\nEdits that you make on this map will be visible to everyone who uses\nOpenStreetMap. In order to make an edit, you'll need a\n[free OpenStreetMap account](https://www.openstreetmap.org/user/new).\n\nThe [iD editor](http://ideditor.com/) is a collaborative project with [source\ncode available on GitHub](https://github.com/openstreetmap/iD).\n",
+3
View File
@@ -66,6 +66,7 @@
<script src="js/id/svg/lines.js"></script>
<script src="js/id/svg/midpoints.js"></script>
<script src="js/id/svg/points.js"></script>
<script src="js/id/svg/sequences.js"></script>
<script src="js/id/svg/surface.js"></script>
<script src="js/id/svg/tag_classes.js"></script>
<script src="js/id/svg/turns.js"></script>
@@ -76,6 +77,7 @@
<script src='js/id/ui/attribution.js'></script>
<script src='js/id/ui/radial_menu.js'></script>
<script src='js/id/ui/inspector.js'></script>
<script src='js/id/ui/image_view.js'></script>
<script src='js/id/ui/modal.js'></script>
<script src='js/id/ui/cmd.js'></script>
<script src='js/id/ui/confirm.js'></script>
@@ -188,6 +190,7 @@
<script src='js/id/modes/rotate_way.js'></script>
<script src='js/id/modes/save.js'></script>
<script src='js/id/modes/select.js'></script>
<script src='js/id/modes/select_image.js'></script>
<script src='js/id/operations.js'></script>
<script src='js/id/operations/continue.js'></script>
+7
View File
@@ -214,6 +214,13 @@ window.iD = function () {
context.zoomIn = map.zoomIn;
context.zoomOut = map.zoomOut;
/* Mapillary image view */
var imageView = iD.ui.ImageView(context);
context.imageView = function() {
return imageView;
};
context.surfaceRect = function() {
// Work around a bug in Firefox.
// http://stackoverflow.com/questions/18153989/
+100
View File
@@ -0,0 +1,100 @@
iD.modes.SelectImage = function (context) {
var mode = {
button: 'selectImage',
id: 'selectImage',
title: t('modes.selectImage.title'),
description: t('modes.selectImage.description'),
key: 'm'
}, imageView, currentImage;
var behaviors = [
];
function click() {
var datum = d3.event.target.__data__;
if (isImage(datum)) {
if (currentImage) {
context.surface().selectAll('.key_' + currentImage.properties.key)
.classed('selected', false);
}
if(currentImage === datum) {
context.surface().selectAll('.key_' + currentImage.properties.key)
.classed('selected', false);
currentImage = undefined;
} else {
currentImage = datum;
context.surface().selectAll('.key_' + currentImage.properties.key)
.classed('selected', true);
}
imageView.show(currentImage);
}
}
function isImage(datum) {
return datum !== undefined && datum && datum.properties !== undefined && datum.properties.entityType === 'image';
}
mode.enter = function () {
// console.log('selectImage.enter');
context.map().enableSequences(true);
context.container().select('#select_image_checkbox')
.attr('checked','checked');
behaviors.forEach(function (behavior) {
context.install(behavior);
});
// Get focus on the body.
if (document.activeElement && document.activeElement.blur) {
document.activeElement.blur();
}
imageView = context.imageView();
imageView.showEmpty();
context.surface()
.on('click.image', click);
context.surface()
.on('mouseover.image', function () {
var datum = d3.event.target.__data__;
if (isImage(datum)) {
imageView.show(datum);
}
})
.on('mouseout.image', function () {
var datum = d3.event.target.__data__;
if (isImage(datum)) {
if(currentImage) {
imageView.show(currentImage);
} else {
imageView.showEmpty();
}
}
});
};
mode.exit = function () {
context.map().enableSequences(false);
context.container().select('#select_image_checkbox')
.attr('checked',null);
if(!currentImage) {
context.container()
.select('#mapillaryImage')
.classed('hidden', true);
}
behaviors.forEach(function (behavior) {
context.uninstall(behavior);
});
context.surface().select('defs').selectAll('marker.arrow')
.remove();
context.surface().select('.layer-hit').selectAll('g.image')
.remove();
context.surface().select('.layer-hit').selectAll('g.sequence')
.remove();
};
return mode;
};
+6
View File
@@ -18,6 +18,7 @@ iD.Map = function(context) {
areas = iD.svg.Areas(projection),
midpoints = iD.svg.Midpoints(roundedProjection, context),
labels = iD.svg.Labels(projection, context),
sequences = iD.svg.Sequences(projection, context),
supersurface, surface,
mouse,
mousemove;
@@ -113,6 +114,7 @@ iD.Map = function(context) {
.call(vertices, graph, all, filter, map.extent(), map.zoom())
.call(lines, graph, all, filter)
.call(areas, graph, all, filter)
.call(sequences, surface)
.call(midpoints, graph, all, filter, map.trimmedExtent())
.call(labels, graph, all, filter, dimensions, !difference && !extent);
@@ -400,5 +402,9 @@ iD.Map = function(context) {
return map;
};
map.enableSequences = function (enable) {
sequences.enable(enable);
};
return d3.rebind(map, dispatch, 'on');
};
+109
View File
@@ -0,0 +1,109 @@
iD.svg.Sequences = function (projection, context) {
var surface, enabled = false;
function drawSequences(_surface) {
surface = _surface;
if (enabled) {
drawSequences.reloadMapillaryImages();
} else {
drawSequences.removeAll();
}
}
drawSequences.removeAll = function () {
var hit_layer = surface.select('.layer-hit');
if (hit_layer) {
hit_layer.selectAll('g.image').remove();
hit_layer.selectAll('g.sequence').remove();
}
};
drawSequences.enable = function (enable) {
enabled = enable;
drawSequences(surface);
};
drawSequences.plotSequences = function (surface, context, sequences) {
var imagePoints = drawSequences.images(sequences, 1000);
var images = surface.select('.layer-hit').selectAll('g.image')
.data(imagePoints);
var image = images.enter()
.append('g')
.attr('class', function (d) {
return 'image point key_' + d.properties.key;
})
.attr('transform', function (d) {
var translate = iD.svg.PointTransform(context.projection)({loc: d.geometry.coordinates});
if (d.properties.ca) {
return translate + 'rotate(' + d.properties.ca + ',0,0)';
}
return translate;
})
.on('mouseover', function (d) {
surface.select('.key_' + d.properties.key).classed('hover', true);
})
.on('mouseout', function (d) {
surface.select('.key_' + d.properties.key).classed('hover', false);
});
image.append('path')
.call(drawSequences.markerPath, 'stroke');
image.append('circle')
.attr('dx', '0')
.attr('dy', '0')
.attr('r', '10');
// Selecting the following implicitly
// sets the data (point entity) on the element
images.select('.shadow');
images.select('.stroke');
};
drawSequences.reloadMapillaryImages = function () {
var extent = context.map().extent();
d3.json('https://mapillary-read-api.herokuapp.com/v1/s/search?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) {
drawSequences.plotSequences(context.surface(), context, data);
});
};
drawSequences.images = function (sequences, limit) {
var images = [];
for (var i = 0; i < sequences.features.length; i++) {
var sequence = sequences.features[i];
for (var j = 0; j < sequence.geometry.coordinates.length; j++) {
images.push({
geometry: {
type: 'Point',
coordinates: sequence.geometry.coordinates[j]
},
properties: {
key: sequence.properties.keys[j],
ca: sequence.properties.cas[j],
entityType: 'image'
}
});
if (limit && images.length >= limit) break;
}
}
return images;
};
drawSequences.markerPath = function (selection, klass) {
selection
.attr('class', klass)
.attr('transform', 'translate(0, 0)')
.attr('d', 'M 0,-10 l 0,-20 l -5,20 l 10,0 l -5,-20');
};
return drawSequences;
};
+4
View File
@@ -31,6 +31,10 @@ iD.ui = function(context) {
var m = content.append('div')
.attr('id', 'map')
.call(map);
content.append('div')
.attr('id', 'mapillaryImage')
.classed('hidden', true)
.call(iD.ui.ImageView(context));
bar.append('div')
.attr('class', 'spacer col4');
+32
View File
@@ -312,6 +312,34 @@ iD.ui.Background = function(context) {
label.append('span')
.text(t('gpx.local_layer'));
var mapillaryLayerItem = content.append('ul')
.attr('class', 'layer-list')
.append('li')
.classed('layer-toggle-gpx', true);
var mapillaryLabel = mapillaryLayerItem.append('label')
.call(bootstrap.tooltip()
.title(t('modes.selectImage.description'))
.placement('top'));
mapillaryLabel.append('input')
.attr('type', 'checkbox')
.attr('id', 'select_image_checkbox')
.on('change', function(){
if(this.checked) {
context.enter(iD.modes.SelectImage(context));
} else {
context.enter(iD.modes.Browse(context));
}
update();
});
mapillaryLabel.append('span')
.text(t('mapillary.title'));
var adjustments = content.append('div')
.attr('class', 'adjustments');
@@ -358,6 +386,10 @@ iD.ui.Background = function(context) {
var keybinding = d3.keybinding('background');
keybinding.on(key, toggle);
keybinding.on('m', function() {
context.enter(iD.modes.SelectImage(context));
});
d3.select(document)
.call(keybinding);
+36
View File
@@ -0,0 +1,36 @@
iD.ui.ImageView = function (context) {
function imageView() {
}
imageView.showEmpty = function () {
var imageWrapper = context.container().select('#mapillaryImage');
imageWrapper.html('');
var content = imageWrapper
.append('div');
content.append('div')
.on('click', function(){
imageWrapper.classed('hidden', true);
});
content.append('div').html(marked(t('mapillary.no_image_found')));
};
imageView.show = function (imageToShow) {
var key = imageToShow.properties.key;
var imageWrapper = context.container().select('#mapillaryImage');
imageWrapper.classed('hidden', false);
imageWrapper.html('');
var content = imageWrapper
.append('div');
content.append('div')
.attr('class', 'icon close')
.on('click', function(){
imageWrapper.classed('hidden', true);
});
content.append('div').html('<div><img src="https://d1cuyjsrcm0gby.cloudfront.net/KEY/thumb-320.jpg"></img></div><a class="link" target="_blank" href="http://mapillary.com/map/im/KEY">View on Mapillary</a>'
.replace(/KEY/g, key));
};
return imageView;
};
+3
View File
@@ -60,6 +60,7 @@
<script src="../js/id/svg/areas.js"></script>
<script src="../js/id/svg/labels.js"></script>
<script src="../js/id/svg/lines.js"></script>
<script src="../js/id/svg/sequences.js"></script>
<script src="../js/id/svg/midpoints.js"></script>
<script src="../js/id/svg/points.js"></script>
<script src="../js/id/svg/surface.js"></script>
@@ -71,6 +72,7 @@
<script src='../js/id/ui/attribution.js'></script>
<script src='../js/id/ui/radial_menu.js'></script>
<script src='../js/id/ui/inspector.js'></script>
<script src='../js/id/ui/image_view.js'></script>
<script src='../js/id/ui/modal.js'></script>
<script src='../js/id/ui/cmd.js'></script>
<script src='../js/id/ui/confirm.js'></script>
@@ -164,6 +166,7 @@
<script src='../js/id/modes/draw_area.js'></script>
<script src='../js/id/modes/draw_line.js'></script>
<script src='../js/id/modes/move.js'></script>
<script src='../js/id/modes/select_image.js'></script>
<script src='../js/id/modes/rotate_way.js'></script>
<script src='../js/id/modes/select.js'></script>