diff --git a/src/ol/mapbrowserevent.js b/src/ol/mapbrowserevent.js index 1ed49ab7b5..49e9100e74 100644 --- a/src/ol/mapbrowserevent.js +++ b/src/ol/mapbrowserevent.js @@ -1,15 +1,8 @@ goog.provide('ol.MapBrowserEvent'); -goog.provide('ol.MapBrowserEvent.EventType'); -goog.provide('ol.MapBrowserEventHandler'); -goog.provide('ol.MapBrowserPointerEvent'); goog.require('ol'); goog.require('ol.MapEvent'); -goog.require('ol.events'); -goog.require('ol.events.EventTarget'); goog.require('ol.events.EventType'); -goog.require('ol.pointer.EventType'); -goog.require('ol.pointer.PointerEventHandler'); /** @@ -90,339 +83,6 @@ ol.MapBrowserEvent.prototype.stopPropagation = function() { }; -/** - * @constructor - * @extends {ol.MapBrowserEvent} - * @param {string} type Event type. - * @param {ol.Map} map Map. - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @param {boolean=} opt_dragging Is the map currently being dragged? - * @param {?olx.FrameState=} opt_frameState Frame state. - */ -ol.MapBrowserPointerEvent = function(type, map, pointerEvent, opt_dragging, - opt_frameState) { - - ol.MapBrowserEvent.call(this, type, map, pointerEvent.originalEvent, opt_dragging, - opt_frameState); - - /** - * @const - * @type {ol.pointer.PointerEvent} - */ - this.pointerEvent = pointerEvent; - -}; -ol.inherits(ol.MapBrowserPointerEvent, ol.MapBrowserEvent); - - -/** - * @param {ol.Map} map The map with the viewport to listen to events on. - * @constructor - * @extends {ol.events.EventTarget} - */ -ol.MapBrowserEventHandler = function(map) { - - ol.events.EventTarget.call(this); - - /** - * This is the element that we will listen to the real events on. - * @type {ol.Map} - * @private - */ - this.map_ = map; - - /** - * @type {number} - * @private - */ - this.clickTimeoutId_ = 0; - - /** - * @type {boolean} - * @private - */ - this.dragging_ = false; - - /** - * @type {!Array.} - * @private - */ - this.dragListenerKeys_ = []; - - /** - * The most recent "down" type event (or null if none have occurred). - * Set on pointerdown. - * @type {ol.pointer.PointerEvent} - * @private - */ - this.down_ = null; - - var element = this.map_.getViewport(); - - /** - * @type {number} - * @private - */ - this.activePointers_ = 0; - - /** - * @type {!Object.} - * @private - */ - this.trackedTouches_ = {}; - - /** - * Event handler which generates pointer events for - * the viewport element. - * - * @type {ol.pointer.PointerEventHandler} - * @private - */ - this.pointerEventHandler_ = new ol.pointer.PointerEventHandler(element); - - /** - * Event handler which generates pointer events for - * the document (used when dragging). - * - * @type {ol.pointer.PointerEventHandler} - * @private - */ - this.documentPointerEventHandler_ = null; - - /** - * @type {?ol.EventsKey} - * @private - */ - this.pointerdownListenerKey_ = ol.events.listen(this.pointerEventHandler_, - ol.pointer.EventType.POINTERDOWN, - this.handlePointerDown_, this); - - /** - * @type {?ol.EventsKey} - * @private - */ - this.relayedListenerKey_ = ol.events.listen(this.pointerEventHandler_, - ol.pointer.EventType.POINTERMOVE, - this.relayEvent_, this); - -}; -ol.inherits(ol.MapBrowserEventHandler, ol.events.EventTarget); - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) { - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.CLICK, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - if (this.clickTimeoutId_ !== 0) { - // double-click - clearTimeout(this.clickTimeoutId_); - this.clickTimeoutId_ = 0; - newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - } else { - // click - this.clickTimeoutId_ = setTimeout(function() { - this.clickTimeoutId_ = 0; - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - }.bind(this), 250); - } -}; - - -/** - * Keeps track on how many pointers are currently active. - * - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.updateActivePointers_ = function(pointerEvent) { - var event = pointerEvent; - - if (event.type == ol.MapBrowserEvent.EventType.POINTERUP || - event.type == ol.MapBrowserEvent.EventType.POINTERCANCEL) { - delete this.trackedTouches_[event.pointerId]; - } else if (event.type == ol.MapBrowserEvent.EventType.POINTERDOWN) { - this.trackedTouches_[event.pointerId] = true; - } - this.activePointers_ = Object.keys(this.trackedTouches_).length; -}; - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) { - this.updateActivePointers_(pointerEvent); - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.POINTERUP, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - - // We emulate click events on left mouse button click, touch contact, and pen - // contact. isMouseActionButton returns true in these cases (evt.button is set - // to 0). - // See http://www.w3.org/TR/pointerevents/#button-states - if (!this.dragging_ && this.isMouseActionButton_(pointerEvent)) { - ol.DEBUG && console.assert(this.down_, 'this.down_ must be truthy'); - this.emulateClick_(this.down_); - } - - ol.DEBUG && console.assert(this.activePointers_ >= 0, - 'this.activePointers_ should be equal to or larger than 0'); - if (this.activePointers_ === 0) { - this.dragListenerKeys_.forEach(ol.events.unlistenByKey); - this.dragListenerKeys_.length = 0; - this.dragging_ = false; - this.down_ = null; - this.documentPointerEventHandler_.dispose(); - this.documentPointerEventHandler_ = null; - } -}; - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @return {boolean} If the left mouse button was pressed. - * @private - */ -ol.MapBrowserEventHandler.prototype.isMouseActionButton_ = function(pointerEvent) { - return pointerEvent.button === 0; -}; - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent) { - this.updateActivePointers_(pointerEvent); - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.POINTERDOWN, this.map_, pointerEvent); - this.dispatchEvent(newEvent); - - this.down_ = pointerEvent; - - if (this.dragListenerKeys_.length === 0) { - /* Set up a pointer event handler on the `document`, - * which is required when the pointer is moved outside - * the viewport when dragging. - */ - this.documentPointerEventHandler_ = - new ol.pointer.PointerEventHandler(document); - - this.dragListenerKeys_.push( - ol.events.listen(this.documentPointerEventHandler_, - ol.MapBrowserEvent.EventType.POINTERMOVE, - this.handlePointerMove_, this), - ol.events.listen(this.documentPointerEventHandler_, - ol.MapBrowserEvent.EventType.POINTERUP, - this.handlePointerUp_, this), - /* Note that the listener for `pointercancel is set up on - * `pointerEventHandler_` and not `documentPointerEventHandler_` like - * the `pointerup` and `pointermove` listeners. - * - * The reason for this is the following: `TouchSource.vacuumTouches_()` - * issues `pointercancel` events, when there was no `touchend` for a - * `touchstart`. Now, let's say a first `touchstart` is registered on - * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up. - * But `documentPointerEventHandler_` doesn't know about the first - * `touchstart`. If there is no `touchend` for the `touchstart`, we can - * only receive a `touchcancel` from `pointerEventHandler_`, because it is - * only registered there. - */ - ol.events.listen(this.pointerEventHandler_, - ol.MapBrowserEvent.EventType.POINTERCANCEL, - this.handlePointerUp_, this) - ); - } -}; - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.handlePointerMove_ = function(pointerEvent) { - // Fix IE10 on windows Surface : When you tap the tablet, it triggers - // multiple pointermove events between pointerdown and pointerup with - // the exact same coordinates of the pointerdown event. To avoid a - // 'false' touchmove event to be dispatched , we test if the pointer - // effectively moved. - if (this.isMoving_(pointerEvent)) { - this.dragging_ = true; - var newEvent = new ol.MapBrowserPointerEvent( - ol.MapBrowserEvent.EventType.POINTERDRAG, this.map_, pointerEvent, - this.dragging_); - this.dispatchEvent(newEvent); - } - - // Some native android browser triggers mousemove events during small period - // of time. See: https://code.google.com/p/android/issues/detail?id=5491 or - // https://code.google.com/p/android/issues/detail?id=19827 - // ex: Galaxy Tab P3110 + Android 4.1.1 - pointerEvent.preventDefault(); -}; - - -/** - * Wrap and relay a pointer event. Note that this requires that the type - * string for the MapBrowserPointerEvent matches the PointerEvent type. - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @private - */ -ol.MapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) { - var dragging = !!(this.down_ && this.isMoving_(pointerEvent)); - this.dispatchEvent(new ol.MapBrowserPointerEvent( - pointerEvent.type, this.map_, pointerEvent, dragging)); -}; - - -/** - * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. - * @return {boolean} Is moving. - * @private - */ -ol.MapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) { - return pointerEvent.clientX != this.down_.clientX || - pointerEvent.clientY != this.down_.clientY; -}; - - -/** - * @inheritDoc - */ -ol.MapBrowserEventHandler.prototype.disposeInternal = function() { - if (this.relayedListenerKey_) { - ol.events.unlistenByKey(this.relayedListenerKey_); - this.relayedListenerKey_ = null; - } - if (this.pointerdownListenerKey_) { - ol.events.unlistenByKey(this.pointerdownListenerKey_); - this.pointerdownListenerKey_ = null; - } - - this.dragListenerKeys_.forEach(ol.events.unlistenByKey); - this.dragListenerKeys_.length = 0; - - if (this.documentPointerEventHandler_) { - this.documentPointerEventHandler_.dispose(); - this.documentPointerEventHandler_ = null; - } - if (this.pointerEventHandler_) { - this.pointerEventHandler_.dispose(); - this.pointerEventHandler_ = null; - } - ol.events.EventTarget.prototype.disposeInternal.call(this); -}; - - /** * Constants for event names. * @enum {string} diff --git a/src/ol/mapbrowsereventhandler.js b/src/ol/mapbrowsereventhandler.js new file mode 100644 index 0000000000..d3b34f9b67 --- /dev/null +++ b/src/ol/mapbrowsereventhandler.js @@ -0,0 +1,317 @@ +goog.provide('ol.MapBrowserEventHandler'); + +goog.require('ol'); +goog.require('ol.MapBrowserEvent'); +goog.require('ol.MapBrowserPointerEvent'); +goog.require('ol.events'); +goog.require('ol.events.EventTarget'); +goog.require('ol.pointer.EventType'); +goog.require('ol.pointer.PointerEventHandler'); + + +/** + * @param {ol.Map} map The map with the viewport to listen to events on. + * @constructor + * @extends {ol.events.EventTarget} + */ +ol.MapBrowserEventHandler = function(map) { + + ol.events.EventTarget.call(this); + + /** + * This is the element that we will listen to the real events on. + * @type {ol.Map} + * @private + */ + this.map_ = map; + + /** + * @type {number} + * @private + */ + this.clickTimeoutId_ = 0; + + /** + * @type {boolean} + * @private + */ + this.dragging_ = false; + + /** + * @type {!Array.} + * @private + */ + this.dragListenerKeys_ = []; + + /** + * The most recent "down" type event (or null if none have occurred). + * Set on pointerdown. + * @type {ol.pointer.PointerEvent} + * @private + */ + this.down_ = null; + + var element = this.map_.getViewport(); + + /** + * @type {number} + * @private + */ + this.activePointers_ = 0; + + /** + * @type {!Object.} + * @private + */ + this.trackedTouches_ = {}; + + /** + * Event handler which generates pointer events for + * the viewport element. + * + * @type {ol.pointer.PointerEventHandler} + * @private + */ + this.pointerEventHandler_ = new ol.pointer.PointerEventHandler(element); + + /** + * Event handler which generates pointer events for + * the document (used when dragging). + * + * @type {ol.pointer.PointerEventHandler} + * @private + */ + this.documentPointerEventHandler_ = null; + + /** + * @type {?ol.EventsKey} + * @private + */ + this.pointerdownListenerKey_ = ol.events.listen(this.pointerEventHandler_, + ol.pointer.EventType.POINTERDOWN, + this.handlePointerDown_, this); + + /** + * @type {?ol.EventsKey} + * @private + */ + this.relayedListenerKey_ = ol.events.listen(this.pointerEventHandler_, + ol.pointer.EventType.POINTERMOVE, + this.relayEvent_, this); + +}; +ol.inherits(ol.MapBrowserEventHandler, ol.events.EventTarget); + + +/** + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private + */ +ol.MapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) { + var newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.CLICK, this.map_, pointerEvent); + this.dispatchEvent(newEvent); + if (this.clickTimeoutId_ !== 0) { + // double-click + clearTimeout(this.clickTimeoutId_); + this.clickTimeoutId_ = 0; + newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, pointerEvent); + this.dispatchEvent(newEvent); + } else { + // click + this.clickTimeoutId_ = setTimeout(function() { + this.clickTimeoutId_ = 0; + var newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, pointerEvent); + this.dispatchEvent(newEvent); + }.bind(this), 250); + } +}; + + +/** + * Keeps track on how many pointers are currently active. + * + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private + */ +ol.MapBrowserEventHandler.prototype.updateActivePointers_ = function(pointerEvent) { + var event = pointerEvent; + + if (event.type == ol.MapBrowserEvent.EventType.POINTERUP || + event.type == ol.MapBrowserEvent.EventType.POINTERCANCEL) { + delete this.trackedTouches_[event.pointerId]; + } else if (event.type == ol.MapBrowserEvent.EventType.POINTERDOWN) { + this.trackedTouches_[event.pointerId] = true; + } + this.activePointers_ = Object.keys(this.trackedTouches_).length; +}; + + +/** + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private + */ +ol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) { + this.updateActivePointers_(pointerEvent); + var newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.POINTERUP, this.map_, pointerEvent); + this.dispatchEvent(newEvent); + + // We emulate click events on left mouse button click, touch contact, and pen + // contact. isMouseActionButton returns true in these cases (evt.button is set + // to 0). + // See http://www.w3.org/TR/pointerevents/#button-states + if (!this.dragging_ && this.isMouseActionButton_(pointerEvent)) { + ol.DEBUG && console.assert(this.down_, 'this.down_ must be truthy'); + this.emulateClick_(this.down_); + } + + ol.DEBUG && console.assert(this.activePointers_ >= 0, + 'this.activePointers_ should be equal to or larger than 0'); + if (this.activePointers_ === 0) { + this.dragListenerKeys_.forEach(ol.events.unlistenByKey); + this.dragListenerKeys_.length = 0; + this.dragging_ = false; + this.down_ = null; + this.documentPointerEventHandler_.dispose(); + this.documentPointerEventHandler_ = null; + } +}; + + +/** + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @return {boolean} If the left mouse button was pressed. + * @private + */ +ol.MapBrowserEventHandler.prototype.isMouseActionButton_ = function(pointerEvent) { + return pointerEvent.button === 0; +}; + + +/** + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private + */ +ol.MapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent) { + this.updateActivePointers_(pointerEvent); + var newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.POINTERDOWN, this.map_, pointerEvent); + this.dispatchEvent(newEvent); + + this.down_ = pointerEvent; + + if (this.dragListenerKeys_.length === 0) { + /* Set up a pointer event handler on the `document`, + * which is required when the pointer is moved outside + * the viewport when dragging. + */ + this.documentPointerEventHandler_ = + new ol.pointer.PointerEventHandler(document); + + this.dragListenerKeys_.push( + ol.events.listen(this.documentPointerEventHandler_, + ol.MapBrowserEvent.EventType.POINTERMOVE, + this.handlePointerMove_, this), + ol.events.listen(this.documentPointerEventHandler_, + ol.MapBrowserEvent.EventType.POINTERUP, + this.handlePointerUp_, this), + /* Note that the listener for `pointercancel is set up on + * `pointerEventHandler_` and not `documentPointerEventHandler_` like + * the `pointerup` and `pointermove` listeners. + * + * The reason for this is the following: `TouchSource.vacuumTouches_()` + * issues `pointercancel` events, when there was no `touchend` for a + * `touchstart`. Now, let's say a first `touchstart` is registered on + * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up. + * But `documentPointerEventHandler_` doesn't know about the first + * `touchstart`. If there is no `touchend` for the `touchstart`, we can + * only receive a `touchcancel` from `pointerEventHandler_`, because it is + * only registered there. + */ + ol.events.listen(this.pointerEventHandler_, + ol.MapBrowserEvent.EventType.POINTERCANCEL, + this.handlePointerUp_, this) + ); + } +}; + + +/** + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private + */ +ol.MapBrowserEventHandler.prototype.handlePointerMove_ = function(pointerEvent) { + // Fix IE10 on windows Surface : When you tap the tablet, it triggers + // multiple pointermove events between pointerdown and pointerup with + // the exact same coordinates of the pointerdown event. To avoid a + // 'false' touchmove event to be dispatched , we test if the pointer + // effectively moved. + if (this.isMoving_(pointerEvent)) { + this.dragging_ = true; + var newEvent = new ol.MapBrowserPointerEvent( + ol.MapBrowserEvent.EventType.POINTERDRAG, this.map_, pointerEvent, + this.dragging_); + this.dispatchEvent(newEvent); + } + + // Some native android browser triggers mousemove events during small period + // of time. See: https://code.google.com/p/android/issues/detail?id=5491 or + // https://code.google.com/p/android/issues/detail?id=19827 + // ex: Galaxy Tab P3110 + Android 4.1.1 + pointerEvent.preventDefault(); +}; + + +/** + * Wrap and relay a pointer event. Note that this requires that the type + * string for the MapBrowserPointerEvent matches the PointerEvent type. + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @private + */ +ol.MapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) { + var dragging = !!(this.down_ && this.isMoving_(pointerEvent)); + this.dispatchEvent(new ol.MapBrowserPointerEvent( + pointerEvent.type, this.map_, pointerEvent, dragging)); +}; + + +/** + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @return {boolean} Is moving. + * @private + */ +ol.MapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) { + return pointerEvent.clientX != this.down_.clientX || + pointerEvent.clientY != this.down_.clientY; +}; + + +/** + * @inheritDoc + */ +ol.MapBrowserEventHandler.prototype.disposeInternal = function() { + if (this.relayedListenerKey_) { + ol.events.unlistenByKey(this.relayedListenerKey_); + this.relayedListenerKey_ = null; + } + if (this.pointerdownListenerKey_) { + ol.events.unlistenByKey(this.pointerdownListenerKey_); + this.pointerdownListenerKey_ = null; + } + + this.dragListenerKeys_.forEach(ol.events.unlistenByKey); + this.dragListenerKeys_.length = 0; + + if (this.documentPointerEventHandler_) { + this.documentPointerEventHandler_.dispose(); + this.documentPointerEventHandler_ = null; + } + if (this.pointerEventHandler_) { + this.pointerEventHandler_.dispose(); + this.pointerEventHandler_ = null; + } + ol.events.EventTarget.prototype.disposeInternal.call(this); +}; diff --git a/src/ol/mapbrowserpointerevent.js b/src/ol/mapbrowserpointerevent.js new file mode 100644 index 0000000000..83b73fe8f7 --- /dev/null +++ b/src/ol/mapbrowserpointerevent.js @@ -0,0 +1,29 @@ +goog.provide('ol.MapBrowserPointerEvent'); + +goog.require('ol'); +goog.require('ol.MapBrowserEvent'); + + +/** + * @constructor + * @extends {ol.MapBrowserEvent} + * @param {string} type Event type. + * @param {ol.Map} map Map. + * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. + * @param {boolean=} opt_dragging Is the map currently being dragged? + * @param {?olx.FrameState=} opt_frameState Frame state. + */ +ol.MapBrowserPointerEvent = function(type, map, pointerEvent, opt_dragging, + opt_frameState) { + + ol.MapBrowserEvent.call(this, type, map, pointerEvent.originalEvent, opt_dragging, + opt_frameState); + + /** + * @const + * @type {ol.pointer.PointerEvent} + */ + this.pointerEvent = pointerEvent; + +}; +ol.inherits(ol.MapBrowserPointerEvent, ol.MapBrowserEvent);