Make the draw modes reuse their behaviorDraw when re-entering

Move click-end-node-to-finish functionality from draw modes to behaviorDraw
Fix issue where the head node would get hover-highlighted when continuing from the end of a line
This commit is contained in:
Quincy Morgan
2020-05-22 15:05:35 -04:00
parent 63aa47f02f
commit 869a0c6b89
4 changed files with 93 additions and 79 deletions
+28 -11
View File
@@ -22,15 +22,19 @@ export function behaviorDraw(context) {
var keybinding = utilKeybinding('draw');
var _hover = behaviorHover(context).altDisables(true).ignoreVertex(true)
var _hover = behaviorHover(context)
.altDisables(true)
.ignoreVertex(true)
.on('hover', context.ui().sidebar.hover);
var edit = behaviorEdit(context);
var _edit = behaviorEdit(context);
var closeTolerance = 4;
var tolerance = 12;
var _closeTolerance = 4;
var _tolerance = 12;
var _mouseLeave = false;
var _lastMouse = null;
var _downPointerId;
// use pointer events on supported platforms; fallback to mouse events
var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
@@ -58,6 +62,9 @@ export function behaviorDraw(context) {
function pointerdown() {
if (_downPointerId) return;
var _downPointerId = d3_event.pointerId || 'mouse';
var pointerLocGetter = utilFastMouse(this);
var element = d3_select(this);
@@ -67,14 +74,18 @@ export function behaviorDraw(context) {
element.on(_pointerPrefix + 'move.draw', null);
d3_select(window).on(_pointerPrefix + 'up.draw', function() {
var t2 = +new Date();
var p2 = pointerLocGetter(d3_event);
var dist = geoVecLength(p1, p2);
if (_downPointerId !== (d3_event.pointerId || 'mouse')) return;
_downPointerId = null;
element.on(_pointerPrefix + 'move.draw', pointermove);
d3_select(window).on(_pointerPrefix + 'up.draw', null);
if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
var t2 = +new Date();
var p2 = pointerLocGetter(d3_event);
var dist = geoVecLength(p1, p2);
if (dist < _closeTolerance || (dist < _tolerance && (t2 - t1) < 500)) {
// Prevent a quick second click
d3_select(window).on('click.draw-block', function() {
d3_event.stopPropagation();
@@ -94,6 +105,10 @@ export function behaviorDraw(context) {
function pointermove() {
if ((d3_event.pointerType && d3_event.pointerType !== 'mouse') ||
d3_event.buttons ||
_downPointerId) return;
_lastMouse = d3_event;
dispatch.call('move', this, datum());
}
@@ -150,7 +165,7 @@ export function behaviorDraw(context) {
var currSpace = context.map().mouse();
if (_disableSpace && _lastSpace) {
var dist = geoVecLength(_lastSpace, currSpace);
if (dist > tolerance) {
if (dist > _tolerance) {
_disableSpace = false;
}
}
@@ -196,7 +211,9 @@ export function behaviorDraw(context) {
function behavior(selection) {
context.install(_hover);
context.install(edit);
context.install(_edit);
_downPointerId = null;
keybinding
.on('⌫', backspace)
@@ -222,7 +239,7 @@ export function behaviorDraw(context) {
behavior.off = function(selection) {
context.ui().sidebar.hover.cancel();
context.uninstall(_hover);
context.uninstall(edit);
context.uninstall(_edit);
selection
.on('mouseenter.draw', null)
+53 -20
View File
@@ -18,25 +18,26 @@ import { osmNode } from '../osm/node';
import { utilRebind } from '../util/rebind';
import { utilKeybinding } from '../util';
export function behaviorDrawWay(context, wayID, index, mode, startGraph) {
export function behaviorDrawWay(context, wayID, mode, startGraph) {
var dispatch = d3_dispatch('rejectedSelfIntersection');
var _origWay = context.entity(wayID);
var _annotation = t((_origWay.isDegenerate() ?
'operations.start.annotation.' :
'operations.continue.annotation.') + _origWay.geometry(context.graph())
);
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]));
// Must be set by `drawWay.nodeIndex` before each install of this behavior.
var _nodeIndex;
var _origWay;
var _wayGeometry;
var _headNodeID;
var _annotation;
// The osmNode to be placed.
// This is temporary and just follows the mouse cursor until an "add" event occurs.
var _drawNode;
var _didResolveTempEdit = false;
function createDrawNode(loc) {
// don't make the draw node until we actually need it
_drawNode = osmNode({ loc: loc });
@@ -47,7 +48,7 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph) {
var way = graph.entity(wayID);
return graph
.replace(_drawNode)
.replace(way.addNode(_drawNode.id, index));
.replace(way.addNode(_drawNode.id, _nodeIndex));
}, _annotation);
context.resumeChangeDispatch();
@@ -70,14 +71,6 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph) {
context.resumeChangeDispatch();
}
var _didResolveTempEdit = false;
// Push an annotated state for undo to return back to.
// We must make sure to replace or remove it later.
context.pauseChangeDispatch();
context.perform(actionNoop(), _annotation);
context.resumeChangeDispatch();
function keydown() {
if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
@@ -241,6 +234,26 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph) {
var drawWay = function(surface) {
_drawNode = undefined;
_didResolveTempEdit = false;
_origWay = context.entity(wayID);
_headNodeID = typeof _nodeIndex === 'number' ? _origWay.nodes[_nodeIndex] :
(_origWay.isClosed() ? _origWay.nodes[_origWay.nodes.length - 2] : _origWay.nodes[_origWay.nodes.length - 1]);
_wayGeometry = _origWay.geometry(context.graph());
_annotation = t((_origWay.isDegenerate() ?
'operations.start.annotation.' :
'operations.continue.annotation.') + _wayGeometry
);
// Push an annotated state for undo to return back to.
// We must make sure to replace or remove it later.
context.pauseChangeDispatch();
context.perform(actionNoop(), _annotation);
context.resumeChangeDispatch();
behavior.hover()
.initialNodeID(_headNodeID);
behavior
.on('move', move)
.on('click', drawWay.add)
@@ -279,6 +292,9 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph) {
context.resumeChangeDispatch();
}
_drawNode = undefined;
_nodeIndex = undefined;
context.map()
.on('drawn.draw', null);
@@ -301,6 +317,7 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph) {
function attemptAdd(d, loc, doAdd) {
var didJustAddDrawNode = false;
if (_drawNode) {
// move the node to the final loc in case move wasn't called
@@ -353,6 +370,15 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph) {
// Connect the way to an existing node
drawWay.addNode = function(node, d) {
// finish drawing if the mapper targets the prior node
if (node.id === _headNodeID ||
// or the first node when drawing an area
(_wayGeometry === 'area' && node.id === _origWay.first())) {
drawWay.finish();
return;
}
attemptAdd(d, node.loc, function() {
context.replace(
function actionReplaceDrawNode(graph) {
@@ -363,7 +389,7 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph) {
.replace(graph.entity(wayID).removeNode(_drawNode.id))
.remove(_drawNode);
return graph
.replace(graph.entity(wayID).addNode(node.id, index));
.replace(graph.entity(wayID).addNode(node.id, _nodeIndex));
},
_annotation
);
@@ -421,6 +447,13 @@ export function behaviorDrawWay(context, wayID, index, mode, startGraph) {
};
drawWay.nodeIndex = function(val) {
if (!arguments.length) return _nodeIndex;
_nodeIndex = val;
return drawWay;
};
drawWay.activeID = function() {
if (!arguments.length) return _drawNode && _drawNode.id;
// no assign
+5 -26
View File
@@ -8,50 +8,29 @@ export function modeDrawArea(context, wayID, startGraph, button) {
id: 'draw-area'
};
var behavior;
var behavior = behaviorDrawWay(context, wayID, mode, startGraph)
.on('rejectedSelfIntersection.modeDrawArea', function() {
context.ui().flash
.text(t('self_intersection.error.areas'))();
});
mode.wayID = wayID;
mode.enter = function() {
var way = context.entity(wayID);
behavior = behaviorDrawWay(context, wayID, undefined, mode, startGraph)
.on('rejectedSelfIntersection.modeDrawArea', function() {
context.ui().flash
.text(t('self_intersection.error.areas'))();
});
var addNode = behavior.addNode;
behavior.addNode = function(node, d) {
var length = way.nodes.length;
var penultimate = length > 2 ? way.nodes[length - 2] : null;
if (node.id === way.first() || node.id === penultimate) {
behavior.finish();
} else {
addNode(node, d);
}
};
context.install(behavior);
};
mode.exit = function() {
context.uninstall(behavior);
};
mode.selectedIDs = function() {
return [wayID];
};
mode.activeID = function() {
return (behavior && behavior.activeID()) || [];
};
return mode;
}
+7 -22
View File
@@ -8,46 +8,31 @@ export function modeDrawLine(context, wayID, startGraph, button, affix, continui
id: 'draw-line'
};
var behavior;
var behavior = behaviorDrawWay(context, wayID, mode, startGraph)
.on('rejectedSelfIntersection.modeDrawLine', function() {
context.ui().flash
.text(t('self_intersection.error.lines'))();
});
mode.wayID = wayID;
mode.isContinuing = continuing;
mode.enter = function() {
var way = context.entity(wayID);
var index = (affix === 'prefix') ? 0 : undefined;
var headID = (affix === 'prefix') ? way.first() : way.last();
behavior = behaviorDrawWay(context, wayID, index, mode, startGraph)
.on('rejectedSelfIntersection.modeDrawLine', function() {
context.ui().flash
.text(t('self_intersection.error.lines'))();
});
var addNode = behavior.addNode;
behavior.addNode = function(node, d) {
if (node.id === headID) {
behavior.finish();
} else {
addNode(node, d);
}
};
behavior
.nodeIndex(affix === 'prefix' ? 0 : undefined);
context.install(behavior);
};
mode.exit = function() {
context.uninstall(behavior);
};
mode.selectedIDs = function() {
return [wayID];
};
mode.activeID = function() {
return (behavior && behavior.activeID()) || [];
};