diff --git a/modules/behavior/draw.js b/modules/behavior/draw.js index 4122478e7..61c263a77 100644 --- a/modules/behavior/draw.js +++ b/modules/behavior/draw.js @@ -92,7 +92,7 @@ export function behaviorDraw(context) { d3_select(window).on('click.draw-block', null); }, 500); - click(); + click(d3_mouse(context.surface().node())); } }, true); } @@ -121,7 +121,7 @@ export function behaviorDraw(context) { // - `mode/drag_node.js` `doMove()` // - `behavior/draw.js` `click()` // - `behavior/draw_way.js` `move()` - function click() { + function click(loc) { var d = datum(); var target = d && d.properties && d.properties.entity; @@ -133,7 +133,7 @@ export function behaviorDraw(context) { } else if (target && target.type === 'way' && (mode.id !== 'add-point' || mode.preset.matchGeometry('vertex'))) { // Snap to a way var choice = geoChooseEdge( - context.childNodes(target), context.mouse(), context.projection, context.activeID() + context.childNodes(target), loc, context.projection, context.activeID() ); if (choice) { var edge = [target.nodes[choice.index - 1], target.nodes[choice.index]]; @@ -141,12 +141,13 @@ export function behaviorDraw(context) { return; } } else if (mode.id !== 'add-point' || mode.preset.matchGeometry('point')) { - dispatch.call('click', this, context.map().mouseCoordinates(), d); + var locLatLng = context.projection.invert(loc); + dispatch.call('click', this, locLatLng, d); } } - + // treat a spacebar press like a click function space() { d3_event.preventDefault(); d3_event.stopPropagation(); @@ -172,7 +173,11 @@ export function behaviorDraw(context) { d3_select(window).on('keyup.space-block', null); }); - click(); + // get the current mouse position + var loc = context.map().mouse() || + // or the map center if the mouse has never entered the map + context.projection(context.map().center()); + click(loc); } diff --git a/modules/behavior/draw_way.js b/modules/behavior/draw_way.js index c70252b8c..8100d25c5 100644 --- a/modules/behavior/draw_way.js +++ b/modules/behavior/draw_way.js @@ -16,30 +16,41 @@ import { utilKeybinding } from '../util'; export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselineGraph) { - var origWay = context.entity(wayID); + var _origWay = context.entity(wayID); - var annotation = t((origWay.isDegenerate() ? + var _annotation = t((_origWay.isDegenerate() ? 'operations.start.annotation.' : 'operations.continue.annotation.') + context.geometry(wayID) ); var behavior = behaviorDraw(context); - behavior.hover().initialNodeID(index ? origWay.nodes[index] : - (origWay.isClosed() ? origWay.nodes[origWay.nodes.length - 2] : origWay.nodes[origWay.nodes.length - 1])); + behavior.hover().initialNodeID(index ? _origWay.nodes[index] : + (_origWay.isClosed() ? _origWay.nodes[_origWay.nodes.length - 2] : _origWay.nodes[_origWay.nodes.length - 1])); var _tempEdits = 0; - var end = osmNode({ loc: context.map().mouseCoordinates() }); + // The osmNode to be placed. + // This is temporary and just follows the mouse cursor until an "add" event occurs. + var _drawNode; + + function createDrawNode(loc) { + // don't make the draw node until we actually need it + _drawNode = osmNode({ loc: loc }); + + context.pauseChangeDispatch(); + // Add the drawing node to the graph. + // We must make sure to remove this edit later. + context.perform(_actionAddDrawNode(_drawNode)); + _tempEdits++; + context.resumeChangeDispatch(); + + setActiveElements(); + } // Push an annotated state for undo to return back to. // We must make sure to remove this edit later. context.pauseChangeDispatch(); - context.perform(actionNoop(), annotation); - _tempEdits++; - - // Add the drawing node to the graph. - // We must make sure to remove this edit later. - context.perform(_actionAddDrawNode()); + context.perform(actionNoop(), _annotation); _tempEdits++; context.resumeChangeDispatch(); @@ -80,24 +91,28 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin // - `behavior/draw.js` `click()` // - `behavior/draw_way.js` `move()` function move(datum) { + + var loc = context.map().mouseCoordinates(); + + if (!_drawNode) createDrawNode(loc); + context.surface().classed('nope-disabled', d3_event.altKey); var targetLoc = datum && datum.properties && datum.properties.entity && allowsVertex(datum.properties.entity) && datum.properties.entity.loc; var targetNodes = datum && datum.properties && datum.properties.nodes; - var loc = context.map().mouseCoordinates(); if (targetLoc) { // snap to node/vertex - a point target with `.loc` loc = targetLoc; } else if (targetNodes) { // snap to way - a line target with `.nodes` - var choice = geoChooseEdge(targetNodes, context.mouse(), context.projection, end.id); + var choice = geoChooseEdge(targetNodes, context.mouse(), context.projection, _drawNode.id); if (choice) { loc = choice.loc; } } - context.replace(actionMoveNode(end.id, loc)); - end = context.entity(end.id); + context.replace(actionMoveNode(_drawNode.id, loc)); + _drawNode = context.entity(_drawNode.id); checkGeometry(false); } @@ -107,7 +122,7 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin // `finishDraw` - Only checks the relevant line segments if finishing drawing function checkGeometry(finishDraw) { var nopeDisabled = context.surface().classed('nope-disabled'); - var isInvalid = isInvalidGeometry(end, context.graph(), finishDraw); + var isInvalid = _drawNode ? isInvalidGeometry(_drawNode, context.graph(), finishDraw) : false; if (nopeDisabled) { context.surface() @@ -128,7 +143,7 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin var parent = parents[i]; var nodes = graph.childNodes(parent).slice(); // shallow copy - if (origWay.isClosed()) { // Check if Area + if (_origWay.isClosed()) { // Check if Area if (finishDraw) { if (nodes.length < 3) return false; nodes.splice(-2, 1); @@ -172,7 +187,9 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin function setActiveElements() { - context.surface().selectAll('.' + end.id) + if (!_drawNode) return; + + context.surface().selectAll('.' + _drawNode.id) .classed('active', true); } @@ -243,20 +260,20 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin }; - function _actionAddDrawNode() { + function _actionAddDrawNode(drawNode) { return function(graph) { return graph - .replace(end) - .replace(origWay.addNode(end.id, index)); + .replace(drawNode) + .replace(_origWay.addNode(drawNode.id, index)); }; } - function _actionReplaceDrawNode(newNode) { + function _actionReplaceDrawNode(drawNode, newNode) { return function(graph) { return graph - .replace(origWay.addNode(newNode.id, index)) - .remove(end); + .replace(_origWay.addNode(newNode.id, index)) + .remove(drawNode); }; } @@ -267,13 +284,19 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin return; // can't click here } + if (!_drawNode) createDrawNode(loc); + + // always move the node to the final loc in case move wasn't consistently called (e.g. on touch devices) + context.replace(actionMoveNode(_drawNode.id, loc)); + _drawNode = context.entity(_drawNode.id); + context.pauseChangeDispatch(); context.pop(_tempEdits); _tempEdits = 0; context.perform( - _actionAddDrawNode(), - annotation + _actionAddDrawNode(_drawNode), + _annotation ); context.resumeChangeDispatch(); @@ -288,14 +311,16 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin return; // can't click here } + if (!_drawNode) createDrawNode(); + context.pauseChangeDispatch(); context.pop(_tempEdits); _tempEdits = 0; context.perform( - _actionAddDrawNode(), - actionAddMidpoint({ loc: loc, edge: edge }, end), - annotation + _actionAddDrawNode(_drawNode), + actionAddMidpoint({ loc: loc, edge: edge }, _drawNode), + _annotation ); context.resumeChangeDispatch(); @@ -310,13 +335,15 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin return; // can't click here } + if (!_drawNode) createDrawNode(); + context.pauseChangeDispatch(); context.pop(_tempEdits); _tempEdits = 0; context.perform( - _actionReplaceDrawNode(node), - annotation + _actionReplaceDrawNode(_drawNode, node), + _annotation ); context.resumeChangeDispatch(); @@ -378,7 +405,7 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph, baselin drawWay.activeID = function() { - if (!arguments.length) return end.id; + if (!arguments.length) return _drawNode && _drawNode.id; // no assign return drawWay; };