mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-14 21:28:11 +02:00
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:
+28
-11
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()) || [];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user