diff --git a/css/app.css b/css/app.css index 44cc8998a..096c4d1d2 100644 --- a/css/app.css +++ b/css/app.css @@ -1538,9 +1538,22 @@ input[type=number] { /* Restrictions editor */ .form-field-restrictions .preset-input-wrap { + position: relative; height: 300px; } +.form-field-restrictions .restriction-help { + z-index: 1; + position: absolute; + top: 0; + left: 0; + right: 0; + padding: 2px 6px; + background-color: rgba(255, 255, 255, .8); + color: #999; + text-align: center; +} + /* combobox dropdown */ div.combobox { diff --git a/data/core.yaml b/data/core.yaml index 048a433dc..5de2517ba 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -146,6 +146,11 @@ en: not_eligible: Lines can't be split at their beginning or end. multiple_ways: There are too many lines here to split. restriction: + help: + select: Click to select a road segment. + toggle: Click to toggle turn restrictions. + toggle_on: 'Click to add a "{restriction}" restriction.' + toggle_off: 'Click to remove the "{restriction}" restriction.' annotation: create: Added a turn restriction delete: Deleted a turn restriction diff --git a/dist/locales/en.json b/dist/locales/en.json index cd29e7272..f89e6f236 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -184,6 +184,12 @@ "multiple_ways": "There are too many lines here to split." }, "restriction": { + "help": { + "select": "Click to select a road segment.", + "toggle": "Click to toggle turn restrictions.", + "toggle_on": "Click to add a \"{restriction}\" restriction.", + "toggle_off": "Click to remove the \"{restriction}\" restriction." + }, "annotation": { "create": "Added a turn restriction", "delete": "Deleted a turn restriction" diff --git a/js/id/actions/restrict_turn.js b/js/id/actions/restrict_turn.js index 0b4ebd02f..eeefee3e6 100644 --- a/js/id/actions/restrict_turn.js +++ b/js/id/actions/restrict_turn.js @@ -62,7 +62,12 @@ iD.actions.RestrictTurn = function(turn, projection, restrictionId) { id: restrictionId, tags: { type: 'restriction', - restriction: turn.restriction || guessRestriction() + restriction: turn.restriction || + iD.geo.inferRestriction( + graph.entity(turn.from.node), + via, + graph.entity(turn.to.node), + projection) }, members: [ {id: from.id, type: 'way', role: 'from'}, @@ -70,21 +75,5 @@ iD.actions.RestrictTurn = function(turn, projection, restrictionId) { {id: to.id, type: 'way', role: 'to'} ] })); - - function guessRestriction() { - var angle = iD.geo.angle(via, graph.entity(turn.from.node), projection) - - iD.geo.angle(via, graph.entity(turn.to.node), projection); - - angle = angle * 180 / Math.PI; - - if (angle > 158 || angle < -158) - return 'no_straight_on'; - if (angle > 23) - return 'no_right_turn'; - if (angle < -22) - return 'no_left_turn'; - - return 'no_u_turn'; - } }; }; diff --git a/js/id/geo/intersection.js b/js/id/geo/intersection.js index 7d29b8f05..1451b1dd2 100644 --- a/js/id/geo/intersection.js +++ b/js/id/geo/intersection.js @@ -108,3 +108,19 @@ iD.geo.Intersection = function(graph, vertexId) { return intersection; }; + +iD.geo.inferRestriction = function(from, via, to, projection) { + var angle = iD.geo.angle(via, from, projection) - + iD.geo.angle(via, to, projection); + + angle = angle * 180 / Math.PI; + + if (angle > 158 || angle < -158) + return 'no_straight_on'; + if (angle > 23) + return 'no_right_turn'; + if (angle < -22) + return 'no_left_turn'; + + return 'no_u_turn'; +}; diff --git a/js/id/ui/preset/restrictions.js b/js/id/ui/preset/restrictions.js index c0e9b66a9..45f137f36 100644 --- a/js/id/ui/preset/restrictions.js +++ b/js/id/ui/preset/restrictions.js @@ -10,6 +10,9 @@ iD.ui.preset.restrictions = function(field, context) { var enter = wrap.enter().append('div') .attr('class', 'preset-input-wrap'); + enter.append('div') + .attr('class', 'restriction-help'); + enter.append('svg') .call(iD.svg.Surface(context)) .call(iD.behavior.Hover(context)); @@ -43,7 +46,30 @@ iD.ui.preset.restrictions = function(field, context) { .call(lines, graph, intersection.highways, filter) .call(turns, graph, intersection.turns(selectedID)); - surface.on('click.select', function() { + surface + .on('click.restrictions', click) + .on('mouseover.restrictions', mouseover) + .on('mouseout.restrictions', mouseout); + + surface + .selectAll('.selected') + .classed('selected', false); + + if (selectedID) { + surface + .selectAll('.' + selectedID) + .classed('selected', true); + } + + mouseout(); + + context.history() + .on('change.restrictions', render); + + d3.select(window) + .on('resize.restrictions', render); + + function click() { var datum = d3.event.target.__data__; if (datum instanceof iD.Entity) { selectedID = datum.id; @@ -59,23 +85,38 @@ iD.ui.preset.restrictions = function(field, context) { t('operations.restriction.annotation.create')); } } - }); - - surface - .selectAll('.selected') - .classed('selected', false); - - if (selectedID) { - surface - .selectAll('.' + selectedID) - .classed('selected', true); } - context.history() - .on('change.restrictions', render); + function mouseover() { + var datum = d3.event.target.__data__; + if (datum instanceof iD.geo.Turn) { + var graph = context.graph(), + presets = context.presets(), + preset; - d3.select(window) - .on('resize.restrictions', render); + if (datum.restriction) { + preset = presets.match(graph.entity(datum.restriction), graph); + } else { + preset = presets.item('type/restriction/' + + iD.geo.inferRestriction( + graph.entity(datum.from.node), + graph.entity(datum.via.node), + graph.entity(datum.to.node), + projection)); + } + + wrap.selectAll('.restriction-help') + .text(t('operations.restriction.help.' + + (datum.restriction ? 'toggle_off' : 'toggle_on'), + {restriction: preset.name()})); + } + } + + function mouseout() { + wrap.selectAll('.restriction-help') + .text(t('operations.restriction.help.' + + (selectedID ? 'toggle' : 'select'))); + } function render() { restrictions(selection);