move all tap hacks code into a separate handler, close #1781

This commit is contained in:
Vladimir Agafonkin 2013-06-24 18:17:25 -04:00
parent a12bd9474f
commit f9ea4758f8
5 changed files with 122 additions and 76 deletions

View File

@ -178,9 +178,10 @@ var deps = {
'dom/DomEvent.DoubleTap.js',
'dom/DomEvent.MsTouch.js',
'core/Handler.js',
'map/handler/Map.TouchZoom.js'],
'map/handler/Map.TouchZoom.js',
'map/handler/Map.Tap.js'],
deps: ['AnimationZoom'],
desc: 'Enables smooth touch zooming on iOS and IE10 and double tap on iOS/IE10/Android.'
desc: 'Enables smooth touch zoom / tap / longhold / doubletap on iOS, IE10, Android.'
},
BoxZoom: {

View File

@ -16,14 +16,12 @@ L.Draggable = L.Class.extend({
mousedown: 'mousemove',
touchstart: 'touchmove',
MSPointerDown: 'touchmove'
},
TAP_TOLERANCE: 15
}
},
initialize: function (element, dragStartTarget, longPress) {
initialize: function (element, dragStartTarget) {
this._element = element;
this._dragStartTarget = dragStartTarget || element;
this._longPress = longPress && !L.Browser.msTouch;
},
enable: function () {
@ -51,23 +49,11 @@ L.Draggable = L.Class.extend({
if (e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
L.DomEvent
.preventDefault(e)
.stopPropagation(e);
if (L.Draggable._disabled) { return; }
this._simulateClick = true;
var touchesNum = (e.touches && e.touches.length) || 0;
// don't simulate click or track longpress if more than 1 touch
if (touchesNum > 1) {
this._simulateClick = false;
clearTimeout(this._longPressTimeout);
return;
}
var first = touchesNum === 1 ? e.touches[0] : e,
var first = e.touches ? e.touches[0] : e,
el = first.target;
// if touching a link, highlight it
@ -82,20 +68,6 @@ L.Draggable = L.Class.extend({
this._startPoint = new L.Point(first.clientX, first.clientY);
this._startPos = this._newPos = L.DomUtil.getPosition(this._element);
// touch contextmenu event emulation
if (touchesNum === 1 && L.Browser.touch && this._longPress) {
this._longPressTimeout = setTimeout(L.bind(function () {
var dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0;
if (dist < L.Draggable.TAP_TOLERANCE) {
this._simulateClick = false;
this._onUp();
this._simulateEvent('contextmenu', first);
}
}, this), 1000);
}
L.DomEvent
.on(document, L.Draggable.MOVE[e.type], this._onMove, this)
.on(document, L.Draggable.END[e.type], this._onUp, this);
@ -141,33 +113,13 @@ L.Draggable = L.Class.extend({
this.fire('drag');
},
_onUp: function (e) {
var first, el, dist, simulateClickTouch, i;
clearTimeout(this._longPressTimeout);
if (this._simulateClick && e.changedTouches) {
dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0;
first = e.changedTouches[0];
el = first.target;
if (el.tagName.toLowerCase() === 'a') {
L.DomUtil.removeClass(el, 'leaflet-active');
}
// simulate click if the touch didn't move too much
if (dist < L.Draggable.TAP_TOLERANCE) {
simulateClickTouch = true;
}
}
_onUp: function () {
if (!L.Browser.touch) {
L.DomUtil.enableTextSelection();
L.DomUtil.removeClass(document.body, 'leaflet-dragging');
}
for (i in L.Draggable.MOVE) {
for (var i in L.Draggable.MOVE) {
L.DomEvent
.off(document, L.Draggable.MOVE[i], this._onMove)
.off(document, L.Draggable.END[i], this._onUp);
@ -183,22 +135,5 @@ L.Draggable = L.Class.extend({
}
this._moving = false;
if (simulateClickTouch) {
this._moved = false;
this._simulateEvent('click', first);
}
},
_simulateEvent: function (type, e) {
var simulatedEvent = document.createEvent('MouseEvents');
simulatedEvent.initMouseEvent(
type, true, true, window, 1,
e.screenX, e.screenY,
e.clientX, e.clientY,
false, false, false, false, 0, null);
e.target.dispatchEvent(simulatedEvent);
}
});

View File

@ -27,6 +27,10 @@ L.Map = L.Class.extend({
this._initLayout();
this._initEvents();
if (L.DomEvent.enableTapHacks) {
L.DomEvent.enableTapHacks(this._container);
}
if (options.maxBounds) {
this.setMaxBounds(options.maxBounds);
}
@ -674,7 +678,7 @@ L.Map = L.Class.extend({
_onMouseClick: function (e) {
// jshint camelcase: false
if (!this._loaded || (this.dragging && this.dragging.moved()) || e._leaflet_stop) { return; }
if (!this._loaded || (!e._simulated && this.dragging && this.dragging.moved()) || e._leaflet_stop) { return; }
this.fire('preclick');
this._fireMouseEvent(e);

View File

@ -11,8 +11,6 @@ L.Map.mergeOptions({
inertiaThreshold: L.Browser.touch ? 32 : 18, // ms
easeLinearity: 0.25,
longPress: true,
// TODO refactor, move to CRS
worldCopyJump: false
});
@ -22,7 +20,7 @@ L.Map.Drag = L.Handler.extend({
if (!this._draggable) {
var map = this._map;
this._draggable = new L.Draggable(map._mapPane, map._container, map.options.longPress);
this._draggable = new L.Draggable(map._mapPane, map._container);
this._draggable.on({
'dragstart': this._onDragStart,

108
src/map/handler/Map.Tap.js Normal file
View File

@ -0,0 +1,108 @@
/*
* L.Map.Tap is used to enable mobile hacks like quick taps and long hold.
*/
L.Map.mergeOptions({
tap: true,
tapTolerance: 15
});
L.Map.Tap = L.Handler.extend({
addHooks: function () {
if (!L.Browser.touch) { return; }
L.DomEvent.on(this._map._container, 'touchstart', this._onDown, this);
},
removeHooks: function () {
if (!L.Browser.touch) { return; }
L.DomEvent.off(this._map._container, 'touchstart', this._onDown, this);
},
_onDown: function (e) {
if (!e.touches) { return; }
L.DomEvent.preventDefault(e);
this._fireClick = true;
// don't simulate click or track longpress if more than 1 touch
if (e.touches.length > 1) {
this._fireClick = false;
clearTimeout(this._holdTimeout);
return;
}
var first = e.touches[0],
el = first.target;
this._startPos = this._newPos = new L.Point(first.clientX, first.clientY);
// if touching a link, highlight it
if (el.tagName.toLowerCase() === 'a') {
L.DomUtil.addClass(el, 'leaflet-active');
}
// simulate long hold but setting a timeout
if (!L.Browser.msTouch) {
this._holdTimeout = setTimeout(L.bind(function () {
if (this._isTapValid()) {
this._fireClick = false;
this._onUp();
this._simulateEvent('contextmenu', first);
}
}, this), 1000);
}
L.DomEvent
.on(document, 'touchmove', this._onMove, this)
.on(document, 'touchend', this._onUp, this);
},
_onUp: function (e) {
clearTimeout(this._holdTimeout);
L.DomEvent
.off(document, 'touchmove', this._onMove, this)
.off(document, 'touchend', this._onUp, this);
if (this._fireClick && e && e.changedTouches) {
var first = e.changedTouches[0],
el = first.target;
if (el.tagName.toLowerCase() === 'a') {
L.DomUtil.removeClass(el, 'leaflet-active');
}
// simulate click if the touch didn't move too much
if (this._isTapValid()) {
this._simulateEvent('click', first);
}
}
},
_isTapValid: function () {
return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
},
_onMove: function (e) {
var first = e.touches[0];
this._newPos = new L.Point(first.clientX, first.clientY);
},
_simulateEvent: function (type, e) {
var simulatedEvent = document.createEvent('MouseEvents');
simulatedEvent._simulated = true;
simulatedEvent.initMouseEvent(
type, true, true, window, 1,
e.screenX, e.screenY,
e.clientX, e.clientY,
false, false, false, false, 0, null);
e.target.dispatchEvent(simulatedEvent);
}
});
L.Map.addInitHook('addHandler', 'tap', L.Map.Tap);