mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-14 13:18:15 +02:00
Preview the draw segment upon pointerdown on touchscreens unless it becomes invalid
Block creation of invalid geometries due to connecting to invalid sibling segments or nodes on the drawn way on touchscreens
This commit is contained in:
+46
-40
@@ -17,7 +17,7 @@ var _lastSpace = null;
|
||||
|
||||
export function behaviorDraw(context) {
|
||||
var dispatch = d3_dispatch(
|
||||
'move', 'click', 'clickWay', 'clickNode', 'undo', 'cancel', 'finish'
|
||||
'move', 'down', 'downcancel', 'click', 'clickWay', 'clickNode', 'undo', 'cancel', 'finish'
|
||||
);
|
||||
|
||||
var keybinding = utilKeybinding('draw');
|
||||
@@ -32,8 +32,9 @@ export function behaviorDraw(context) {
|
||||
var _tolerance = 12;
|
||||
var _mouseLeave = false;
|
||||
var _lastMouse = null;
|
||||
var _lastPointerUpEvent;
|
||||
|
||||
var _downPointerId;
|
||||
var _downPointer;
|
||||
|
||||
// use pointer events on supported platforms; fallback to mouse events
|
||||
var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
|
||||
@@ -59,79 +60,81 @@ export function behaviorDraw(context) {
|
||||
return (d && d.properties && d.properties.target) ? d : {};
|
||||
}
|
||||
|
||||
var _lastPointerUpEvent;
|
||||
|
||||
function pointerdown() {
|
||||
|
||||
if (_downPointerId) return;
|
||||
var _downPointerId = d3_event.pointerId || 'mouse';
|
||||
if (_downPointer) return;
|
||||
|
||||
var pointerLocGetter = utilFastMouse(this);
|
||||
_downPointer = {
|
||||
id: d3_event.pointerId || 'mouse',
|
||||
pointerLocGetter: pointerLocGetter,
|
||||
downTime: +new Date(),
|
||||
downLoc: pointerLocGetter(d3_event)
|
||||
};
|
||||
|
||||
var element = d3_select(this);
|
||||
var t1 = +new Date();
|
||||
var p1 = pointerLocGetter(d3_event);
|
||||
dispatch.call('pointerdown', this, datum());
|
||||
}
|
||||
|
||||
element.on(_pointerPrefix + 'move.draw', null);
|
||||
function pointerup() {
|
||||
|
||||
d3_select(window)
|
||||
.on(_pointerPrefix + 'up.draw', pointerup, true);
|
||||
if (!_downPointer || _downPointer.id !== (d3_event.pointerId || 'mouse')) return;
|
||||
|
||||
function pointerup() {
|
||||
var downPointer = _downPointer;
|
||||
_downPointer = null;
|
||||
|
||||
if (_downPointerId !== (d3_event.pointerId || 'mouse')) return;
|
||||
_downPointerId = null;
|
||||
_lastPointerUpEvent = d3_event;
|
||||
|
||||
_lastPointerUpEvent = d3_event;
|
||||
if (downPointer.isCancelled) return;
|
||||
|
||||
element.on(_pointerPrefix + 'move.draw', pointermove);
|
||||
d3_select(window).on(_pointerPrefix + 'up.draw', null);
|
||||
var t2 = +new Date();
|
||||
var p2 = downPointer.pointerLocGetter(d3_event);
|
||||
var dist = geoVecLength(downPointer.downLoc, p2);
|
||||
|
||||
var t2 = +new Date();
|
||||
var p2 = pointerLocGetter(d3_event);
|
||||
var dist = geoVecLength(p1, p2);
|
||||
if (dist < _closeTolerance || (dist < _tolerance && (t2 - downPointer.downTime) < 500)) {
|
||||
// Prevent a quick second click
|
||||
d3_select(window).on('click.draw-block', function() {
|
||||
d3_event.stopPropagation();
|
||||
}, true);
|
||||
|
||||
if (dist < _closeTolerance || (dist < _tolerance && (t2 - t1) < 500)) {
|
||||
// Prevent a quick second click
|
||||
d3_select(window).on('click.draw-block', function() {
|
||||
d3_event.stopPropagation();
|
||||
}, true);
|
||||
context.map().dblclickZoomEnable(false);
|
||||
|
||||
context.map().dblclickZoomEnable(false);
|
||||
window.setTimeout(function() {
|
||||
context.map().dblclickZoomEnable(true);
|
||||
d3_select(window).on('click.draw-block', null);
|
||||
}, 500);
|
||||
|
||||
window.setTimeout(function() {
|
||||
context.map().dblclickZoomEnable(true);
|
||||
d3_select(window).on('click.draw-block', null);
|
||||
}, 500);
|
||||
|
||||
click(p2);
|
||||
}
|
||||
click(p2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function pointermove() {
|
||||
if (_downPointer && !_downPointer.isCancelled) {
|
||||
var p2 = _downPointer.pointerLocGetter(d3_event);
|
||||
var dist = geoVecLength(_downPointer.downLoc, p2);
|
||||
if (dist >= _closeTolerance) {
|
||||
_downPointer.isCancelled = true;
|
||||
dispatch.call('downcancel', this);
|
||||
}
|
||||
}
|
||||
|
||||
if ((d3_event.pointerType && d3_event.pointerType !== 'mouse') ||
|
||||
d3_event.buttons ||
|
||||
_downPointerId) return;
|
||||
_downPointer) return;
|
||||
|
||||
// HACK: Mobile Safari likes to send one or more `mouse` type pointermove
|
||||
// events immediately after non-mouse pointerup events; detect and ignore them.
|
||||
if (_lastPointerUpEvent &&
|
||||
_lastPointerUpEvent.pointerType !== 'mouse' &&
|
||||
geoVecLength([_lastPointerUpEvent.clientX, _lastPointerUpEvent.clientY], [d3_event.clientX, d3_event.clientY]) < 2 &&
|
||||
d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100) return;
|
||||
|
||||
_lastMouse = d3_event;
|
||||
dispatch.call('move', this, datum());
|
||||
}
|
||||
|
||||
|
||||
function mouseenter() {
|
||||
_mouseLeave = false;
|
||||
}
|
||||
|
||||
|
||||
function mouseleave() {
|
||||
_mouseLeave = true;
|
||||
}
|
||||
@@ -226,7 +229,7 @@ export function behaviorDraw(context) {
|
||||
context.install(_hover);
|
||||
context.install(_edit);
|
||||
|
||||
_downPointerId = null;
|
||||
_downPointer = null;
|
||||
|
||||
keybinding
|
||||
.on('⌫', backspace)
|
||||
@@ -242,6 +245,9 @@ export function behaviorDraw(context) {
|
||||
.on(_pointerPrefix + 'down.draw', pointerdown)
|
||||
.on(_pointerPrefix + 'move.draw', pointermove);
|
||||
|
||||
d3_select(window)
|
||||
.on(_pointerPrefix + 'up.draw', pointerup, true);
|
||||
|
||||
d3_select(document)
|
||||
.call(keybinding);
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) {
|
||||
var _headNodeID;
|
||||
var _annotation;
|
||||
|
||||
var _pointerHasMoved = false;
|
||||
|
||||
// The osmNode to be placed.
|
||||
// This is temporary and just follows the mouse cursor until an "add" event occurs.
|
||||
var _drawNode;
|
||||
@@ -244,6 +246,7 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) {
|
||||
'operations.start.annotation.' :
|
||||
'operations.continue.annotation.') + _wayGeometry
|
||||
);
|
||||
_pointerHasMoved = false;
|
||||
|
||||
// Push an annotated state for undo to return back to.
|
||||
// We must make sure to replace or remove it later.
|
||||
@@ -255,7 +258,16 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) {
|
||||
.initialNodeID(_headNodeID);
|
||||
|
||||
behavior
|
||||
.on('move', move)
|
||||
.on('move', function() {
|
||||
_pointerHasMoved = true;
|
||||
move.apply(this, arguments);
|
||||
})
|
||||
.on('down', function() {
|
||||
move.apply(this, arguments);
|
||||
})
|
||||
.on('downcancel', function() {
|
||||
if (_drawNode) removeDrawNode();
|
||||
})
|
||||
.on('click', drawWay.add)
|
||||
.on('clickWay', drawWay.addWay)
|
||||
.on('clickNode', drawWay.addNode)
|
||||
@@ -318,7 +330,6 @@ export function behaviorDrawWay(context, wayID, 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
|
||||
// consistently (e.g. on touch devices)
|
||||
@@ -326,12 +337,11 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) {
|
||||
_drawNode = context.entity(_drawNode.id);
|
||||
} else {
|
||||
createDrawNode(loc);
|
||||
didJustAddDrawNode = true;
|
||||
}
|
||||
|
||||
checkGeometry(true /* includeDrawNode */);
|
||||
if ((d && d.properties && d.properties.nope) || context.surface().classed('nope')) {
|
||||
if (didJustAddDrawNode) {
|
||||
if (!_pointerHasMoved) {
|
||||
// prevent the temporary draw node from appearing on touch devices
|
||||
removeDrawNode();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user