Handle tap touch actions.
This specifically supports styli on iPads.
MODIFY
src/mapInteractor.js
src/mapInteractor.js
@@ -553,7 +553,7 @@ var mapInteractor = function (args) {
return;
}
}
- var evtType = /^(.*)(start|end|move)$/.exec(evt.type);
+ var evtType = /^(.*)(start|end|move|tap)$/.exec(evt.type);
if (!evtType || evtType.length !== 3) {
endIfBound = true;
}
@@ -603,6 +603,14 @@ var mapInteractor = function (args) {
}
m_touchHandler.lastEvent = null;
}
+ /* tap events are represented as a mouse left button down and up. */
+ if (evtType[2] === 'tap' && !m_state.boundDocumentHandlers) {
+ evt.which = 1;
+ m_touchHandler.lastEventType = null;
+ m_this._handleMouseDown(evt);
+ m_this._handleMouseUp(evt);
+ m_touchHandler.lastEventType = evtType[2];
+ }
};
/**
@@ -681,12 +689,17 @@ var mapInteractor = function (args) {
recog.push([Hammer.Pan, {direction: Hammer.DIRECTION_ALL}]);
touchEvents = touchEvents.concat(['panstart', 'panend', 'panmove']);
}
+ /* Always handle tap events. Reject double taps. */
+ recog.push([Hammer.Tap, {event: 'doubletap', taps: 2}]);
+ recog.push([Hammer.Tap, {event: 'singletap'}, undefined, ['doubletap']]);
+ touchEvents = touchEvents.concat(['singletap']);
var hammerParams = {recognizers: recog, preventDefault: true};
m_touchHandler = {
manager: new Hammer.Manager($node[0], hammerParams),
touchSupport: m_this.hasTouchSupport(),
lastTime: 0
};
+ m_touchHandler.manager.get('doubletap').recognizeWith('singletap');
touchEvents.forEach(function (touchEvent) {
m_touchHandler.manager.on(touchEvent, m_this._handleTouch);
});
@@ -923,6 +936,12 @@ var mapInteractor = function (args) {
if (m_paused) {
return;
}
+ /* In some scenarios, we get both a tap event and then, somewhat later, a
+ * set of mousedown/mouseup events. Ignore the spurious down/up set if we
+ * just handled a tap. */
+ if (m_touchHandler && m_touchHandler.lastEventType === 'tap' && (new Date()).valueOf() - m_touchHandler.lastTime < 1000) {
+ return;
+ }
m_this._getMousePosition(evt);
m_this._getMouseButton(evt);

MODIFY
tests/cases/mapInteractor.js
tests/cases/mapInteractor.js
@@ -1694,7 +1694,8 @@ describe('mapInteractor', function () {
it('Test touch interactions', function () {
var map = mockedMap('#mapNode1'),
- interactor = geo.mapInteractor({map: map});
+ interactor = geo.mapInteractor({map: map}),
+ clickTriggered = 0;
expect(interactor.hasTouchSupport()).toBe(true);
@@ -1817,6 +1818,24 @@ describe('mapInteractor', function () {
interactor.simulateEvent(
'rotateend', {touch: true, center: {x: 20, y: 20}, scale: 1.3});
expect(map.info.zoom).toBe(2);
+
+ // test tap
+ map.geoOn(geo.event.mouseclick, function () {
+ clickTriggered += 1;
+ });
+ interactor.simulateEvent(
+ 'singletap', {touch: true, center: {x: 20, y: 20}});
+ expect(clickTriggered).toBe(1);
+ // don't get a second click event from a non-tap.
+ interactor.simulateEvent(
+ 'mousedown', {map: {x: 20, y: 20}, button: 'left'});
+ interactor.simulateEvent(
+ 'mouseup', {map: {x: 20, y: 20}, button: 'left'});
+ expect(clickTriggered).toBe(1);
+ // but another tap will trigger another event
+ interactor.simulateEvent(
+ 'singletap', {touch: true, center: {x: 20, y: 20}});
+ expect(clickTriggered).toBe(2);
});
});
describe('Optional Dependencies', function () {

Handle tap touch actions.

This specifically supports styli on iPads.