Automated class transform

npx lebab --replace src --transform class
This commit is contained in:
Tim Schaub
2018-07-16 16:18:16 -06:00
parent 60e85e7d89
commit 7b4a73f3b9
145 changed files with 32887 additions and 33714 deletions

View File

@@ -6,36 +6,37 @@
* @param {!Object.<string, function(Event)>} mapping Event mapping.
* @constructor
*/
const EventSource = function(dispatcher, mapping) {
/**
* @type {module:ol/pointer/PointerEventHandler}
*/
this.dispatcher = dispatcher;
class EventSource {
constructor(dispatcher, mapping) {
/**
* @type {module:ol/pointer/PointerEventHandler}
*/
this.dispatcher = dispatcher;
/**
* @private
* @const
* @type {!Object.<string, function(Event)>}
*/
this.mapping_ = mapping;
};
/**
* @private
* @const
* @type {!Object.<string, function(Event)>}
*/
this.mapping_ = mapping;
}
/**
* List of events supported by this source.
* @return {Array.<string>} Event names
*/
getEvents() {
return Object.keys(this.mapping_);
}
/**
* List of events supported by this source.
* @return {Array.<string>} Event names
*/
EventSource.prototype.getEvents = function() {
return Object.keys(this.mapping_);
};
/**
* Returns the handler that should handle a given event type.
* @param {string} eventType The event type.
* @return {function(Event)} Handler
*/
getHandlerForEvent(eventType) {
return this.mapping_[eventType];
}
}
/**
* Returns the handler that should handle a given event type.
* @param {string} eventType The event type.
* @return {function(Event)} Handler
*/
EventSource.prototype.getHandlerForEvent = function(eventType) {
return this.mapping_[eventType];
};
export default EventSource;

View File

@@ -39,28 +39,158 @@ import EventSource from '../pointer/EventSource.js';
* @constructor
* @extends {module:ol/pointer/EventSource}
*/
const MouseSource = function(dispatcher) {
const mapping = {
'mousedown': this.mousedown,
'mousemove': this.mousemove,
'mouseup': this.mouseup,
'mouseover': this.mouseover,
'mouseout': this.mouseout
};
EventSource.call(this, dispatcher, mapping);
class MouseSource {
constructor(dispatcher) {
const mapping = {
'mousedown': this.mousedown,
'mousemove': this.mousemove,
'mouseup': this.mouseup,
'mouseover': this.mouseover,
'mouseout': this.mouseout
};
EventSource.call(this, dispatcher, mapping);
/**
* @const
* @type {!Object.<string, Event|Object>}
*/
this.pointerMap = dispatcher.pointerMap;
/**
* @const
* @type {Array.<module:ol~Pixel>}
*/
this.lastTouches = [];
}
/**
* @const
* @type {!Object.<string, Event|Object>}
* Detect if a mouse event was simulated from a touch by
* checking if previously there was a touch event at the
* same position.
*
* FIXME - Known problem with the native Android browser on
* Samsung GT-I9100 (Android 4.1.2):
* In case the page is scrolled, this function does not work
* correctly when a canvas is used (WebGL or canvas renderer).
* Mouse listeners on canvas elements (for this browser), create
* two mouse events: One 'good' and one 'bad' one (on other browsers or
* when a div is used, there is only one event). For the 'bad' one,
* clientX/clientY and also pageX/pageY are wrong when the page
* is scrolled. Because of that, this function can not detect if
* the events were simulated from a touch event. As result, a
* pointer event at a wrong position is dispatched, which confuses
* the map interactions.
* It is unclear, how one can get the correct position for the event
* or detect that the positions are invalid.
*
* @private
* @param {MouseEvent} inEvent The in event.
* @return {boolean} True, if the event was generated by a touch.
*/
this.pointerMap = dispatcher.pointerMap;
isEventSimulatedFromTouch_(inEvent) {
const lts = this.lastTouches;
const x = inEvent.clientX;
const y = inEvent.clientY;
for (let i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
// simulated mouse events will be swallowed near a primary touchend
const dx = Math.abs(x - t[0]);
const dy = Math.abs(y - t[1]);
if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) {
return true;
}
}
return false;
}
/**
* @const
* @type {Array.<module:ol~Pixel>}
* Handler for `mousedown`.
*
* @param {MouseEvent} inEvent The in event.
*/
this.lastTouches = [];
};
mousedown(inEvent) {
if (!this.isEventSimulatedFromTouch_(inEvent)) {
// TODO(dfreedman) workaround for some elements not sending mouseup
// http://crbug/149091
if (POINTER_ID.toString() in this.pointerMap) {
this.cancel(inEvent);
}
const e = prepareEvent(inEvent, this.dispatcher);
this.pointerMap[POINTER_ID.toString()] = inEvent;
this.dispatcher.down(e, inEvent);
}
}
/**
* Handler for `mousemove`.
*
* @param {MouseEvent} inEvent The in event.
*/
mousemove(inEvent) {
if (!this.isEventSimulatedFromTouch_(inEvent)) {
const e = prepareEvent(inEvent, this.dispatcher);
this.dispatcher.move(e, inEvent);
}
}
/**
* Handler for `mouseup`.
*
* @param {MouseEvent} inEvent The in event.
*/
mouseup(inEvent) {
if (!this.isEventSimulatedFromTouch_(inEvent)) {
const p = this.pointerMap[POINTER_ID.toString()];
if (p && p.button === inEvent.button) {
const e = prepareEvent(inEvent, this.dispatcher);
this.dispatcher.up(e, inEvent);
this.cleanupMouse();
}
}
}
/**
* Handler for `mouseover`.
*
* @param {MouseEvent} inEvent The in event.
*/
mouseover(inEvent) {
if (!this.isEventSimulatedFromTouch_(inEvent)) {
const e = prepareEvent(inEvent, this.dispatcher);
this.dispatcher.enterOver(e, inEvent);
}
}
/**
* Handler for `mouseout`.
*
* @param {MouseEvent} inEvent The in event.
*/
mouseout(inEvent) {
if (!this.isEventSimulatedFromTouch_(inEvent)) {
const e = prepareEvent(inEvent, this.dispatcher);
this.dispatcher.leaveOut(e, inEvent);
}
}
/**
* Dispatches a `pointercancel` event.
*
* @param {Event} inEvent The in event.
*/
cancel(inEvent) {
const e = prepareEvent(inEvent, this.dispatcher);
this.dispatcher.cancel(e, inEvent);
this.cleanupMouse();
}
/**
* Remove the mouse from the list of active pointers.
*/
cleanupMouse() {
delete this.pointerMap[POINTER_ID.toString()];
}
}
inherits(MouseSource, EventSource);
@@ -85,46 +215,6 @@ export const POINTER_TYPE = 'mouse';
const DEDUP_DIST = 25;
/**
* Detect if a mouse event was simulated from a touch by
* checking if previously there was a touch event at the
* same position.
*
* FIXME - Known problem with the native Android browser on
* Samsung GT-I9100 (Android 4.1.2):
* In case the page is scrolled, this function does not work
* correctly when a canvas is used (WebGL or canvas renderer).
* Mouse listeners on canvas elements (for this browser), create
* two mouse events: One 'good' and one 'bad' one (on other browsers or
* when a div is used, there is only one event). For the 'bad' one,
* clientX/clientY and also pageX/pageY are wrong when the page
* is scrolled. Because of that, this function can not detect if
* the events were simulated from a touch event. As result, a
* pointer event at a wrong position is dispatched, which confuses
* the map interactions.
* It is unclear, how one can get the correct position for the event
* or detect that the positions are invalid.
*
* @private
* @param {MouseEvent} inEvent The in event.
* @return {boolean} True, if the event was generated by a touch.
*/
MouseSource.prototype.isEventSimulatedFromTouch_ = function(inEvent) {
const lts = this.lastTouches;
const x = inEvent.clientX;
const y = inEvent.clientY;
for (let i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
// simulated mouse events will be swallowed near a primary touchend
const dx = Math.abs(x - t[0]);
const dy = Math.abs(y - t[1]);
if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) {
return true;
}
}
return false;
};
/**
* Creates a copy of the original event that will be used
* for the fake pointer event.
@@ -151,98 +241,4 @@ function prepareEvent(inEvent, dispatcher) {
}
/**
* Handler for `mousedown`.
*
* @param {MouseEvent} inEvent The in event.
*/
MouseSource.prototype.mousedown = function(inEvent) {
if (!this.isEventSimulatedFromTouch_(inEvent)) {
// TODO(dfreedman) workaround for some elements not sending mouseup
// http://crbug/149091
if (POINTER_ID.toString() in this.pointerMap) {
this.cancel(inEvent);
}
const e = prepareEvent(inEvent, this.dispatcher);
this.pointerMap[POINTER_ID.toString()] = inEvent;
this.dispatcher.down(e, inEvent);
}
};
/**
* Handler for `mousemove`.
*
* @param {MouseEvent} inEvent The in event.
*/
MouseSource.prototype.mousemove = function(inEvent) {
if (!this.isEventSimulatedFromTouch_(inEvent)) {
const e = prepareEvent(inEvent, this.dispatcher);
this.dispatcher.move(e, inEvent);
}
};
/**
* Handler for `mouseup`.
*
* @param {MouseEvent} inEvent The in event.
*/
MouseSource.prototype.mouseup = function(inEvent) {
if (!this.isEventSimulatedFromTouch_(inEvent)) {
const p = this.pointerMap[POINTER_ID.toString()];
if (p && p.button === inEvent.button) {
const e = prepareEvent(inEvent, this.dispatcher);
this.dispatcher.up(e, inEvent);
this.cleanupMouse();
}
}
};
/**
* Handler for `mouseover`.
*
* @param {MouseEvent} inEvent The in event.
*/
MouseSource.prototype.mouseover = function(inEvent) {
if (!this.isEventSimulatedFromTouch_(inEvent)) {
const e = prepareEvent(inEvent, this.dispatcher);
this.dispatcher.enterOver(e, inEvent);
}
};
/**
* Handler for `mouseout`.
*
* @param {MouseEvent} inEvent The in event.
*/
MouseSource.prototype.mouseout = function(inEvent) {
if (!this.isEventSimulatedFromTouch_(inEvent)) {
const e = prepareEvent(inEvent, this.dispatcher);
this.dispatcher.leaveOut(e, inEvent);
}
};
/**
* Dispatches a `pointercancel` event.
*
* @param {Event} inEvent The in event.
*/
MouseSource.prototype.cancel = function(inEvent) {
const e = prepareEvent(inEvent, this.dispatcher);
this.dispatcher.cancel(e, inEvent);
this.cleanupMouse();
};
/**
* Remove the mouse from the list of active pointers.
*/
MouseSource.prototype.cleanupMouse = function() {
delete this.pointerMap[POINTER_ID.toString()];
};
export default MouseSource;

View File

@@ -39,25 +39,136 @@ import EventSource from '../pointer/EventSource.js';
* @constructor
* @extends {module:ol/pointer/EventSource}
*/
const MsSource = function(dispatcher) {
const mapping = {
'MSPointerDown': this.msPointerDown,
'MSPointerMove': this.msPointerMove,
'MSPointerUp': this.msPointerUp,
'MSPointerOut': this.msPointerOut,
'MSPointerOver': this.msPointerOver,
'MSPointerCancel': this.msPointerCancel,
'MSGotPointerCapture': this.msGotPointerCapture,
'MSLostPointerCapture': this.msLostPointerCapture
};
EventSource.call(this, dispatcher, mapping);
class MsSource {
constructor(dispatcher) {
const mapping = {
'MSPointerDown': this.msPointerDown,
'MSPointerMove': this.msPointerMove,
'MSPointerUp': this.msPointerUp,
'MSPointerOut': this.msPointerOut,
'MSPointerOver': this.msPointerOver,
'MSPointerCancel': this.msPointerCancel,
'MSGotPointerCapture': this.msGotPointerCapture,
'MSLostPointerCapture': this.msLostPointerCapture
};
EventSource.call(this, dispatcher, mapping);
/**
* @const
* @type {!Object.<string, MSPointerEvent|Object>}
*/
this.pointerMap = dispatcher.pointerMap;
};
/**
* @const
* @type {!Object.<string, MSPointerEvent|Object>}
*/
this.pointerMap = dispatcher.pointerMap;
}
/**
* Creates a copy of the original event that will be used
* for the fake pointer event.
*
* @private
* @param {MSPointerEvent} inEvent The in event.
* @return {Object} The copied event.
*/
prepareEvent_(inEvent) {
let e = inEvent;
if (typeof inEvent.pointerType === 'number') {
e = this.dispatcher.cloneEvent(inEvent, inEvent);
e.pointerType = POINTER_TYPES[inEvent.pointerType];
}
return e;
}
/**
* Remove this pointer from the list of active pointers.
* @param {number} pointerId Pointer identifier.
*/
cleanup(pointerId) {
delete this.pointerMap[pointerId.toString()];
}
/**
* Handler for `msPointerDown`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
msPointerDown(inEvent) {
this.pointerMap[inEvent.pointerId.toString()] = inEvent;
const e = this.prepareEvent_(inEvent);
this.dispatcher.down(e, inEvent);
}
/**
* Handler for `msPointerMove`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
msPointerMove(inEvent) {
const e = this.prepareEvent_(inEvent);
this.dispatcher.move(e, inEvent);
}
/**
* Handler for `msPointerUp`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
msPointerUp(inEvent) {
const e = this.prepareEvent_(inEvent);
this.dispatcher.up(e, inEvent);
this.cleanup(inEvent.pointerId);
}
/**
* Handler for `msPointerOut`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
msPointerOut(inEvent) {
const e = this.prepareEvent_(inEvent);
this.dispatcher.leaveOut(e, inEvent);
}
/**
* Handler for `msPointerOver`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
msPointerOver(inEvent) {
const e = this.prepareEvent_(inEvent);
this.dispatcher.enterOver(e, inEvent);
}
/**
* Handler for `msPointerCancel`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
msPointerCancel(inEvent) {
const e = this.prepareEvent_(inEvent);
this.dispatcher.cancel(e, inEvent);
this.cleanup(inEvent.pointerId);
}
/**
* Handler for `msLostPointerCapture`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
msLostPointerCapture(inEvent) {
const e = this.dispatcher.makeEvent('lostpointercapture', inEvent, inEvent);
this.dispatcher.dispatchEvent(e);
}
/**
* Handler for `msGotPointerCapture`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
msGotPointerCapture(inEvent) {
const e = this.dispatcher.makeEvent('gotpointercapture', inEvent, inEvent);
this.dispatcher.dispatchEvent(e);
}
}
inherits(MsSource, EventSource);
@@ -74,121 +185,4 @@ const POINTER_TYPES = [
];
/**
* Creates a copy of the original event that will be used
* for the fake pointer event.
*
* @private
* @param {MSPointerEvent} inEvent The in event.
* @return {Object} The copied event.
*/
MsSource.prototype.prepareEvent_ = function(inEvent) {
let e = inEvent;
if (typeof inEvent.pointerType === 'number') {
e = this.dispatcher.cloneEvent(inEvent, inEvent);
e.pointerType = POINTER_TYPES[inEvent.pointerType];
}
return e;
};
/**
* Remove this pointer from the list of active pointers.
* @param {number} pointerId Pointer identifier.
*/
MsSource.prototype.cleanup = function(pointerId) {
delete this.pointerMap[pointerId.toString()];
};
/**
* Handler for `msPointerDown`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
MsSource.prototype.msPointerDown = function(inEvent) {
this.pointerMap[inEvent.pointerId.toString()] = inEvent;
const e = this.prepareEvent_(inEvent);
this.dispatcher.down(e, inEvent);
};
/**
* Handler for `msPointerMove`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
MsSource.prototype.msPointerMove = function(inEvent) {
const e = this.prepareEvent_(inEvent);
this.dispatcher.move(e, inEvent);
};
/**
* Handler for `msPointerUp`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
MsSource.prototype.msPointerUp = function(inEvent) {
const e = this.prepareEvent_(inEvent);
this.dispatcher.up(e, inEvent);
this.cleanup(inEvent.pointerId);
};
/**
* Handler for `msPointerOut`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
MsSource.prototype.msPointerOut = function(inEvent) {
const e = this.prepareEvent_(inEvent);
this.dispatcher.leaveOut(e, inEvent);
};
/**
* Handler for `msPointerOver`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
MsSource.prototype.msPointerOver = function(inEvent) {
const e = this.prepareEvent_(inEvent);
this.dispatcher.enterOver(e, inEvent);
};
/**
* Handler for `msPointerCancel`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
MsSource.prototype.msPointerCancel = function(inEvent) {
const e = this.prepareEvent_(inEvent);
this.dispatcher.cancel(e, inEvent);
this.cleanup(inEvent.pointerId);
};
/**
* Handler for `msLostPointerCapture`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
MsSource.prototype.msLostPointerCapture = function(inEvent) {
const e = this.dispatcher.makeEvent('lostpointercapture', inEvent, inEvent);
this.dispatcher.dispatchEvent(e);
};
/**
* Handler for `msGotPointerCapture`.
*
* @param {MSPointerEvent} inEvent The in event.
*/
MsSource.prototype.msGotPointerCapture = function(inEvent) {
const e = this.dispatcher.makeEvent('gotpointercapture', inEvent, inEvent);
this.dispatcher.dispatchEvent(e);
};
export default MsSource;

View File

@@ -39,99 +39,95 @@ import EventSource from '../pointer/EventSource.js';
* @constructor
* @extends {module:ol/pointer/EventSource}
*/
const NativeSource = function(dispatcher) {
const mapping = {
'pointerdown': this.pointerDown,
'pointermove': this.pointerMove,
'pointerup': this.pointerUp,
'pointerout': this.pointerOut,
'pointerover': this.pointerOver,
'pointercancel': this.pointerCancel,
'gotpointercapture': this.gotPointerCapture,
'lostpointercapture': this.lostPointerCapture
};
EventSource.call(this, dispatcher, mapping);
};
class NativeSource {
constructor(dispatcher) {
const mapping = {
'pointerdown': this.pointerDown,
'pointermove': this.pointerMove,
'pointerup': this.pointerUp,
'pointerout': this.pointerOut,
'pointerover': this.pointerOver,
'pointercancel': this.pointerCancel,
'gotpointercapture': this.gotPointerCapture,
'lostpointercapture': this.lostPointerCapture
};
EventSource.call(this, dispatcher, mapping);
}
/**
* Handler for `pointerdown`.
*
* @param {Event} inEvent The in event.
*/
pointerDown(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
}
/**
* Handler for `pointermove`.
*
* @param {Event} inEvent The in event.
*/
pointerMove(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
}
/**
* Handler for `pointerup`.
*
* @param {Event} inEvent The in event.
*/
pointerUp(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
}
/**
* Handler for `pointerout`.
*
* @param {Event} inEvent The in event.
*/
pointerOut(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
}
/**
* Handler for `pointerover`.
*
* @param {Event} inEvent The in event.
*/
pointerOver(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
}
/**
* Handler for `pointercancel`.
*
* @param {Event} inEvent The in event.
*/
pointerCancel(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
}
/**
* Handler for `lostpointercapture`.
*
* @param {Event} inEvent The in event.
*/
lostPointerCapture(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
}
/**
* Handler for `gotpointercapture`.
*
* @param {Event} inEvent The in event.
*/
gotPointerCapture(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
}
}
inherits(NativeSource, EventSource);
/**
* Handler for `pointerdown`.
*
* @param {Event} inEvent The in event.
*/
NativeSource.prototype.pointerDown = function(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
};
/**
* Handler for `pointermove`.
*
* @param {Event} inEvent The in event.
*/
NativeSource.prototype.pointerMove = function(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
};
/**
* Handler for `pointerup`.
*
* @param {Event} inEvent The in event.
*/
NativeSource.prototype.pointerUp = function(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
};
/**
* Handler for `pointerout`.
*
* @param {Event} inEvent The in event.
*/
NativeSource.prototype.pointerOut = function(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
};
/**
* Handler for `pointerover`.
*
* @param {Event} inEvent The in event.
*/
NativeSource.prototype.pointerOver = function(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
};
/**
* Handler for `pointercancel`.
*
* @param {Event} inEvent The in event.
*/
NativeSource.prototype.pointerCancel = function(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
};
/**
* Handler for `lostpointercapture`.
*
* @param {Event} inEvent The in event.
*/
NativeSource.prototype.lostPointerCapture = function(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
};
/**
* Handler for `gotpointercapture`.
*
* @param {Event} inEvent The in event.
*/
NativeSource.prototype.gotPointerCapture = function(inEvent) {
this.dispatcher.fireNativeEvent(inEvent);
};
export default NativeSource;

View File

@@ -47,150 +47,211 @@ import Event from '../events/Event.js';
* @param {Object.<string, ?>=} opt_eventDict An optional dictionary of
* initial event properties.
*/
const PointerEvent = function(type, originalEvent, opt_eventDict) {
Event.call(this, type);
class PointerEvent {
constructor(type, originalEvent, opt_eventDict) {
Event.call(this, type);
/**
* @const
* @type {Event}
*/
this.originalEvent = originalEvent;
/**
* @const
* @type {Event}
*/
this.originalEvent = originalEvent;
const eventDict = opt_eventDict ? opt_eventDict : {};
const eventDict = opt_eventDict ? opt_eventDict : {};
/**
* @type {number}
*/
this.buttons = this.getButtons_(eventDict);
/**
* @type {number}
*/
this.buttons = this.getButtons_(eventDict);
/**
* @type {number}
*/
this.pressure = this.getPressure_(eventDict, this.buttons);
/**
* @type {number}
*/
this.pressure = this.getPressure_(eventDict, this.buttons);
// MouseEvent related properties
// MouseEvent related properties
/**
* @type {boolean}
*/
this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false;
/**
* @type {boolean}
*/
this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false;
/**
* @type {boolean}
*/
this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false;
/**
* @type {boolean}
*/
this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false;
/**
* @type {Object}
*/
this.view = 'view' in eventDict ? eventDict['view'] : null;
/**
* @type {Object}
*/
this.view = 'view' in eventDict ? eventDict['view'] : null;
/**
* @type {number}
*/
this.detail = 'detail' in eventDict ? eventDict['detail'] : null;
/**
* @type {number}
*/
this.detail = 'detail' in eventDict ? eventDict['detail'] : null;
/**
* @type {number}
*/
this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0;
/**
* @type {number}
*/
this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0;
/**
* @type {number}
*/
this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0;
/**
* @type {number}
*/
this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0;
/**
* @type {number}
*/
this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0;
/**
* @type {number}
*/
this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0;
/**
* @type {number}
*/
this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0;
/**
* @type {number}
*/
this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0;
/**
* @type {boolean}
*/
this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false;
/**
* @type {boolean}
*/
this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false;
/**
* @type {boolean}
*/
this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false;
/**
* @type {boolean}
*/
this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false;
/**
* @type {boolean}
*/
this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false;
/**
* @type {boolean}
*/
this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false;
/**
* @type {boolean}
*/
this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false;
/**
* @type {boolean}
*/
this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false;
/**
* @type {number}
*/
this.button = 'button' in eventDict ? eventDict['button'] : 0;
/**
* @type {number}
*/
this.button = 'button' in eventDict ? eventDict['button'] : 0;
/**
* @type {Node}
*/
this.relatedTarget = 'relatedTarget' in eventDict ?
eventDict['relatedTarget'] : null;
/**
* @type {Node}
*/
this.relatedTarget = 'relatedTarget' in eventDict ?
eventDict['relatedTarget'] : null;
// PointerEvent related properties
// PointerEvent related properties
/**
* @const
* @type {number}
*/
this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0;
/**
* @const
* @type {number}
*/
this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0;
/**
* @type {number}
*/
this.width = 'width' in eventDict ? eventDict['width'] : 0;
/**
* @type {number}
*/
this.width = 'width' in eventDict ? eventDict['width'] : 0;
/**
* @type {number}
*/
this.height = 'height' in eventDict ? eventDict['height'] : 0;
/**
* @type {number}
*/
this.height = 'height' in eventDict ? eventDict['height'] : 0;
/**
* @type {number}
*/
this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0;
/**
* @type {number}
*/
this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0;
/**
* @type {number}
*/
this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0;
/**
* @type {number}
*/
this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0;
/**
* @type {string}
*/
this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : '';
/**
* @type {string}
*/
this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : '';
/**
* @type {number}
*/
this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0;
/**
* @type {number}
*/
this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0;
/**
* @type {boolean}
*/
this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false;
/**
* @type {boolean}
*/
this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false;
// keep the semantics of preventDefault
if (originalEvent.preventDefault) {
this.preventDefault = function() {
originalEvent.preventDefault();
};
}
};
// keep the semantics of preventDefault
if (originalEvent.preventDefault) {
this.preventDefault = function() {
originalEvent.preventDefault();
};
}
}
/**
* @private
* @param {Object.<string, ?>} eventDict The event dictionary.
* @return {number} Button indicator.
*/
getButtons_(eventDict) {
// According to the w3c spec,
// http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button
// MouseEvent.button == 0 can mean either no mouse button depressed, or the
// left mouse button depressed.
//
// As of now, the only way to distinguish between the two states of
// MouseEvent.button is by using the deprecated MouseEvent.which property, as
// this maps mouse buttons to positive integers > 0, and uses 0 to mean that
// no mouse button is held.
//
// MouseEvent.which is derived from MouseEvent.button at MouseEvent creation,
// but initMouseEvent does not expose an argument with which to set
// MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set
// MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations
// of app developers.
//
// The only way to propagate the correct state of MouseEvent.which and
// MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0
// is to call initMouseEvent with a buttonArg value of -1.
//
// This is fixed with DOM Level 4's use of buttons
let buttons;
if (eventDict.buttons || HAS_BUTTONS) {
buttons = eventDict.buttons;
} else {
switch (eventDict.which) {
case 1: buttons = 1; break;
case 2: buttons = 4; break;
case 3: buttons = 2; break;
default: buttons = 0;
}
}
return buttons;
}
/**
* @private
* @param {Object.<string, ?>} eventDict The event dictionary.
* @param {number} buttons Button indicator.
* @return {number} The pressure.
*/
getPressure_(eventDict, buttons) {
// Spec requires that pointers without pressure specified use 0.5 for down
// state and 0 for up state.
let pressure = 0;
if (eventDict.pressure) {
pressure = eventDict.pressure;
} else {
pressure = buttons ? 0.5 : 0;
}
return pressure;
}
}
inherits(PointerEvent, Event);
@@ -202,67 +263,6 @@ inherits(PointerEvent, Event);
let HAS_BUTTONS = false;
/**
* @private
* @param {Object.<string, ?>} eventDict The event dictionary.
* @return {number} Button indicator.
*/
PointerEvent.prototype.getButtons_ = function(eventDict) {
// According to the w3c spec,
// http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button
// MouseEvent.button == 0 can mean either no mouse button depressed, or the
// left mouse button depressed.
//
// As of now, the only way to distinguish between the two states of
// MouseEvent.button is by using the deprecated MouseEvent.which property, as
// this maps mouse buttons to positive integers > 0, and uses 0 to mean that
// no mouse button is held.
//
// MouseEvent.which is derived from MouseEvent.button at MouseEvent creation,
// but initMouseEvent does not expose an argument with which to set
// MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set
// MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations
// of app developers.
//
// The only way to propagate the correct state of MouseEvent.which and
// MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0
// is to call initMouseEvent with a buttonArg value of -1.
//
// This is fixed with DOM Level 4's use of buttons
let buttons;
if (eventDict.buttons || HAS_BUTTONS) {
buttons = eventDict.buttons;
} else {
switch (eventDict.which) {
case 1: buttons = 1; break;
case 2: buttons = 4; break;
case 3: buttons = 2; break;
default: buttons = 0;
}
}
return buttons;
};
/**
* @private
* @param {Object.<string, ?>} eventDict The event dictionary.
* @param {number} buttons Button indicator.
* @return {number} The pressure.
*/
PointerEvent.prototype.getPressure_ = function(eventDict, buttons) {
// Spec requires that pointers without pressure specified use 0.5 for down
// state and 0 for up state.
let pressure = 0;
if (eventDict.pressure) {
pressure = eventDict.pressure;
} else {
pressure = buttons ? 0.5 : 0;
}
return pressure;
};
/**
* Checks if the `buttons` property is supported.
*/

View File

@@ -47,36 +47,333 @@ import TouchSource from '../pointer/TouchSource.js';
* @extends {module:ol/events/EventTarget}
* @param {Element|HTMLDocument} element Viewport element.
*/
const PointerEventHandler = function(element) {
EventTarget.call(this);
class PointerEventHandler {
constructor(element) {
EventTarget.call(this);
/**
* @const
* @private
* @type {Element|HTMLDocument}
*/
this.element_ = element;
/**
* @const
* @type {!Object.<string, Event|Object>}
*/
this.pointerMap = {};
/**
* @type {Object.<string, function(Event)>}
* @private
*/
this.eventMap_ = {};
/**
* @type {Array.<module:ol/pointer/EventSource>}
* @private
*/
this.eventSourceList_ = [];
this.registerSources();
}
/**
* @const
* @private
* @type {Element|HTMLDocument}
* Set up the event sources (mouse, touch and native pointers)
* that generate pointer events.
*/
this.element_ = element;
registerSources() {
if (POINTER) {
this.registerSource('native', new NativeSource(this));
} else if (MSPOINTER) {
this.registerSource('ms', new MsSource(this));
} else {
const mouseSource = new MouseSource(this);
this.registerSource('mouse', mouseSource);
if (TOUCH) {
this.registerSource('touch', new TouchSource(this, mouseSource));
}
}
// register events on the viewport element
this.register_();
}
/**
* @const
* @type {!Object.<string, Event|Object>}
* Add a new event source that will generate pointer events.
*
* @param {string} name A name for the event source
* @param {module:ol/pointer/EventSource} source The source event.
*/
this.pointerMap = {};
registerSource(name, source) {
const s = source;
const newEvents = s.getEvents();
if (newEvents) {
newEvents.forEach(function(e) {
const handler = s.getHandlerForEvent(e);
if (handler) {
this.eventMap_[e] = handler.bind(s);
}
}.bind(this));
this.eventSourceList_.push(s);
}
}
/**
* @type {Object.<string, function(Event)>}
* Set up the events for all registered event sources.
* @private
*/
this.eventMap_ = {};
register_() {
const l = this.eventSourceList_.length;
for (let i = 0; i < l; i++) {
const eventSource = this.eventSourceList_[i];
this.addEvents_(eventSource.getEvents());
}
}
/**
* @type {Array.<module:ol/pointer/EventSource>}
* Remove all registered events.
* @private
*/
this.eventSourceList_ = [];
unregister_() {
const l = this.eventSourceList_.length;
for (let i = 0; i < l; i++) {
const eventSource = this.eventSourceList_[i];
this.removeEvents_(eventSource.getEvents());
}
}
this.registerSources();
};
/**
* Calls the right handler for a new event.
* @private
* @param {Event} inEvent Browser event.
*/
eventHandler_(inEvent) {
const type = inEvent.type;
const handler = this.eventMap_[type];
if (handler) {
handler(inEvent);
}
}
/**
* Setup listeners for the given events.
* @private
* @param {Array.<string>} events List of events.
*/
addEvents_(events) {
events.forEach(function(eventName) {
listen(this.element_, eventName, this.eventHandler_, this);
}.bind(this));
}
/**
* Unregister listeners for the given events.
* @private
* @param {Array.<string>} events List of events.
*/
removeEvents_(events) {
events.forEach(function(e) {
unlisten(this.element_, e, this.eventHandler_, this);
}.bind(this));
}
/**
* Returns a snapshot of inEvent, with writable properties.
*
* @param {Event} event Browser event.
* @param {Event|Touch} inEvent An event that contains
* properties to copy.
* @return {Object} An object containing shallow copies of
* `inEvent`'s properties.
*/
cloneEvent(event, inEvent) {
const eventCopy = {};
for (let i = 0, ii = CLONE_PROPS.length; i < ii; i++) {
const p = CLONE_PROPS[i][0];
eventCopy[p] = event[p] || inEvent[p] || CLONE_PROPS[i][1];
}
return eventCopy;
}
// EVENTS
/**
* Triggers a 'pointerdown' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
down(data, event) {
this.fireEvent(PointerEventType.POINTERDOWN, data, event);
}
/**
* Triggers a 'pointermove' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
move(data, event) {
this.fireEvent(PointerEventType.POINTERMOVE, data, event);
}
/**
* Triggers a 'pointerup' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
up(data, event) {
this.fireEvent(PointerEventType.POINTERUP, data, event);
}
/**
* Triggers a 'pointerenter' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
enter(data, event) {
data.bubbles = false;
this.fireEvent(PointerEventType.POINTERENTER, data, event);
}
/**
* Triggers a 'pointerleave' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
leave(data, event) {
data.bubbles = false;
this.fireEvent(PointerEventType.POINTERLEAVE, data, event);
}
/**
* Triggers a 'pointerover' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
over(data, event) {
data.bubbles = true;
this.fireEvent(PointerEventType.POINTEROVER, data, event);
}
/**
* Triggers a 'pointerout' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
out(data, event) {
data.bubbles = true;
this.fireEvent(PointerEventType.POINTEROUT, data, event);
}
/**
* Triggers a 'pointercancel' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
cancel(data, event) {
this.fireEvent(PointerEventType.POINTERCANCEL, data, event);
}
/**
* Triggers a combination of 'pointerout' and 'pointerleave' events.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
leaveOut(data, event) {
this.out(data, event);
if (!this.contains_(data.target, data.relatedTarget)) {
this.leave(data, event);
}
}
/**
* Triggers a combination of 'pointerover' and 'pointerevents' events.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
enterOver(data, event) {
this.over(data, event);
if (!this.contains_(data.target, data.relatedTarget)) {
this.enter(data, event);
}
}
/**
* @private
* @param {Element} container The container element.
* @param {Element} contained The contained element.
* @return {boolean} Returns true if the container element
* contains the other element.
*/
contains_(container, contained) {
if (!container || !contained) {
return false;
}
return container.contains(contained);
}
// EVENT CREATION AND TRACKING
/**
* Creates a new Event of type `inType`, based on the information in
* `data`.
*
* @param {string} inType A string representing the type of event to create.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
* @return {module:ol/pointer/PointerEvent} A PointerEvent of type `inType`.
*/
makeEvent(inType, data, event) {
return new PointerEvent(inType, event, data);
}
/**
* Make and dispatch an event in one call.
* @param {string} inType A string representing the type of event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
fireEvent(inType, data, event) {
const e = this.makeEvent(inType, data, event);
this.dispatchEvent(e);
}
/**
* Creates a pointer event from a native pointer event
* and dispatches this event.
* @param {Event} event A platform event with a target.
*/
fireNativeEvent(event) {
const e = this.makeEvent(event.type, event, event);
this.dispatchEvent(e);
}
/**
* Wrap a native mouse event into a pointer event.
* This proxy method is required for the legacy IE support.
* @param {string} eventType The pointer event type.
* @param {Event} event The event.
* @return {module:ol/pointer/PointerEvent} The wrapped event.
*/
wrapMouseEvent(eventType, event) {
const pointerEvent = this.makeEvent(
eventType, MouseSource.prepareEvent(event, this), event);
return pointerEvent;
}
/**
* @inheritDoc
*/
disposeInternal() {
this.unregister_();
EventTarget.prototype.disposeInternal.call(this);
}
}
inherits(PointerEventHandler, EventTarget);
@@ -120,323 +417,4 @@ const CLONE_PROPS = [
];
/**
* Set up the event sources (mouse, touch and native pointers)
* that generate pointer events.
*/
PointerEventHandler.prototype.registerSources = function() {
if (POINTER) {
this.registerSource('native', new NativeSource(this));
} else if (MSPOINTER) {
this.registerSource('ms', new MsSource(this));
} else {
const mouseSource = new MouseSource(this);
this.registerSource('mouse', mouseSource);
if (TOUCH) {
this.registerSource('touch', new TouchSource(this, mouseSource));
}
}
// register events on the viewport element
this.register_();
};
/**
* Add a new event source that will generate pointer events.
*
* @param {string} name A name for the event source
* @param {module:ol/pointer/EventSource} source The source event.
*/
PointerEventHandler.prototype.registerSource = function(name, source) {
const s = source;
const newEvents = s.getEvents();
if (newEvents) {
newEvents.forEach(function(e) {
const handler = s.getHandlerForEvent(e);
if (handler) {
this.eventMap_[e] = handler.bind(s);
}
}.bind(this));
this.eventSourceList_.push(s);
}
};
/**
* Set up the events for all registered event sources.
* @private
*/
PointerEventHandler.prototype.register_ = function() {
const l = this.eventSourceList_.length;
for (let i = 0; i < l; i++) {
const eventSource = this.eventSourceList_[i];
this.addEvents_(eventSource.getEvents());
}
};
/**
* Remove all registered events.
* @private
*/
PointerEventHandler.prototype.unregister_ = function() {
const l = this.eventSourceList_.length;
for (let i = 0; i < l; i++) {
const eventSource = this.eventSourceList_[i];
this.removeEvents_(eventSource.getEvents());
}
};
/**
* Calls the right handler for a new event.
* @private
* @param {Event} inEvent Browser event.
*/
PointerEventHandler.prototype.eventHandler_ = function(inEvent) {
const type = inEvent.type;
const handler = this.eventMap_[type];
if (handler) {
handler(inEvent);
}
};
/**
* Setup listeners for the given events.
* @private
* @param {Array.<string>} events List of events.
*/
PointerEventHandler.prototype.addEvents_ = function(events) {
events.forEach(function(eventName) {
listen(this.element_, eventName, this.eventHandler_, this);
}.bind(this));
};
/**
* Unregister listeners for the given events.
* @private
* @param {Array.<string>} events List of events.
*/
PointerEventHandler.prototype.removeEvents_ = function(events) {
events.forEach(function(e) {
unlisten(this.element_, e, this.eventHandler_, this);
}.bind(this));
};
/**
* Returns a snapshot of inEvent, with writable properties.
*
* @param {Event} event Browser event.
* @param {Event|Touch} inEvent An event that contains
* properties to copy.
* @return {Object} An object containing shallow copies of
* `inEvent`'s properties.
*/
PointerEventHandler.prototype.cloneEvent = function(event, inEvent) {
const eventCopy = {};
for (let i = 0, ii = CLONE_PROPS.length; i < ii; i++) {
const p = CLONE_PROPS[i][0];
eventCopy[p] = event[p] || inEvent[p] || CLONE_PROPS[i][1];
}
return eventCopy;
};
// EVENTS
/**
* Triggers a 'pointerdown' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.down = function(data, event) {
this.fireEvent(PointerEventType.POINTERDOWN, data, event);
};
/**
* Triggers a 'pointermove' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.move = function(data, event) {
this.fireEvent(PointerEventType.POINTERMOVE, data, event);
};
/**
* Triggers a 'pointerup' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.up = function(data, event) {
this.fireEvent(PointerEventType.POINTERUP, data, event);
};
/**
* Triggers a 'pointerenter' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.enter = function(data, event) {
data.bubbles = false;
this.fireEvent(PointerEventType.POINTERENTER, data, event);
};
/**
* Triggers a 'pointerleave' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.leave = function(data, event) {
data.bubbles = false;
this.fireEvent(PointerEventType.POINTERLEAVE, data, event);
};
/**
* Triggers a 'pointerover' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.over = function(data, event) {
data.bubbles = true;
this.fireEvent(PointerEventType.POINTEROVER, data, event);
};
/**
* Triggers a 'pointerout' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.out = function(data, event) {
data.bubbles = true;
this.fireEvent(PointerEventType.POINTEROUT, data, event);
};
/**
* Triggers a 'pointercancel' event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.cancel = function(data, event) {
this.fireEvent(PointerEventType.POINTERCANCEL, data, event);
};
/**
* Triggers a combination of 'pointerout' and 'pointerleave' events.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.leaveOut = function(data, event) {
this.out(data, event);
if (!this.contains_(data.target, data.relatedTarget)) {
this.leave(data, event);
}
};
/**
* Triggers a combination of 'pointerover' and 'pointerevents' events.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.enterOver = function(data, event) {
this.over(data, event);
if (!this.contains_(data.target, data.relatedTarget)) {
this.enter(data, event);
}
};
/**
* @private
* @param {Element} container The container element.
* @param {Element} contained The contained element.
* @return {boolean} Returns true if the container element
* contains the other element.
*/
PointerEventHandler.prototype.contains_ = function(container, contained) {
if (!container || !contained) {
return false;
}
return container.contains(contained);
};
// EVENT CREATION AND TRACKING
/**
* Creates a new Event of type `inType`, based on the information in
* `data`.
*
* @param {string} inType A string representing the type of event to create.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
* @return {module:ol/pointer/PointerEvent} A PointerEvent of type `inType`.
*/
PointerEventHandler.prototype.makeEvent = function(inType, data, event) {
return new PointerEvent(inType, event, data);
};
/**
* Make and dispatch an event in one call.
* @param {string} inType A string representing the type of event.
* @param {Object} data Pointer event data.
* @param {Event} event The event.
*/
PointerEventHandler.prototype.fireEvent = function(inType, data, event) {
const e = this.makeEvent(inType, data, event);
this.dispatchEvent(e);
};
/**
* Creates a pointer event from a native pointer event
* and dispatches this event.
* @param {Event} event A platform event with a target.
*/
PointerEventHandler.prototype.fireNativeEvent = function(event) {
const e = this.makeEvent(event.type, event, event);
this.dispatchEvent(e);
};
/**
* Wrap a native mouse event into a pointer event.
* This proxy method is required for the legacy IE support.
* @param {string} eventType The pointer event type.
* @param {Event} event The event.
* @return {module:ol/pointer/PointerEvent} The wrapped event.
*/
PointerEventHandler.prototype.wrapMouseEvent = function(eventType, event) {
const pointerEvent = this.makeEvent(
eventType, MouseSource.prepareEvent(event, this), event);
return pointerEvent;
};
/**
* @inheritDoc
*/
PointerEventHandler.prototype.disposeInternal = function() {
this.unregister_();
EventTarget.prototype.disposeInternal.call(this);
};
export default PointerEventHandler;

View File

@@ -43,53 +43,370 @@ import {POINTER_ID} from '../pointer/MouseSource.js';
* @param {module:ol/pointer/MouseSource} mouseSource Mouse source.
* @extends {module:ol/pointer/EventSource}
*/
const TouchSource = function(dispatcher, mouseSource) {
const mapping = {
'touchstart': this.touchstart,
'touchmove': this.touchmove,
'touchend': this.touchend,
'touchcancel': this.touchcancel
};
EventSource.call(this, dispatcher, mapping);
class TouchSource {
constructor(dispatcher, mouseSource) {
const mapping = {
'touchstart': this.touchstart,
'touchmove': this.touchmove,
'touchend': this.touchend,
'touchcancel': this.touchcancel
};
EventSource.call(this, dispatcher, mapping);
/**
* @const
* @type {!Object.<string, Event|Object>}
*/
this.pointerMap = dispatcher.pointerMap;
/**
* @const
* @type {!Object.<string, Event|Object>}
*/
this.pointerMap = dispatcher.pointerMap;
/**
* @const
* @type {module:ol/pointer/MouseSource}
*/
this.mouseSource = mouseSource;
/**
* @const
* @type {module:ol/pointer/MouseSource}
*/
this.mouseSource = mouseSource;
/**
* @private
* @type {number|undefined}
*/
this.firstTouchId_ = undefined;
/**
* @private
* @type {number}
*/
this.clickCount_ = 0;
/**
* @private
* @type {number|undefined}
*/
this.resetId_ = undefined;
/**
* Mouse event timeout: This should be long enough to
* ignore compat mouse events made by touch.
* @private
* @type {number}
*/
this.dedupTimeout_ = 2500;
}
/**
* @private
* @type {number|undefined}
* @param {Touch} inTouch The in touch.
* @return {boolean} True, if this is the primary touch.
*/
this.firstTouchId_ = undefined;
isPrimaryTouch_(inTouch) {
return this.firstTouchId_ === inTouch.identifier;
}
/**
* Set primary touch if there are no pointers, or the only pointer is the mouse.
* @param {Touch} inTouch The in touch.
* @private
*/
setPrimaryTouch_(inTouch) {
const count = Object.keys(this.pointerMap).length;
if (count === 0 || (count === 1 && POINTER_ID.toString() in this.pointerMap)) {
this.firstTouchId_ = inTouch.identifier;
this.cancelResetClickCount_();
}
}
/**
* @private
* @type {number}
* @param {PointerEvent} inPointer The in pointer object.
*/
this.clickCount_ = 0;
removePrimaryPointer_(inPointer) {
if (inPointer.isPrimary) {
this.firstTouchId_ = undefined;
this.resetClickCount_();
}
}
/**
* @private
* @type {number|undefined}
*/
this.resetId_ = undefined;
resetClickCount_() {
this.resetId_ = setTimeout(
this.resetClickCountHandler_.bind(this),
CLICK_COUNT_TIMEOUT);
}
/**
* Mouse event timeout: This should be long enough to
* ignore compat mouse events made by touch.
* @private
* @type {number}
*/
this.dedupTimeout_ = 2500;
};
resetClickCountHandler_() {
this.clickCount_ = 0;
this.resetId_ = undefined;
}
/**
* @private
*/
cancelResetClickCount_() {
if (this.resetId_ !== undefined) {
clearTimeout(this.resetId_);
}
}
/**
* @private
* @param {TouchEvent} browserEvent Browser event
* @param {Touch} inTouch Touch event
* @return {PointerEvent} A pointer object.
*/
touchToPointer_(browserEvent, inTouch) {
const e = this.dispatcher.cloneEvent(browserEvent, inTouch);
// Spec specifies that pointerId 1 is reserved for Mouse.
// Touch identifiers can start at 0.
// Add 2 to the touch identifier for compatibility.
e.pointerId = inTouch.identifier + 2;
// TODO: check if this is necessary?
//e.target = findTarget(e);
e.bubbles = true;
e.cancelable = true;
e.detail = this.clickCount_;
e.button = 0;
e.buttons = 1;
e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
e.isPrimary = this.isPrimaryTouch_(inTouch);
e.pointerType = POINTER_TYPE;
// make sure that the properties that are different for
// each `Touch` object are not copied from the BrowserEvent object
e.clientX = inTouch.clientX;
e.clientY = inTouch.clientY;
e.screenX = inTouch.screenX;
e.screenY = inTouch.screenY;
return e;
}
/**
* @private
* @param {TouchEvent} inEvent Touch event
* @param {function(TouchEvent, PointerEvent)} inFunction In function.
*/
processTouches_(inEvent, inFunction) {
const touches = Array.prototype.slice.call(inEvent.changedTouches);
const count = touches.length;
function preventDefault() {
inEvent.preventDefault();
}
for (let i = 0; i < count; ++i) {
const pointer = this.touchToPointer_(inEvent, touches[i]);
// forward touch preventDefaults
pointer.preventDefault = preventDefault;
inFunction.call(this, inEvent, pointer);
}
}
/**
* @private
* @param {TouchList} touchList The touch list.
* @param {number} searchId Search identifier.
* @return {boolean} True, if the `Touch` with the given id is in the list.
*/
findTouch_(touchList, searchId) {
const l = touchList.length;
for (let i = 0; i < l; i++) {
const touch = touchList[i];
if (touch.identifier === searchId) {
return true;
}
}
return false;
}
/**
* In some instances, a touchstart can happen without a touchend. This
* leaves the pointermap in a broken state.
* Therefore, on every touchstart, we remove the touches that did not fire a
* touchend event.
* To keep state globally consistent, we fire a pointercancel for
* this "abandoned" touch
*
* @private
* @param {TouchEvent} inEvent The in event.
*/
vacuumTouches_(inEvent) {
const touchList = inEvent.touches;
// pointerMap.getCount() should be < touchList.length here,
// as the touchstart has not been processed yet.
const keys = Object.keys(this.pointerMap);
const count = keys.length;
if (count >= touchList.length) {
const d = [];
for (let i = 0; i < count; ++i) {
const key = keys[i];
const value = this.pointerMap[key];
// Never remove pointerId == 1, which is mouse.
// Touch identifiers are 2 smaller than their pointerId, which is the
// index in pointermap.
if (key != POINTER_ID && !this.findTouch_(touchList, key - 2)) {
d.push(value.out);
}
}
for (let i = 0; i < d.length; ++i) {
this.cancelOut_(inEvent, d[i]);
}
}
}
/**
* Handler for `touchstart`, triggers `pointerover`,
* `pointerenter` and `pointerdown` events.
*
* @param {TouchEvent} inEvent The in event.
*/
touchstart(inEvent) {
this.vacuumTouches_(inEvent);
this.setPrimaryTouch_(inEvent.changedTouches[0]);
this.dedupSynthMouse_(inEvent);
this.clickCount_++;
this.processTouches_(inEvent, this.overDown_);
}
/**
* @private
* @param {TouchEvent} browserEvent The event.
* @param {PointerEvent} inPointer The in pointer object.
*/
overDown_(browserEvent, inPointer) {
this.pointerMap[inPointer.pointerId] = {
target: inPointer.target,
out: inPointer,
outTarget: inPointer.target
};
this.dispatcher.over(inPointer, browserEvent);
this.dispatcher.enter(inPointer, browserEvent);
this.dispatcher.down(inPointer, browserEvent);
}
/**
* Handler for `touchmove`.
*
* @param {TouchEvent} inEvent The in event.
*/
touchmove(inEvent) {
inEvent.preventDefault();
this.processTouches_(inEvent, this.moveOverOut_);
}
/**
* @private
* @param {TouchEvent} browserEvent The event.
* @param {PointerEvent} inPointer The in pointer.
*/
moveOverOut_(browserEvent, inPointer) {
const event = inPointer;
const pointer = this.pointerMap[event.pointerId];
// a finger drifted off the screen, ignore it
if (!pointer) {
return;
}
const outEvent = pointer.out;
const outTarget = pointer.outTarget;
this.dispatcher.move(event, browserEvent);
if (outEvent && outTarget !== event.target) {
outEvent.relatedTarget = event.target;
event.relatedTarget = outTarget;
// recover from retargeting by shadow
outEvent.target = outTarget;
if (event.target) {
this.dispatcher.leaveOut(outEvent, browserEvent);
this.dispatcher.enterOver(event, browserEvent);
} else {
// clean up case when finger leaves the screen
event.target = outTarget;
event.relatedTarget = null;
this.cancelOut_(browserEvent, event);
}
}
pointer.out = event;
pointer.outTarget = event.target;
}
/**
* Handler for `touchend`, triggers `pointerup`,
* `pointerout` and `pointerleave` events.
*
* @param {TouchEvent} inEvent The event.
*/
touchend(inEvent) {
this.dedupSynthMouse_(inEvent);
this.processTouches_(inEvent, this.upOut_);
}
/**
* @private
* @param {TouchEvent} browserEvent An event.
* @param {PointerEvent} inPointer The inPointer object.
*/
upOut_(browserEvent, inPointer) {
this.dispatcher.up(inPointer, browserEvent);
this.dispatcher.out(inPointer, browserEvent);
this.dispatcher.leave(inPointer, browserEvent);
this.cleanUpPointer_(inPointer);
}
/**
* Handler for `touchcancel`, triggers `pointercancel`,
* `pointerout` and `pointerleave` events.
*
* @param {TouchEvent} inEvent The in event.
*/
touchcancel(inEvent) {
this.processTouches_(inEvent, this.cancelOut_);
}
/**
* @private
* @param {TouchEvent} browserEvent The event.
* @param {PointerEvent} inPointer The in pointer.
*/
cancelOut_(browserEvent, inPointer) {
this.dispatcher.cancel(inPointer, browserEvent);
this.dispatcher.out(inPointer, browserEvent);
this.dispatcher.leave(inPointer, browserEvent);
this.cleanUpPointer_(inPointer);
}
/**
* @private
* @param {PointerEvent} inPointer The inPointer object.
*/
cleanUpPointer_(inPointer) {
delete this.pointerMap[inPointer.pointerId];
this.removePrimaryPointer_(inPointer);
}
/**
* Prevent synth mouse events from creating pointer events.
*
* @private
* @param {TouchEvent} inEvent The in event.
*/
dedupSynthMouse_(inEvent) {
const lts = this.mouseSource.lastTouches;
const t = inEvent.changedTouches[0];
// only the primary finger will synth mouse events
if (this.isPrimaryTouch_(t)) {
// remember x/y of last touch
const lt = [t.clientX, t.clientY];
lts.push(lt);
setTimeout(function() {
// remove touch after timeout
remove(lts, lt);
}, this.dedupTimeout_);
}
}
}
inherits(TouchSource, EventSource);
@@ -105,337 +422,4 @@ const CLICK_COUNT_TIMEOUT = 200;
*/
const POINTER_TYPE = 'touch';
/**
* @private
* @param {Touch} inTouch The in touch.
* @return {boolean} True, if this is the primary touch.
*/
TouchSource.prototype.isPrimaryTouch_ = function(inTouch) {
return this.firstTouchId_ === inTouch.identifier;
};
/**
* Set primary touch if there are no pointers, or the only pointer is the mouse.
* @param {Touch} inTouch The in touch.
* @private
*/
TouchSource.prototype.setPrimaryTouch_ = function(inTouch) {
const count = Object.keys(this.pointerMap).length;
if (count === 0 || (count === 1 && POINTER_ID.toString() in this.pointerMap)) {
this.firstTouchId_ = inTouch.identifier;
this.cancelResetClickCount_();
}
};
/**
* @private
* @param {PointerEvent} inPointer The in pointer object.
*/
TouchSource.prototype.removePrimaryPointer_ = function(inPointer) {
if (inPointer.isPrimary) {
this.firstTouchId_ = undefined;
this.resetClickCount_();
}
};
/**
* @private
*/
TouchSource.prototype.resetClickCount_ = function() {
this.resetId_ = setTimeout(
this.resetClickCountHandler_.bind(this),
CLICK_COUNT_TIMEOUT);
};
/**
* @private
*/
TouchSource.prototype.resetClickCountHandler_ = function() {
this.clickCount_ = 0;
this.resetId_ = undefined;
};
/**
* @private
*/
TouchSource.prototype.cancelResetClickCount_ = function() {
if (this.resetId_ !== undefined) {
clearTimeout(this.resetId_);
}
};
/**
* @private
* @param {TouchEvent} browserEvent Browser event
* @param {Touch} inTouch Touch event
* @return {PointerEvent} A pointer object.
*/
TouchSource.prototype.touchToPointer_ = function(browserEvent, inTouch) {
const e = this.dispatcher.cloneEvent(browserEvent, inTouch);
// Spec specifies that pointerId 1 is reserved for Mouse.
// Touch identifiers can start at 0.
// Add 2 to the touch identifier for compatibility.
e.pointerId = inTouch.identifier + 2;
// TODO: check if this is necessary?
//e.target = findTarget(e);
e.bubbles = true;
e.cancelable = true;
e.detail = this.clickCount_;
e.button = 0;
e.buttons = 1;
e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
e.isPrimary = this.isPrimaryTouch_(inTouch);
e.pointerType = POINTER_TYPE;
// make sure that the properties that are different for
// each `Touch` object are not copied from the BrowserEvent object
e.clientX = inTouch.clientX;
e.clientY = inTouch.clientY;
e.screenX = inTouch.screenX;
e.screenY = inTouch.screenY;
return e;
};
/**
* @private
* @param {TouchEvent} inEvent Touch event
* @param {function(TouchEvent, PointerEvent)} inFunction In function.
*/
TouchSource.prototype.processTouches_ = function(inEvent, inFunction) {
const touches = Array.prototype.slice.call(inEvent.changedTouches);
const count = touches.length;
function preventDefault() {
inEvent.preventDefault();
}
for (let i = 0; i < count; ++i) {
const pointer = this.touchToPointer_(inEvent, touches[i]);
// forward touch preventDefaults
pointer.preventDefault = preventDefault;
inFunction.call(this, inEvent, pointer);
}
};
/**
* @private
* @param {TouchList} touchList The touch list.
* @param {number} searchId Search identifier.
* @return {boolean} True, if the `Touch` with the given id is in the list.
*/
TouchSource.prototype.findTouch_ = function(touchList, searchId) {
const l = touchList.length;
for (let i = 0; i < l; i++) {
const touch = touchList[i];
if (touch.identifier === searchId) {
return true;
}
}
return false;
};
/**
* In some instances, a touchstart can happen without a touchend. This
* leaves the pointermap in a broken state.
* Therefore, on every touchstart, we remove the touches that did not fire a
* touchend event.
* To keep state globally consistent, we fire a pointercancel for
* this "abandoned" touch
*
* @private
* @param {TouchEvent} inEvent The in event.
*/
TouchSource.prototype.vacuumTouches_ = function(inEvent) {
const touchList = inEvent.touches;
// pointerMap.getCount() should be < touchList.length here,
// as the touchstart has not been processed yet.
const keys = Object.keys(this.pointerMap);
const count = keys.length;
if (count >= touchList.length) {
const d = [];
for (let i = 0; i < count; ++i) {
const key = keys[i];
const value = this.pointerMap[key];
// Never remove pointerId == 1, which is mouse.
// Touch identifiers are 2 smaller than their pointerId, which is the
// index in pointermap.
if (key != POINTER_ID && !this.findTouch_(touchList, key - 2)) {
d.push(value.out);
}
}
for (let i = 0; i < d.length; ++i) {
this.cancelOut_(inEvent, d[i]);
}
}
};
/**
* Handler for `touchstart`, triggers `pointerover`,
* `pointerenter` and `pointerdown` events.
*
* @param {TouchEvent} inEvent The in event.
*/
TouchSource.prototype.touchstart = function(inEvent) {
this.vacuumTouches_(inEvent);
this.setPrimaryTouch_(inEvent.changedTouches[0]);
this.dedupSynthMouse_(inEvent);
this.clickCount_++;
this.processTouches_(inEvent, this.overDown_);
};
/**
* @private
* @param {TouchEvent} browserEvent The event.
* @param {PointerEvent} inPointer The in pointer object.
*/
TouchSource.prototype.overDown_ = function(browserEvent, inPointer) {
this.pointerMap[inPointer.pointerId] = {
target: inPointer.target,
out: inPointer,
outTarget: inPointer.target
};
this.dispatcher.over(inPointer, browserEvent);
this.dispatcher.enter(inPointer, browserEvent);
this.dispatcher.down(inPointer, browserEvent);
};
/**
* Handler for `touchmove`.
*
* @param {TouchEvent} inEvent The in event.
*/
TouchSource.prototype.touchmove = function(inEvent) {
inEvent.preventDefault();
this.processTouches_(inEvent, this.moveOverOut_);
};
/**
* @private
* @param {TouchEvent} browserEvent The event.
* @param {PointerEvent} inPointer The in pointer.
*/
TouchSource.prototype.moveOverOut_ = function(browserEvent, inPointer) {
const event = inPointer;
const pointer = this.pointerMap[event.pointerId];
// a finger drifted off the screen, ignore it
if (!pointer) {
return;
}
const outEvent = pointer.out;
const outTarget = pointer.outTarget;
this.dispatcher.move(event, browserEvent);
if (outEvent && outTarget !== event.target) {
outEvent.relatedTarget = event.target;
event.relatedTarget = outTarget;
// recover from retargeting by shadow
outEvent.target = outTarget;
if (event.target) {
this.dispatcher.leaveOut(outEvent, browserEvent);
this.dispatcher.enterOver(event, browserEvent);
} else {
// clean up case when finger leaves the screen
event.target = outTarget;
event.relatedTarget = null;
this.cancelOut_(browserEvent, event);
}
}
pointer.out = event;
pointer.outTarget = event.target;
};
/**
* Handler for `touchend`, triggers `pointerup`,
* `pointerout` and `pointerleave` events.
*
* @param {TouchEvent} inEvent The event.
*/
TouchSource.prototype.touchend = function(inEvent) {
this.dedupSynthMouse_(inEvent);
this.processTouches_(inEvent, this.upOut_);
};
/**
* @private
* @param {TouchEvent} browserEvent An event.
* @param {PointerEvent} inPointer The inPointer object.
*/
TouchSource.prototype.upOut_ = function(browserEvent, inPointer) {
this.dispatcher.up(inPointer, browserEvent);
this.dispatcher.out(inPointer, browserEvent);
this.dispatcher.leave(inPointer, browserEvent);
this.cleanUpPointer_(inPointer);
};
/**
* Handler for `touchcancel`, triggers `pointercancel`,
* `pointerout` and `pointerleave` events.
*
* @param {TouchEvent} inEvent The in event.
*/
TouchSource.prototype.touchcancel = function(inEvent) {
this.processTouches_(inEvent, this.cancelOut_);
};
/**
* @private
* @param {TouchEvent} browserEvent The event.
* @param {PointerEvent} inPointer The in pointer.
*/
TouchSource.prototype.cancelOut_ = function(browserEvent, inPointer) {
this.dispatcher.cancel(inPointer, browserEvent);
this.dispatcher.out(inPointer, browserEvent);
this.dispatcher.leave(inPointer, browserEvent);
this.cleanUpPointer_(inPointer);
};
/**
* @private
* @param {PointerEvent} inPointer The inPointer object.
*/
TouchSource.prototype.cleanUpPointer_ = function(inPointer) {
delete this.pointerMap[inPointer.pointerId];
this.removePrimaryPointer_(inPointer);
};
/**
* Prevent synth mouse events from creating pointer events.
*
* @private
* @param {TouchEvent} inEvent The in event.
*/
TouchSource.prototype.dedupSynthMouse_ = function(inEvent) {
const lts = this.mouseSource.lastTouches;
const t = inEvent.changedTouches[0];
// only the primary finger will synth mouse events
if (this.isPrimaryTouch_(t)) {
// remember x/y of last touch
const lt = [t.clientX, t.clientY];
lts.push(lt);
setTimeout(function() {
// remove touch after timeout
remove(lts, lt);
}, this.dedupTimeout_);
}
};
export default TouchSource;