Use pepjs instead of our own pointerevent polyfill
This commit is contained in:
@@ -37,6 +37,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pbf": "3.2.0",
|
"pbf": "3.2.0",
|
||||||
|
"pepjs": "^0.5.2",
|
||||||
"pixelworks": "1.1.0",
|
"pixelworks": "1.1.0",
|
||||||
"rbush": "^3.0.0"
|
"rbush": "^3.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* @module ol/MapBrowserEventHandler
|
* @module ol/MapBrowserEventHandler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'pepjs';
|
||||||
import {DEVICE_PIXEL_RATIO} from './has.js';
|
import {DEVICE_PIXEL_RATIO} from './has.js';
|
||||||
import MapBrowserEventType from './MapBrowserEventType.js';
|
import MapBrowserEventType from './MapBrowserEventType.js';
|
||||||
import MapBrowserPointerEvent from './MapBrowserPointerEvent.js';
|
import MapBrowserPointerEvent from './MapBrowserPointerEvent.js';
|
||||||
import {listen, unlistenByKey} from './events.js';
|
import {listen, unlistenByKey} from './events.js';
|
||||||
import EventTarget from './events/Target.js';
|
import EventTarget from './events/Target.js';
|
||||||
import PointerEventType from './pointer/EventType.js';
|
import PointerEventType from './pointer/EventType.js';
|
||||||
import PointerEventHandler from './pointer/PointerEventHandler.js';
|
|
||||||
|
|
||||||
class MapBrowserEventHandler extends EventTarget {
|
class MapBrowserEventHandler extends EventTarget {
|
||||||
|
|
||||||
@@ -54,12 +55,13 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
/**
|
/**
|
||||||
* The most recent "down" type event (or null if none have occurred).
|
* The most recent "down" type event (or null if none have occurred).
|
||||||
* Set on pointerdown.
|
* Set on pointerdown.
|
||||||
* @type {import("./pointer/PointerEvent.js").default}
|
* @type {PointerEvent}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.down_ = null;
|
this.down_ = null;
|
||||||
|
|
||||||
const element = this.map_.getViewport();
|
const element = this.map_.getViewport();
|
||||||
|
element.setAttribute('touch-action', 'none');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {number}
|
* @type {number}
|
||||||
@@ -73,29 +75,13 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
*/
|
*/
|
||||||
this.trackedTouches_ = {};
|
this.trackedTouches_ = {};
|
||||||
|
|
||||||
/**
|
this.element_ = element;
|
||||||
* Event handler which generates pointer events for
|
|
||||||
* the viewport element.
|
|
||||||
*
|
|
||||||
* @type {PointerEventHandler}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.pointerEventHandler_ = new PointerEventHandler(element);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event handler which generates pointer events for
|
|
||||||
* the document (used when dragging).
|
|
||||||
*
|
|
||||||
* @type {PointerEventHandler}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.documentPointerEventHandler_ = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {?import("./events.js").EventsKey}
|
* @type {?import("./events.js").EventsKey}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.pointerdownListenerKey_ = listen(this.pointerEventHandler_,
|
this.pointerdownListenerKey_ = listen(element,
|
||||||
PointerEventType.POINTERDOWN,
|
PointerEventType.POINTERDOWN,
|
||||||
this.handlePointerDown_, this);
|
this.handlePointerDown_, this);
|
||||||
|
|
||||||
@@ -103,14 +89,14 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
* @type {?import("./events.js").EventsKey}
|
* @type {?import("./events.js").EventsKey}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.relayedListenerKey_ = listen(this.pointerEventHandler_,
|
this.relayedListenerKey_ = listen(element,
|
||||||
PointerEventType.POINTERMOVE,
|
PointerEventType.POINTERMOVE,
|
||||||
this.relayEvent_, this);
|
this.relayEvent_, this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("./pointer/PointerEvent.js").default} pointerEvent Pointer
|
* @param {PointerEvent} pointerEvent Pointer
|
||||||
* event.
|
* event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -139,7 +125,7 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
/**
|
/**
|
||||||
* Keeps track on how many pointers are currently active.
|
* Keeps track on how many pointers are currently active.
|
||||||
*
|
*
|
||||||
* @param {import("./pointer/PointerEvent.js").default} pointerEvent Pointer
|
* @param {PointerEvent} pointerEvent Pointer
|
||||||
* event.
|
* event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -156,7 +142,7 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("./pointer/PointerEvent.js").default} pointerEvent Pointer
|
* @param {PointerEvent} pointerEvent Pointer
|
||||||
* event.
|
* event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -181,13 +167,11 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
this.dragListenerKeys_.length = 0;
|
this.dragListenerKeys_.length = 0;
|
||||||
this.dragging_ = false;
|
this.dragging_ = false;
|
||||||
this.down_ = null;
|
this.down_ = null;
|
||||||
this.documentPointerEventHandler_.dispose();
|
|
||||||
this.documentPointerEventHandler_ = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("./pointer/PointerEvent.js").default} pointerEvent Pointer
|
* @param {PointerEvent} pointerEvent Pointer
|
||||||
* event.
|
* event.
|
||||||
* @return {boolean} If the left mouse button was pressed.
|
* @return {boolean} If the left mouse button was pressed.
|
||||||
* @private
|
* @private
|
||||||
@@ -197,7 +181,7 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("./pointer/PointerEvent.js").default} pointerEvent Pointer
|
* @param {PointerEvent} pointerEvent Pointer
|
||||||
* event.
|
* event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -210,18 +194,11 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
this.down_ = pointerEvent;
|
this.down_ = pointerEvent;
|
||||||
|
|
||||||
if (this.dragListenerKeys_.length === 0) {
|
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 PointerEventHandler(document);
|
|
||||||
|
|
||||||
this.dragListenerKeys_.push(
|
this.dragListenerKeys_.push(
|
||||||
listen(this.documentPointerEventHandler_,
|
listen(document,
|
||||||
MapBrowserEventType.POINTERMOVE,
|
MapBrowserEventType.POINTERMOVE,
|
||||||
this.handlePointerMove_, this),
|
this.handlePointerMove_, this),
|
||||||
listen(this.documentPointerEventHandler_,
|
listen(document,
|
||||||
MapBrowserEventType.POINTERUP,
|
MapBrowserEventType.POINTERUP,
|
||||||
this.handlePointerUp_, this),
|
this.handlePointerUp_, this),
|
||||||
/* Note that the listener for `pointercancel is set up on
|
/* Note that the listener for `pointercancel is set up on
|
||||||
@@ -237,7 +214,7 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
* only receive a `touchcancel` from `pointerEventHandler_`, because it is
|
* only receive a `touchcancel` from `pointerEventHandler_`, because it is
|
||||||
* only registered there.
|
* only registered there.
|
||||||
*/
|
*/
|
||||||
listen(this.pointerEventHandler_,
|
listen(this.element_,
|
||||||
MapBrowserEventType.POINTERCANCEL,
|
MapBrowserEventType.POINTERCANCEL,
|
||||||
this.handlePointerUp_, this)
|
this.handlePointerUp_, this)
|
||||||
);
|
);
|
||||||
@@ -245,7 +222,7 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("./pointer/PointerEvent.js").default} pointerEvent Pointer
|
* @param {PointerEvent} pointerEvent Pointer
|
||||||
* event.
|
* event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -265,7 +242,7 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
/**
|
/**
|
||||||
* Wrap and relay a pointer event. Note that this requires that the type
|
* Wrap and relay a pointer event. Note that this requires that the type
|
||||||
* string for the MapBrowserPointerEvent matches the PointerEvent type.
|
* string for the MapBrowserPointerEvent matches the PointerEvent type.
|
||||||
* @param {import("./pointer/PointerEvent.js").default} pointerEvent Pointer
|
* @param {PointerEvent} pointerEvent Pointer
|
||||||
* event.
|
* event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -276,7 +253,7 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("./pointer/PointerEvent.js").default} pointerEvent Pointer
|
* @param {PointerEvent} pointerEvent Pointer
|
||||||
* event.
|
* event.
|
||||||
* @return {boolean} Is moving.
|
* @return {boolean} Is moving.
|
||||||
* @private
|
* @private
|
||||||
@@ -303,14 +280,7 @@ class MapBrowserEventHandler extends EventTarget {
|
|||||||
this.dragListenerKeys_.forEach(unlistenByKey);
|
this.dragListenerKeys_.forEach(unlistenByKey);
|
||||||
this.dragListenerKeys_.length = 0;
|
this.dragListenerKeys_.length = 0;
|
||||||
|
|
||||||
if (this.documentPointerEventHandler_) {
|
this.element_ = null;
|
||||||
this.documentPointerEventHandler_.dispose();
|
|
||||||
this.documentPointerEventHandler_ = null;
|
|
||||||
}
|
|
||||||
if (this.pointerEventHandler_) {
|
|
||||||
this.pointerEventHandler_.dispose();
|
|
||||||
this.pointerEventHandler_ = null;
|
|
||||||
}
|
|
||||||
super.disposeInternal();
|
super.disposeInternal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ class MapBrowserPointerEvent extends MapBrowserEvent {
|
|||||||
/**
|
/**
|
||||||
* @param {string} type Event type.
|
* @param {string} type Event type.
|
||||||
* @param {import("./PluggableMap.js").default} map Map.
|
* @param {import("./PluggableMap.js").default} map Map.
|
||||||
* @param {import("./pointer/PointerEvent.js").default} pointerEvent Pointer event.
|
* @param {PointerEvent} pointerEvent Pointer event.
|
||||||
* @param {boolean=} opt_dragging Is the map currently being dragged?
|
* @param {boolean=} opt_dragging Is the map currently being dragged?
|
||||||
* @param {?import("./PluggableMap.js").FrameState=} opt_frameState Frame state.
|
* @param {?import("./PluggableMap.js").FrameState=} opt_frameState Frame state.
|
||||||
*/
|
*/
|
||||||
constructor(type, map, pointerEvent, opt_dragging, opt_frameState) {
|
constructor(type, map, pointerEvent, opt_dragging, opt_frameState) {
|
||||||
|
|
||||||
super(type, map, pointerEvent.originalEvent, opt_dragging, opt_frameState);
|
super(type, map, pointerEvent, opt_dragging, opt_frameState);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @const
|
* @const
|
||||||
* @type {import("./pointer/PointerEvent.js").default}
|
* @type {PointerEvent}
|
||||||
*/
|
*/
|
||||||
this.pointerEvent = pointerEvent;
|
this.pointerEvent = pointerEvent;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {stopPropagation} from '../events/Event.js';
|
|||||||
import EventType from '../events/EventType.js';
|
import EventType from '../events/EventType.js';
|
||||||
import {clamp} from '../math.js';
|
import {clamp} from '../math.js';
|
||||||
import PointerEventType from '../pointer/EventType.js';
|
import PointerEventType from '../pointer/EventType.js';
|
||||||
import PointerEventHandler from '../pointer/PointerEventHandler.js';
|
import 'pepjs';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,19 +135,15 @@ class ZoomSlider extends Control {
|
|||||||
thumbElement.setAttribute('type', 'button');
|
thumbElement.setAttribute('type', 'button');
|
||||||
thumbElement.className = className + '-thumb ' + CLASS_UNSELECTABLE;
|
thumbElement.className = className + '-thumb ' + CLASS_UNSELECTABLE;
|
||||||
const containerElement = this.element;
|
const containerElement = this.element;
|
||||||
|
containerElement.setAttribute('touch-action', 'none');
|
||||||
containerElement.className = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
containerElement.className = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;
|
||||||
containerElement.appendChild(thumbElement);
|
containerElement.appendChild(thumbElement);
|
||||||
/**
|
|
||||||
* @type {PointerEventHandler}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.dragger_ = new PointerEventHandler(containerElement);
|
|
||||||
|
|
||||||
listen(this.dragger_, PointerEventType.POINTERDOWN,
|
listen(containerElement, PointerEventType.POINTERDOWN,
|
||||||
this.handleDraggerStart_, this);
|
this.handleDraggerStart_, this);
|
||||||
listen(this.dragger_, PointerEventType.POINTERMOVE,
|
listen(containerElement, PointerEventType.POINTERMOVE,
|
||||||
this.handleDraggerDrag_, this);
|
this.handleDraggerDrag_, this);
|
||||||
listen(this.dragger_, PointerEventType.POINTERUP,
|
listen(containerElement, PointerEventType.POINTERUP,
|
||||||
this.handleDraggerEnd_, this);
|
this.handleDraggerEnd_, this);
|
||||||
|
|
||||||
listen(containerElement, EventType.CLICK, this.handleContainerClick_, this);
|
listen(containerElement, EventType.CLICK, this.handleContainerClick_, this);
|
||||||
@@ -158,7 +154,6 @@ class ZoomSlider extends Control {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
disposeInternal() {
|
disposeInternal() {
|
||||||
this.dragger_.dispose();
|
|
||||||
super.disposeInternal();
|
super.disposeInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +201,7 @@ class ZoomSlider extends Control {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MouseEvent} event The browser event to handle.
|
* @param {PointerEvent} event The browser event to handle.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleContainerClick_(event) {
|
handleContainerClick_(event) {
|
||||||
@@ -228,11 +223,11 @@ class ZoomSlider extends Control {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle dragger start events.
|
* Handle dragger start events.
|
||||||
* @param {import("../pointer/PointerEvent.js").default} event The drag event.
|
* @param {PointerEvent} event The drag event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleDraggerStart_(event) {
|
handleDraggerStart_(event) {
|
||||||
if (!this.dragging_ && event.originalEvent.target === this.element.firstElementChild) {
|
if (!this.dragging_ && event.target === this.element.firstElementChild) {
|
||||||
const element = /** @type {HTMLElement} */ (this.element.firstElementChild);
|
const element = /** @type {HTMLElement} */ (this.element.firstElementChild);
|
||||||
this.getMap().getView().beginInteraction();
|
this.getMap().getView().beginInteraction();
|
||||||
this.startX_ = event.clientX - parseFloat(element.style.left);
|
this.startX_ = event.clientX - parseFloat(element.style.left);
|
||||||
@@ -243,9 +238,7 @@ class ZoomSlider extends Control {
|
|||||||
const drag = this.handleDraggerDrag_;
|
const drag = this.handleDraggerDrag_;
|
||||||
const end = this.handleDraggerEnd_;
|
const end = this.handleDraggerEnd_;
|
||||||
this.dragListenerKeys_.push(
|
this.dragListenerKeys_.push(
|
||||||
listen(document, EventType.MOUSEMOVE, drag, this),
|
|
||||||
listen(document, PointerEventType.POINTERMOVE, drag, this),
|
listen(document, PointerEventType.POINTERMOVE, drag, this),
|
||||||
listen(document, EventType.MOUSEUP, end, this),
|
|
||||||
listen(document, PointerEventType.POINTERUP, end, this)
|
listen(document, PointerEventType.POINTERUP, end, this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -255,7 +248,7 @@ class ZoomSlider extends Control {
|
|||||||
/**
|
/**
|
||||||
* Handle dragger drag events.
|
* Handle dragger drag events.
|
||||||
*
|
*
|
||||||
* @param {import("../pointer/PointerEvent.js").default} event The drag event.
|
* @param {PointerEvent} event The drag event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleDraggerDrag_(event) {
|
handleDraggerDrag_(event) {
|
||||||
@@ -270,7 +263,7 @@ class ZoomSlider extends Control {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle dragger end events.
|
* Handle dragger end events.
|
||||||
* @param {import("../pointer/PointerEvent.js").default} event The drag event.
|
* @param {PointerEvent} event The drag event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
handleDraggerEnd_(event) {
|
handleDraggerEnd_(event) {
|
||||||
|
|||||||
@@ -82,7 +82,9 @@ class Target extends Disposable {
|
|||||||
dispatchEvent(event) {
|
dispatchEvent(event) {
|
||||||
const evt = typeof event === 'string' ? new Event(event) : event;
|
const evt = typeof event === 'string' ? new Event(event) : event;
|
||||||
const type = evt.type;
|
const type = evt.type;
|
||||||
evt.target = this;
|
if (!evt.target) {
|
||||||
|
evt.target = this;
|
||||||
|
}
|
||||||
const listeners = this.listeners_[type];
|
const listeners = this.listeners_[type];
|
||||||
let propagate;
|
let propagate;
|
||||||
if (listeners) {
|
if (listeners) {
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ export const shiftKeyOnly = function(mapBrowserEvent) {
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
export const targetNotEditable = function(mapBrowserEvent) {
|
export const targetNotEditable = function(mapBrowserEvent) {
|
||||||
const target = mapBrowserEvent.originalEvent.target;
|
const target = mapBrowserEvent.target;
|
||||||
const tagName = /** @type {Element} */ (target).tagName;
|
const tagName = /** @type {Element} */ (target).tagName;
|
||||||
return (
|
return (
|
||||||
tagName !== 'INPUT' &&
|
tagName !== 'INPUT' &&
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import LineString from '../geom/LineString.js';
|
|||||||
import MultiLineString from '../geom/MultiLineString.js';
|
import MultiLineString from '../geom/MultiLineString.js';
|
||||||
import MultiPoint from '../geom/MultiPoint.js';
|
import MultiPoint from '../geom/MultiPoint.js';
|
||||||
import MultiPolygon from '../geom/MultiPolygon.js';
|
import MultiPolygon from '../geom/MultiPolygon.js';
|
||||||
import {POINTER_TYPE} from '../pointer/MouseSource.js';
|
|
||||||
import Point from '../geom/Point.js';
|
import Point from '../geom/Point.js';
|
||||||
import Polygon, {fromCircle, makeRegular} from '../geom/Polygon.js';
|
import Polygon, {fromCircle, makeRegular} from '../geom/Polygon.js';
|
||||||
import PointerInteraction from './Pointer.js';
|
import PointerInteraction from './Pointer.js';
|
||||||
@@ -511,7 +510,7 @@ class Draw extends PointerInteraction {
|
|||||||
pass = event.type === MapBrowserEventType.POINTERMOVE;
|
pass = event.type === MapBrowserEventType.POINTERMOVE;
|
||||||
if (pass && this.freehand_) {
|
if (pass && this.freehand_) {
|
||||||
pass = this.handlePointerMove_(event);
|
pass = this.handlePointerMove_(event);
|
||||||
} else if (/** @type {MapBrowserPointerEvent} */ (event).pointerEvent.pointerType == POINTER_TYPE ||
|
} else if (/** @type {MapBrowserPointerEvent} */ (event).pointerEvent.pointerType == 'mouse' ||
|
||||||
(event.type === MapBrowserEventType.POINTERDRAG && this.downTimeout_ === undefined)) {
|
(event.type === MapBrowserEventType.POINTERDRAG && this.downTimeout_ === undefined)) {
|
||||||
this.handlePointerMove_(event);
|
this.handlePointerMove_(event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,13 +80,13 @@ class PointerInteraction extends Interaction {
|
|||||||
this.handlingDownUpSequence = false;
|
this.handlingDownUpSequence = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {!Object<string, import("../pointer/PointerEvent.js").default>}
|
* @type {!Object<string, PointerEvent>}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.trackedPointers_ = {};
|
this.trackedPointers_ = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Array<import("../pointer/PointerEvent.js").default>}
|
* @type {Array<PointerEvent>}
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
this.targetPointers = [];
|
this.targetPointers = [];
|
||||||
@@ -199,7 +199,7 @@ class PointerInteraction extends Interaction {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array<import("../pointer/PointerEvent.js").default>} pointerEvents List of events.
|
* @param {Array<PointerEvent>} pointerEvents List of events.
|
||||||
* @return {import("../pixel.js").Pixel} Centroid pixel.
|
* @return {import("../pixel.js").Pixel} Centroid pixel.
|
||||||
*/
|
*/
|
||||||
export function centroid(pointerEvents) {
|
export function centroid(pointerEvents) {
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
/**
|
|
||||||
* @module ol/pointer/EventSource
|
|
||||||
*/
|
|
||||||
|
|
||||||
class EventSource {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("./PointerEventHandler.js").default} dispatcher Event handler.
|
|
||||||
* @param {!Object<string, function(Event): void>} mapping Event mapping.
|
|
||||||
*/
|
|
||||||
constructor(dispatcher, mapping) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {import("./PointerEventHandler.js").default}
|
|
||||||
*/
|
|
||||||
this.dispatcher = dispatcher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @const
|
|
||||||
* @type {!Object<string, function(Event): void>}
|
|
||||||
*/
|
|
||||||
this.mapping_ = mapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of events supported by this source.
|
|
||||||
* @return {Array<string>} Event names
|
|
||||||
*/
|
|
||||||
getEvents() {
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EventSource;
|
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
/**
|
|
||||||
* @module ol/pointer/MouseSource
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Based on https://github.com/Polymer/PointerEvents
|
|
||||||
|
|
||||||
// Copyright (c) 2013 The Polymer Authors. All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are
|
|
||||||
// met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above
|
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
|
||||||
// in the documentation and/or other materials provided with the
|
|
||||||
// distribution.
|
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
|
||||||
// contributors may be used to endorse or promote products derived from
|
|
||||||
// this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
import EventSource from './EventSource.js';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
export const POINTER_ID = 1;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
export const POINTER_TYPE = 'mouse';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Radius around touchend that swallows mouse events.
|
|
||||||
*
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
const DEDUP_DIST = 25;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `mousedown`.
|
|
||||||
*
|
|
||||||
* @this {MouseSource}
|
|
||||||
* @param {MouseEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function 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`.
|
|
||||||
*
|
|
||||||
* @this {MouseSource}
|
|
||||||
* @param {MouseEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function mousemove(inEvent) {
|
|
||||||
if (!this.isEventSimulatedFromTouch_(inEvent)) {
|
|
||||||
const e = prepareEvent(inEvent, this.dispatcher);
|
|
||||||
this.dispatcher.move(e, inEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `mouseup`.
|
|
||||||
*
|
|
||||||
* @this {MouseSource}
|
|
||||||
* @param {MouseEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function 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`.
|
|
||||||
*
|
|
||||||
* @this {MouseSource}
|
|
||||||
* @param {MouseEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function mouseover(inEvent) {
|
|
||||||
if (!this.isEventSimulatedFromTouch_(inEvent)) {
|
|
||||||
const e = prepareEvent(inEvent, this.dispatcher);
|
|
||||||
this.dispatcher.enterOver(e, inEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `mouseout`.
|
|
||||||
*
|
|
||||||
* @this {MouseSource}
|
|
||||||
* @param {MouseEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function mouseout(inEvent) {
|
|
||||||
if (!this.isEventSimulatedFromTouch_(inEvent)) {
|
|
||||||
const e = prepareEvent(inEvent, this.dispatcher);
|
|
||||||
this.dispatcher.leaveOut(e, inEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class MouseSource extends EventSource {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("./PointerEventHandler.js").default} dispatcher Event handler.
|
|
||||||
*/
|
|
||||||
constructor(dispatcher) {
|
|
||||||
const mapping = {
|
|
||||||
'mousedown': mousedown,
|
|
||||||
'mousemove': mousemove,
|
|
||||||
'mouseup': mouseup,
|
|
||||||
'mouseover': mouseover,
|
|
||||||
'mouseout': mouseout
|
|
||||||
};
|
|
||||||
super(dispatcher, mapping);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @const
|
|
||||||
* @type {!Object<string, Event|Object>}
|
|
||||||
*/
|
|
||||||
this.pointerMap = dispatcher.pointerMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @const
|
|
||||||
* @type {Array<import("../pixel.js").Pixel>}
|
|
||||||
*/
|
|
||||||
this.lastTouches = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a copy of the original event that will be used
|
|
||||||
* for the fake pointer event.
|
|
||||||
*
|
|
||||||
* @param {Event} inEvent The in event.
|
|
||||||
* @param {import("./PointerEventHandler.js").default} dispatcher Event handler.
|
|
||||||
* @return {Object} The copied event.
|
|
||||||
*/
|
|
||||||
export function prepareEvent(inEvent, dispatcher) {
|
|
||||||
const e = dispatcher.cloneEvent(inEvent, inEvent);
|
|
||||||
|
|
||||||
// forward mouse preventDefault
|
|
||||||
const pd = e.preventDefault;
|
|
||||||
e.preventDefault = function() {
|
|
||||||
inEvent.preventDefault();
|
|
||||||
pd();
|
|
||||||
};
|
|
||||||
|
|
||||||
e.pointerId = POINTER_ID;
|
|
||||||
e.isPrimary = true;
|
|
||||||
e.pointerType = POINTER_TYPE;
|
|
||||||
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default MouseSource;
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
/**
|
|
||||||
* @module ol/pointer/MsSource
|
|
||||||
*/
|
|
||||||
// Based on https://github.com/Polymer/PointerEvents
|
|
||||||
|
|
||||||
// Copyright (c) 2013 The Polymer Authors. All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are
|
|
||||||
// met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above
|
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
|
||||||
// in the documentation and/or other materials provided with the
|
|
||||||
// distribution.
|
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
|
||||||
// contributors may be used to endorse or promote products derived from
|
|
||||||
// this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
import EventSource from './EventSource.js';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @const
|
|
||||||
* @type {Array<string>}
|
|
||||||
*/
|
|
||||||
const POINTER_TYPES = [
|
|
||||||
'',
|
|
||||||
'unavailable',
|
|
||||||
'touch',
|
|
||||||
'pen',
|
|
||||||
'mouse'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `msPointerDown`.
|
|
||||||
*
|
|
||||||
* @this {MsSource}
|
|
||||||
* @param {MSPointerEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function msPointerDown(inEvent) {
|
|
||||||
this.pointerMap[inEvent.pointerId.toString()] = inEvent;
|
|
||||||
const e = this.prepareEvent_(inEvent);
|
|
||||||
this.dispatcher.down(e, inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `msPointerMove`.
|
|
||||||
*
|
|
||||||
* @this {MsSource}
|
|
||||||
* @param {MSPointerEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function msPointerMove(inEvent) {
|
|
||||||
const e = this.prepareEvent_(inEvent);
|
|
||||||
this.dispatcher.move(e, inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `msPointerUp`.
|
|
||||||
*
|
|
||||||
* @this {MsSource}
|
|
||||||
* @param {MSPointerEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function msPointerUp(inEvent) {
|
|
||||||
const e = this.prepareEvent_(inEvent);
|
|
||||||
this.dispatcher.up(e, inEvent);
|
|
||||||
this.cleanup(inEvent.pointerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `msPointerOut`.
|
|
||||||
*
|
|
||||||
* @this {MsSource}
|
|
||||||
* @param {MSPointerEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function msPointerOut(inEvent) {
|
|
||||||
const e = this.prepareEvent_(inEvent);
|
|
||||||
this.dispatcher.leaveOut(e, inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `msPointerOver`.
|
|
||||||
*
|
|
||||||
* @this {MsSource}
|
|
||||||
* @param {MSPointerEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function msPointerOver(inEvent) {
|
|
||||||
const e = this.prepareEvent_(inEvent);
|
|
||||||
this.dispatcher.enterOver(e, inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `msPointerCancel`.
|
|
||||||
*
|
|
||||||
* @this {MsSource}
|
|
||||||
* @param {MSPointerEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function msPointerCancel(inEvent) {
|
|
||||||
const e = this.prepareEvent_(inEvent);
|
|
||||||
this.dispatcher.cancel(e, inEvent);
|
|
||||||
this.cleanup(inEvent.pointerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `msLostPointerCapture`.
|
|
||||||
*
|
|
||||||
* @this {MsSource}
|
|
||||||
* @param {MSPointerEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function msLostPointerCapture(inEvent) {
|
|
||||||
const e = this.dispatcher.makeEvent('lostpointercapture', inEvent, inEvent);
|
|
||||||
this.dispatcher.dispatchEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `msGotPointerCapture`.
|
|
||||||
*
|
|
||||||
* @this {MsSource}
|
|
||||||
* @param {MSPointerEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function msGotPointerCapture(inEvent) {
|
|
||||||
const e = this.dispatcher.makeEvent('gotpointercapture', inEvent, inEvent);
|
|
||||||
this.dispatcher.dispatchEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
class MsSource extends EventSource {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("./PointerEventHandler.js").default} dispatcher Event handler.
|
|
||||||
*/
|
|
||||||
constructor(dispatcher) {
|
|
||||||
const mapping = {
|
|
||||||
'MSPointerDown': msPointerDown,
|
|
||||||
'MSPointerMove': msPointerMove,
|
|
||||||
'MSPointerUp': msPointerUp,
|
|
||||||
'MSPointerOut': msPointerOut,
|
|
||||||
'MSPointerOver': msPointerOver,
|
|
||||||
'MSPointerCancel': msPointerCancel,
|
|
||||||
'MSGotPointerCapture': msGotPointerCapture,
|
|
||||||
'MSLostPointerCapture': msLostPointerCapture
|
|
||||||
};
|
|
||||||
super(dispatcher, mapping);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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) {
|
|
||||||
/** @type {MSPointerEvent|Object} */
|
|
||||||
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()];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MsSource;
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
/**
|
|
||||||
* @module ol/pointer/NativeSource
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Based on https://github.com/Polymer/PointerEvents
|
|
||||||
|
|
||||||
// Copyright (c) 2013 The Polymer Authors. All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are
|
|
||||||
// met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above
|
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
|
||||||
// in the documentation and/or other materials provided with the
|
|
||||||
// distribution.
|
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
|
||||||
// contributors may be used to endorse or promote products derived from
|
|
||||||
// this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
import EventSource from './EventSource.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `pointerdown`.
|
|
||||||
*
|
|
||||||
* @this {NativeSource}
|
|
||||||
* @param {Event} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function pointerDown(inEvent) {
|
|
||||||
this.dispatcher.fireNativeEvent(inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `pointermove`.
|
|
||||||
*
|
|
||||||
* @this {NativeSource}
|
|
||||||
* @param {Event} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function pointerMove(inEvent) {
|
|
||||||
this.dispatcher.fireNativeEvent(inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `pointerup`.
|
|
||||||
*
|
|
||||||
* @this {NativeSource}
|
|
||||||
* @param {Event} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function pointerUp(inEvent) {
|
|
||||||
this.dispatcher.fireNativeEvent(inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `pointerout`.
|
|
||||||
*
|
|
||||||
* @this {NativeSource}
|
|
||||||
* @param {Event} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function pointerOut(inEvent) {
|
|
||||||
this.dispatcher.fireNativeEvent(inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `pointerover`.
|
|
||||||
*
|
|
||||||
* @this {NativeSource}
|
|
||||||
* @param {Event} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function pointerOver(inEvent) {
|
|
||||||
this.dispatcher.fireNativeEvent(inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `pointercancel`.
|
|
||||||
*
|
|
||||||
* @this {NativeSource}
|
|
||||||
* @param {Event} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function pointerCancel(inEvent) {
|
|
||||||
this.dispatcher.fireNativeEvent(inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `lostpointercapture`.
|
|
||||||
*
|
|
||||||
* @this {NativeSource}
|
|
||||||
* @param {Event} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function lostPointerCapture(inEvent) {
|
|
||||||
this.dispatcher.fireNativeEvent(inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `gotpointercapture`.
|
|
||||||
*
|
|
||||||
* @this {NativeSource}
|
|
||||||
* @param {Event} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function gotPointerCapture(inEvent) {
|
|
||||||
this.dispatcher.fireNativeEvent(inEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
class NativeSource extends EventSource {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("./PointerEventHandler.js").default} dispatcher Event handler.
|
|
||||||
*/
|
|
||||||
constructor(dispatcher) {
|
|
||||||
const mapping = {
|
|
||||||
'pointerdown': pointerDown,
|
|
||||||
'pointermove': pointerMove,
|
|
||||||
'pointerup': pointerUp,
|
|
||||||
'pointerout': pointerOut,
|
|
||||||
'pointerover': pointerOver,
|
|
||||||
'pointercancel': pointerCancel,
|
|
||||||
'gotpointercapture': gotPointerCapture,
|
|
||||||
'lostpointercapture': lostPointerCapture
|
|
||||||
};
|
|
||||||
super(dispatcher, mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default NativeSource;
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
/**
|
|
||||||
* @module ol/pointer/PointerEvent
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Based on https://github.com/Polymer/PointerEvents
|
|
||||||
|
|
||||||
// Copyright (c) 2013 The Polymer Authors. All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are
|
|
||||||
// met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above
|
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
|
||||||
// in the documentation and/or other materials provided with the
|
|
||||||
// distribution.
|
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
|
||||||
// contributors may be used to endorse or promote products derived from
|
|
||||||
// this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
import _Event from '../events/Event.js';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the `buttons` property supported?
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
let HAS_BUTTONS = false;
|
|
||||||
|
|
||||||
|
|
||||||
class PointerEvent extends _Event {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class for pointer events.
|
|
||||||
*
|
|
||||||
* This class is used as an abstraction for mouse events,
|
|
||||||
* touch events and even native pointer events.
|
|
||||||
*
|
|
||||||
* @param {string} type The type of the event to create.
|
|
||||||
* @param {Event} originalEvent The event.
|
|
||||||
* @param {Object<string, ?>=} opt_eventDict An optional dictionary of
|
|
||||||
* initial event properties.
|
|
||||||
*/
|
|
||||||
constructor(type, originalEvent, opt_eventDict) {
|
|
||||||
super(type);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @const
|
|
||||||
* @type {Event}
|
|
||||||
*/
|
|
||||||
this.originalEvent = originalEvent;
|
|
||||||
|
|
||||||
const eventDict = opt_eventDict ? opt_eventDict : {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.buttons = getButtons(eventDict);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.pressure = getPressure(eventDict, this.buttons);
|
|
||||||
|
|
||||||
// MouseEvent related properties
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Object}
|
|
||||||
*/
|
|
||||||
this.view = 'view' in eventDict ? eventDict['view'] : null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.detail = 'detail' in eventDict ? eventDict['detail'] : null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.button = 'button' in eventDict ? eventDict['button'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Node}
|
|
||||||
*/
|
|
||||||
this.relatedTarget = 'relatedTarget' in eventDict ?
|
|
||||||
eventDict['relatedTarget'] : null;
|
|
||||||
|
|
||||||
// PointerEvent related properties
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @const
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.width = 'width' in eventDict ? eventDict['width'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.height = 'height' in eventDict ? eventDict['height'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false;
|
|
||||||
|
|
||||||
// keep the semantics of preventDefault
|
|
||||||
if (originalEvent.preventDefault) {
|
|
||||||
this.preventDefault = function() {
|
|
||||||
originalEvent.preventDefault();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object<string, ?>} eventDict The event dictionary.
|
|
||||||
* @return {number} Button indicator.
|
|
||||||
*/
|
|
||||||
function 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object<string, ?>} eventDict The event dictionary.
|
|
||||||
* @param {number} buttons Button indicator.
|
|
||||||
* @return {number} The pressure.
|
|
||||||
*/
|
|
||||||
function 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the `buttons` property is supported.
|
|
||||||
*/
|
|
||||||
(function() {
|
|
||||||
try {
|
|
||||||
const ev = new MouseEvent('click', {buttons: 1});
|
|
||||||
HAS_BUTTONS = ev.buttons === 1;
|
|
||||||
} catch (e) {
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
export default PointerEvent;
|
|
||||||
@@ -1,417 +0,0 @@
|
|||||||
/**
|
|
||||||
* @module ol/pointer/PointerEventHandler
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Based on https://github.com/Polymer/PointerEvents
|
|
||||||
|
|
||||||
// Copyright (c) 2013 The Polymer Authors. All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are
|
|
||||||
// met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above
|
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
|
||||||
// in the documentation and/or other materials provided with the
|
|
||||||
// distribution.
|
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
|
||||||
// contributors may be used to endorse or promote products derived from
|
|
||||||
// this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
import {listen, unlisten} from '../events.js';
|
|
||||||
import EventTarget from '../events/Target.js';
|
|
||||||
import PointerEventType from './EventType.js';
|
|
||||||
import MouseSource, {prepareEvent as prepareMouseEvent} from './MouseSource.js';
|
|
||||||
import MsSource from './MsSource.js';
|
|
||||||
import NativeSource from './NativeSource.js';
|
|
||||||
import PointerEvent from './PointerEvent.js';
|
|
||||||
import TouchSource from './TouchSource.js';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties to copy when cloning an event, with default values.
|
|
||||||
* @type {Array<Array>}
|
|
||||||
*/
|
|
||||||
const CLONE_PROPS = [
|
|
||||||
// MouseEvent
|
|
||||||
['bubbles', false],
|
|
||||||
['cancelable', false],
|
|
||||||
['view', null],
|
|
||||||
['detail', null],
|
|
||||||
['screenX', 0],
|
|
||||||
['screenY', 0],
|
|
||||||
['clientX', 0],
|
|
||||||
['clientY', 0],
|
|
||||||
['ctrlKey', false],
|
|
||||||
['altKey', false],
|
|
||||||
['shiftKey', false],
|
|
||||||
['metaKey', false],
|
|
||||||
['button', 0],
|
|
||||||
['relatedTarget', null],
|
|
||||||
// DOM Level 3
|
|
||||||
['buttons', 0],
|
|
||||||
// PointerEvent
|
|
||||||
['pointerId', 0],
|
|
||||||
['width', 0],
|
|
||||||
['height', 0],
|
|
||||||
['pressure', 0],
|
|
||||||
['tiltX', 0],
|
|
||||||
['tiltY', 0],
|
|
||||||
['pointerType', ''],
|
|
||||||
['hwTimestamp', 0],
|
|
||||||
['isPrimary', false],
|
|
||||||
// event instance
|
|
||||||
['type', ''],
|
|
||||||
['target', null],
|
|
||||||
['currentTarget', null],
|
|
||||||
['which', 0]
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
class PointerEventHandler extends EventTarget {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Element|HTMLDocument} element Viewport element.
|
|
||||||
*/
|
|
||||||
constructor(element) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @const
|
|
||||||
* @private
|
|
||||||
* @type {Element|HTMLDocument}
|
|
||||||
*/
|
|
||||||
this.element_ = element;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @const
|
|
||||||
* @type {!Object<string, Event|Object>}
|
|
||||||
*/
|
|
||||||
this.pointerMap = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Object<string, function(Event): void>}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.eventMap_ = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Array<import("./EventSource.js").default>}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this.eventSourceList_ = [];
|
|
||||||
|
|
||||||
this.registerSources();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the event sources (mouse, touch and native pointers)
|
|
||||||
* that generate pointer events.
|
|
||||||
*/
|
|
||||||
registerSources() {
|
|
||||||
if ('PointerEvent' in window) {
|
|
||||||
this.registerSource('native', new NativeSource(this));
|
|
||||||
} else if (window.navigator.msPointerEnabled) {
|
|
||||||
this.registerSource('ms', new MsSource(this));
|
|
||||||
} else {
|
|
||||||
const mouseSource = new MouseSource(this);
|
|
||||||
this.registerSource('mouse', mouseSource);
|
|
||||||
|
|
||||||
if ('ontouchstart' in window) {
|
|
||||||
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 {import("./EventSource.js").default} source The source event.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the events for all registered event sources.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
register_() {
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
unregister_() {
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
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 {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 {PointerEvent} The wrapped event.
|
|
||||||
*/
|
|
||||||
wrapMouseEvent(eventType, event) {
|
|
||||||
const pointerEvent = this.makeEvent(
|
|
||||||
eventType, prepareMouseEvent(event, this), event);
|
|
||||||
return pointerEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
disposeInternal() {
|
|
||||||
this.unregister_();
|
|
||||||
super.disposeInternal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PointerEventHandler;
|
|
||||||
@@ -1,424 +0,0 @@
|
|||||||
/**
|
|
||||||
* @module ol/pointer/TouchSource
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Based on https://github.com/Polymer/PointerEvents
|
|
||||||
|
|
||||||
// Copyright (c) 2013 The Polymer Authors. All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are
|
|
||||||
// met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above
|
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
|
||||||
// in the documentation and/or other materials provided with the
|
|
||||||
// distribution.
|
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
|
||||||
// contributors may be used to endorse or promote products derived from
|
|
||||||
// this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
import {remove} from '../array.js';
|
|
||||||
import EventSource from './EventSource.js';
|
|
||||||
import {POINTER_ID} from './MouseSource.js';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
const CLICK_COUNT_TIMEOUT = 200;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
const POINTER_TYPE = 'touch';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `touchstart`, triggers `pointerover`,
|
|
||||||
* `pointerenter` and `pointerdown` events.
|
|
||||||
*
|
|
||||||
* @this {TouchSource}
|
|
||||||
* @param {TouchEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function touchstart(inEvent) {
|
|
||||||
this.vacuumTouches_(inEvent);
|
|
||||||
this.setPrimaryTouch_(inEvent.changedTouches[0]);
|
|
||||||
this.dedupSynthMouse_(inEvent);
|
|
||||||
this.clickCount_++;
|
|
||||||
this.processTouches_(inEvent, this.overDown_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `touchmove`.
|
|
||||||
*
|
|
||||||
* @this {TouchSource}
|
|
||||||
* @param {TouchEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function touchmove(inEvent) {
|
|
||||||
this.processTouches_(inEvent, this.moveOverOut_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `touchend`, triggers `pointerup`,
|
|
||||||
* `pointerout` and `pointerleave` events.
|
|
||||||
*
|
|
||||||
* @this {TouchSource}
|
|
||||||
* @param {TouchEvent} inEvent The event.
|
|
||||||
*/
|
|
||||||
function touchend(inEvent) {
|
|
||||||
this.dedupSynthMouse_(inEvent);
|
|
||||||
this.processTouches_(inEvent, this.upOut_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler for `touchcancel`, triggers `pointercancel`,
|
|
||||||
* `pointerout` and `pointerleave` events.
|
|
||||||
*
|
|
||||||
* @this {TouchSource}
|
|
||||||
* @param {TouchEvent} inEvent The in event.
|
|
||||||
*/
|
|
||||||
function touchcancel(inEvent) {
|
|
||||||
this.processTouches_(inEvent, this.cancelOut_);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TouchSource extends EventSource {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("./PointerEventHandler.js").default} dispatcher The event handler.
|
|
||||||
* @param {import("./MouseSource.js").default} mouseSource Mouse source.
|
|
||||||
*/
|
|
||||||
constructor(dispatcher, mouseSource) {
|
|
||||||
const mapping = {
|
|
||||||
'touchstart': touchstart,
|
|
||||||
'touchmove': touchmove,
|
|
||||||
'touchend': touchend,
|
|
||||||
'touchcancel': touchcancel
|
|
||||||
};
|
|
||||||
super(dispatcher, mapping);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @const
|
|
||||||
* @type {!Object<string, Event|Object>}
|
|
||||||
*/
|
|
||||||
this.pointerMap = dispatcher.pointerMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @const
|
|
||||||
* @type {import("./MouseSource.js").default}
|
|
||||||
*/
|
|
||||||
this.mouseSource = mouseSource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {number|undefined}
|
|
||||||
*/
|
|
||||||
this.firstTouchId_ = undefined;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.clickCount_ = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {?}
|
|
||||||
*/
|
|
||||||
this.resetId_;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mouse event timeout: This should be long enough to
|
|
||||||
* ignore compat mouse events made by touch.
|
|
||||||
* @private
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.dedupTimeout_ = 2500;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @param {Touch} inTouch The in touch.
|
|
||||||
* @return {boolean} True, if this is the primary touch.
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
* @param {PointerEvent} inPointer The in pointer object.
|
|
||||||
*/
|
|
||||||
removePrimaryPointer_(inPointer) {
|
|
||||||
if (inPointer.isPrimary) {
|
|
||||||
this.firstTouchId_ = undefined;
|
|
||||||
this.resetClickCount_();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
resetClickCount_() {
|
|
||||||
this.resetId_ = setTimeout(
|
|
||||||
this.resetClickCountHandler_.bind(this),
|
|
||||||
CLICK_COUNT_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
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.radiusX || 0;
|
|
||||||
e.height = inTouch.radiusY || 0;
|
|
||||||
e.pressure = 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): void} 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 = Number(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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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;
|
|
||||||
/** @type {Object} */ (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
|
|
||||||
/** @type {Object} */ (event).target = outTarget;
|
|
||||||
/** @type {Object} */ (event).relatedTarget = null;
|
|
||||||
this.cancelOut_(browserEvent, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pointer.out = event;
|
|
||||||
pointer.outTarget = event.target;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TouchSource;
|
|
||||||
@@ -1,11 +1,24 @@
|
|||||||
import Map from '../../../../src/ol/Map.js';
|
import Map from '../../../../src/ol/Map.js';
|
||||||
import View from '../../../../src/ol/View.js';
|
import View from '../../../../src/ol/View.js';
|
||||||
import ZoomSlider from '../../../../src/ol/control/ZoomSlider.js';
|
import ZoomSlider from '../../../../src/ol/control/ZoomSlider.js';
|
||||||
import PointerEvent from '../../../../src/ol/pointer/PointerEvent.js';
|
import Event from '../../../../src/ol/events/Event.js';
|
||||||
|
import EventTarget from '../../../../src/ol/events/Target.js';
|
||||||
|
|
||||||
describe('ol.control.ZoomSlider', function() {
|
describe('ol.control.ZoomSlider', function() {
|
||||||
let map, target, zoomslider;
|
let map, target, zoomslider;
|
||||||
|
|
||||||
|
const createElement = document.createElement;
|
||||||
|
function createEventElement(type) {
|
||||||
|
const element = createElement.call(document, type);
|
||||||
|
const eventTarget = new EventTarget();
|
||||||
|
element.listeners_ = {};
|
||||||
|
element.dispatching_ = {};
|
||||||
|
element.pendingRemovals_ = {};
|
||||||
|
element.dispatchEvent = eventTarget.dispatchEvent.bind(element);
|
||||||
|
element.addEventListener = eventTarget.addEventListener.bind(element);
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
target = document.createElement('div');
|
target = document.createElement('div');
|
||||||
document.body.appendChild(target);
|
document.body.appendChild(target);
|
||||||
@@ -102,138 +115,142 @@ describe('ol.control.ZoomSlider', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('[horizontal] handles a drag sequence', function() {
|
it('[horizontal] handles a drag sequence', function() {
|
||||||
|
document.createElement = createEventElement;
|
||||||
const control = new ZoomSlider();
|
const control = new ZoomSlider();
|
||||||
map.addControl(control);
|
map.addControl(control);
|
||||||
|
document.createElement = createElement;
|
||||||
map.getView().setZoom(0);
|
map.getView().setZoom(0);
|
||||||
control.element.style.width = '500px';
|
control.element.style.width = '500px';
|
||||||
control.element.style.height = '10px';
|
control.element.style.height = '10px';
|
||||||
control.element.firstChild.style.width = '100px';
|
control.element.firstChild.style.width = '100px';
|
||||||
control.element.firstChild.style.height = '10px';
|
control.element.firstChild.style.height = '10px';
|
||||||
map.renderSync();
|
map.renderSync();
|
||||||
const dragger = control.dragger_;
|
const event = new Event();
|
||||||
const event = new PointerEvent('pointerdown', {
|
event.type = 'pointerdown',
|
||||||
target: control.element.firstElementChild
|
event.target = control.element.firstElementChild;
|
||||||
});
|
|
||||||
event.clientX = control.widthLimit_;
|
event.clientX = control.widthLimit_;
|
||||||
event.clientY = 0;
|
event.clientY = 0;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(16);
|
expect(control.currentResolution_).to.be(16);
|
||||||
expect(control.dragging_).to.be(true);
|
expect(control.dragging_).to.be(true);
|
||||||
expect(control.dragListenerKeys_.length).to.be(4);
|
expect(control.dragListenerKeys_.length).to.be(2);
|
||||||
event.type = 'pointermove';
|
event.type = 'pointermove';
|
||||||
event.clientX = 6 * control.widthLimit_ / 8;
|
event.clientX = 6 * control.widthLimit_ / 8;
|
||||||
event.clientY = 0;
|
event.clientY = 0;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(4);
|
expect(control.currentResolution_).to.be(4);
|
||||||
event.type = 'pointermove';
|
event.type = 'pointermove';
|
||||||
event.clientX = 4 * control.widthLimit_ / 8;
|
event.clientX = 4 * control.widthLimit_ / 8;
|
||||||
event.clientY = 0;
|
event.clientY = 0;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
event.type = 'pointerup';
|
event.type = 'pointerup';
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(1);
|
expect(control.currentResolution_).to.be(1);
|
||||||
expect(control.dragListenerKeys_.length).to.be(0);
|
expect(control.dragListenerKeys_.length).to.be(0);
|
||||||
expect(control.dragging_).to.be(false);
|
expect(control.dragging_).to.be(false);
|
||||||
});
|
});
|
||||||
it('[horizontal] handles a drag sequence ending outside its bounds', function() {
|
it('[horizontal] handles a drag sequence ending outside its bounds', function() {
|
||||||
|
document.createElement = createEventElement;
|
||||||
const control = new ZoomSlider();
|
const control = new ZoomSlider();
|
||||||
map.addControl(control);
|
map.addControl(control);
|
||||||
|
document.createElement = createElement;
|
||||||
map.getView().setZoom(0);
|
map.getView().setZoom(0);
|
||||||
control.element.style.width = '500px';
|
control.element.style.width = '500px';
|
||||||
control.element.style.height = '10px';
|
control.element.style.height = '10px';
|
||||||
control.element.firstChild.style.width = '100px';
|
control.element.firstChild.style.width = '100px';
|
||||||
control.element.firstChild.style.height = '10px';
|
control.element.firstChild.style.height = '10px';
|
||||||
map.renderSync();
|
map.renderSync();
|
||||||
const dragger = control.dragger_;
|
const event = new Event();
|
||||||
const event = new PointerEvent('pointerdown', {
|
event.type = 'pointerdown';
|
||||||
target: control.element.firstElementChild
|
event.target = control.element.firstElementChild;
|
||||||
});
|
|
||||||
event.clientX = control.widthLimit_;
|
event.clientX = control.widthLimit_;
|
||||||
event.clientY = 0;
|
event.clientY = 0;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(16);
|
expect(control.currentResolution_).to.be(16);
|
||||||
expect(control.dragging_).to.be(true);
|
expect(control.dragging_).to.be(true);
|
||||||
expect(control.dragListenerKeys_.length).to.be(4);
|
expect(control.dragListenerKeys_.length).to.be(2);
|
||||||
event.type = 'pointermove';
|
event.type = 'pointermove';
|
||||||
event.clientX = 6 * control.widthLimit_ / 8;
|
event.clientX = 6 * control.widthLimit_ / 8;
|
||||||
event.clientY = 0;
|
event.clientY = 0;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(4);
|
expect(control.currentResolution_).to.be(4);
|
||||||
event.type = 'pointermove';
|
event.type = 'pointermove';
|
||||||
event.clientX = 12 * control.widthLimit_ / 8;
|
event.clientX = 12 * control.widthLimit_ / 8;
|
||||||
event.clientY = 0;
|
event.clientY = 0;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
event.type = 'pointerup';
|
event.type = 'pointerup';
|
||||||
event.target = 'document';
|
event.target = 'document';
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.dragListenerKeys_.length).to.be(0);
|
expect(control.dragListenerKeys_.length).to.be(0);
|
||||||
expect(control.dragging_).to.be(false);
|
expect(control.dragging_).to.be(false);
|
||||||
expect(control.currentResolution_).to.be(16);
|
expect(control.currentResolution_).to.be(16);
|
||||||
});
|
});
|
||||||
it('[vertical] handles a drag sequence', function() {
|
it('[vertical] handles a drag sequence', function() {
|
||||||
|
document.createElement = createEventElement;
|
||||||
const control = new ZoomSlider();
|
const control = new ZoomSlider();
|
||||||
control.element.style.width = '10px';
|
control.element.style.width = '10px';
|
||||||
control.element.style.height = '100px';
|
control.element.style.height = '100px';
|
||||||
control.element.firstChild.style.width = '10px';
|
control.element.firstChild.style.width = '10px';
|
||||||
control.element.firstChild.style.height = '20px';
|
control.element.firstChild.style.height = '20px';
|
||||||
map.addControl(control);
|
map.addControl(control);
|
||||||
|
document.createElement = createElement;
|
||||||
map.getView().setZoom(8);
|
map.getView().setZoom(8);
|
||||||
map.renderSync();
|
map.renderSync();
|
||||||
const dragger = control.dragger_;
|
const event = new Event();
|
||||||
const event = new PointerEvent('pointerdown', {
|
event.type = 'pointerdown';
|
||||||
target: control.element.firstElementChild
|
event.target = control.element.firstElementChild;
|
||||||
});
|
|
||||||
event.clientX = 0;
|
event.clientX = 0;
|
||||||
event.clientY = 0;
|
event.clientY = 0;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(0.0625);
|
expect(control.currentResolution_).to.be(0.0625);
|
||||||
expect(control.dragging_).to.be(true);
|
expect(control.dragging_).to.be(true);
|
||||||
expect(control.dragListenerKeys_.length).to.be(4);
|
expect(control.dragListenerKeys_.length).to.be(2);
|
||||||
event.type = 'pointermove';
|
event.type = 'pointermove';
|
||||||
event.clientX = 0;
|
event.clientX = 0;
|
||||||
event.clientY = 2 * control.heightLimit_ / 8;
|
event.clientY = 2 * control.heightLimit_ / 8;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(0.25);
|
expect(control.currentResolution_).to.be(0.25);
|
||||||
event.type = 'pointermove';
|
event.type = 'pointermove';
|
||||||
event.clientX = 0;
|
event.clientX = 0;
|
||||||
event.clientY = 4 * control.heightLimit_ / 8;
|
event.clientY = 4 * control.heightLimit_ / 8;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
event.type = 'pointerup';
|
event.type = 'pointerup';
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(1);
|
expect(control.currentResolution_).to.be(1);
|
||||||
expect(control.dragListenerKeys_.length).to.be(0);
|
expect(control.dragListenerKeys_.length).to.be(0);
|
||||||
expect(control.dragging_).to.be(false);
|
expect(control.dragging_).to.be(false);
|
||||||
});
|
});
|
||||||
it('[vertical] handles a drag sequence ending outside its bounds', function() {
|
it('[vertical] handles a drag sequence ending outside its bounds', function() {
|
||||||
|
document.createElement = createEventElement;
|
||||||
const control = new ZoomSlider();
|
const control = new ZoomSlider();
|
||||||
control.element.style.width = '10px';
|
control.element.style.width = '10px';
|
||||||
control.element.style.height = '100px';
|
control.element.style.height = '100px';
|
||||||
control.element.firstChild.style.width = '10px';
|
control.element.firstChild.style.width = '10px';
|
||||||
control.element.firstChild.style.height = '20px';
|
control.element.firstChild.style.height = '20px';
|
||||||
map.addControl(control);
|
map.addControl(control);
|
||||||
|
document.createElement = createElement;
|
||||||
map.getView().setZoom(8);
|
map.getView().setZoom(8);
|
||||||
map.renderSync();
|
map.renderSync();
|
||||||
const dragger = control.dragger_;
|
const event = new Event();
|
||||||
const event = new PointerEvent('pointerdown', {
|
event.type = 'pointerdown';
|
||||||
target: control.element.firstElementChild
|
event.target = control.element.firstElementChild;
|
||||||
});
|
|
||||||
event.clientX = 0;
|
event.clientX = 0;
|
||||||
event.clientY = 0;
|
event.clientY = 0;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(0.0625);
|
expect(control.currentResolution_).to.be(0.0625);
|
||||||
expect(control.dragging_).to.be(true);
|
expect(control.dragging_).to.be(true);
|
||||||
expect(control.dragListenerKeys_.length).to.be(4);
|
expect(control.dragListenerKeys_.length).to.be(2);
|
||||||
event.type = 'pointermove';
|
event.type = 'pointermove';
|
||||||
event.clientX = 0;
|
event.clientX = 0;
|
||||||
event.clientY = 2 * control.heightLimit_ / 8;
|
event.clientY = 2 * control.heightLimit_ / 8;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(0.25);
|
expect(control.currentResolution_).to.be(0.25);
|
||||||
event.type = 'pointermove';
|
event.type = 'pointermove';
|
||||||
event.clientX = 0;
|
event.clientX = 0;
|
||||||
event.clientY = 12 * control.heightLimit_ / 8;
|
event.clientY = 12 * control.heightLimit_ / 8;
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
event.type = 'pointerup';
|
event.type = 'pointerup';
|
||||||
dragger.dispatchEvent(event);
|
control.element.dispatchEvent(event);
|
||||||
expect(control.currentResolution_).to.be(16);
|
expect(control.currentResolution_).to.be(16);
|
||||||
expect(control.dragListenerKeys_.length).to.be(0);
|
expect(control.dragListenerKeys_.length).to.be(0);
|
||||||
expect(control.dragging_).to.be(false);
|
expect(control.dragging_).to.be(false);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import MapBrowserPointerEvent from '../../../../src/ol/MapBrowserPointerEvent.js
|
|||||||
import View from '../../../../src/ol/View.js';
|
import View from '../../../../src/ol/View.js';
|
||||||
import DragRotateAndZoom from '../../../../src/ol/interaction/DragRotateAndZoom.js';
|
import DragRotateAndZoom from '../../../../src/ol/interaction/DragRotateAndZoom.js';
|
||||||
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
||||||
import PointerEvent from '../../../../src/ol/pointer/PointerEvent.js';
|
import Event from '../../../../src/ol/events/Event.js';
|
||||||
import VectorSource from '../../../../src/ol/source/Vector.js';
|
import VectorSource from '../../../../src/ol/source/Vector.js';
|
||||||
|
|
||||||
describe('ol.interaction.DragRotateAndZoom', function() {
|
describe('ol.interaction.DragRotateAndZoom', function() {
|
||||||
@@ -57,9 +57,12 @@ describe('ol.interaction.DragRotateAndZoom', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not rotate when rotation is disabled on the view', function() {
|
it('does not rotate when rotation is disabled on the view', function() {
|
||||||
let event = new MapBrowserPointerEvent('pointermove', map,
|
const pointerEvent = new Event();
|
||||||
new PointerEvent('pointermove', {clientX: 20, clientY: 10}, {pointerType: 'mouse'}),
|
pointerEvent.type = 'pointermove';
|
||||||
true);
|
pointerEvent.clientX = 20;
|
||||||
|
pointerEvent.clientY = 10;
|
||||||
|
pointerEvent.pointerType = 'mouse';
|
||||||
|
let event = new MapBrowserPointerEvent('pointermove', map, pointerEvent, true);
|
||||||
interaction.lastAngle_ = Math.PI;
|
interaction.lastAngle_ = Math.PI;
|
||||||
|
|
||||||
let callCount = 0;
|
let callCount = 0;
|
||||||
@@ -85,9 +88,11 @@ describe('ol.interaction.DragRotateAndZoom', function() {
|
|||||||
callCount++;
|
callCount++;
|
||||||
});
|
});
|
||||||
|
|
||||||
event = new MapBrowserPointerEvent('pointermove', map,
|
pointerEvent.type = 'pointermove';
|
||||||
new PointerEvent('pointermove', {clientX: 24, clientY: 16}, {pointerType: 'mouse'}),
|
pointerEvent.clientX = 24;
|
||||||
true);
|
pointerEvent.clientY = 16;
|
||||||
|
pointerEvent.pointerType = 'mouse';
|
||||||
|
event = new MapBrowserPointerEvent('pointermove', map, pointerEvent, true);
|
||||||
|
|
||||||
interaction.handleDragEvent(event);
|
interaction.handleDragEvent(event);
|
||||||
expect(callCount).to.be(0);
|
expect(callCount).to.be(0);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import Polygon from '../../../../src/ol/geom/Polygon.js';
|
|||||||
import Draw, {createRegularPolygon, createBox} from '../../../../src/ol/interaction/Draw.js';
|
import Draw, {createRegularPolygon, createBox} from '../../../../src/ol/interaction/Draw.js';
|
||||||
import Interaction from '../../../../src/ol/interaction/Interaction.js';
|
import Interaction from '../../../../src/ol/interaction/Interaction.js';
|
||||||
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
||||||
import PointerEvent from '../../../../src/ol/pointer/PointerEvent.js';
|
import Event from '../../../../src/ol/events/Event.js';
|
||||||
import VectorSource from '../../../../src/ol/source/Vector.js';
|
import VectorSource from '../../../../src/ol/source/Vector.js';
|
||||||
|
|
||||||
|
|
||||||
@@ -69,14 +69,14 @@ describe('ol.interaction.Draw', function() {
|
|||||||
// calculated in case body has top < 0 (test runner with small window)
|
// calculated in case body has top < 0 (test runner with small window)
|
||||||
const position = viewport.getBoundingClientRect();
|
const position = viewport.getBoundingClientRect();
|
||||||
const shiftKey = opt_shiftKey !== undefined ? opt_shiftKey : false;
|
const shiftKey = opt_shiftKey !== undefined ? opt_shiftKey : false;
|
||||||
const event = new PointerEvent(type, {
|
const event = new Event();
|
||||||
clientX: position.left + x + width / 2,
|
event.type = type;
|
||||||
clientY: position.top + y + height / 2,
|
event.clientX = position.left + x + width / 2;
|
||||||
shiftKey: shiftKey,
|
event.clientY = position.top + y + height / 2;
|
||||||
preventDefault: function() {}
|
event.shiftKey = shiftKey;
|
||||||
}, {
|
event.preventDefault = function() {};
|
||||||
pointerType: 'mouse'
|
event.pointerType = 'mouse';
|
||||||
});
|
event.pointerId = 0;
|
||||||
const simulatedEvent = new MapBrowserPointerEvent(type, map, event);
|
const simulatedEvent = new MapBrowserPointerEvent(type, map, event);
|
||||||
map.handleMapBrowserEvent(simulatedEvent);
|
map.handleMapBrowserEvent(simulatedEvent);
|
||||||
return simulatedEvent;
|
return simulatedEvent;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import Map from '../../../../src/ol/Map.js';
|
|||||||
import MapBrowserPointerEvent from '../../../../src/ol/MapBrowserPointerEvent.js';
|
import MapBrowserPointerEvent from '../../../../src/ol/MapBrowserPointerEvent.js';
|
||||||
import View from '../../../../src/ol/View.js';
|
import View from '../../../../src/ol/View.js';
|
||||||
import ExtentInteraction from '../../../../src/ol/interaction/Extent.js';
|
import ExtentInteraction from '../../../../src/ol/interaction/Extent.js';
|
||||||
import PointerEvent from '../../../../src/ol/pointer/PointerEvent.js';
|
import Event from '../../../../src/ol/events/Event.js';
|
||||||
|
|
||||||
describe('ol.interaction.Extent', function() {
|
describe('ol.interaction.Extent', function() {
|
||||||
let map, interaction;
|
let map, interaction;
|
||||||
@@ -50,14 +50,14 @@ describe('ol.interaction.Extent', function() {
|
|||||||
// calculated in case body has top < 0 (test runner with small window)
|
// calculated in case body has top < 0 (test runner with small window)
|
||||||
const position = viewport.getBoundingClientRect();
|
const position = viewport.getBoundingClientRect();
|
||||||
const shiftKey = opt_shiftKey !== undefined ? opt_shiftKey : false;
|
const shiftKey = opt_shiftKey !== undefined ? opt_shiftKey : false;
|
||||||
const pointerEvent = new PointerEvent(type, {
|
const pointerEvent = new Event();
|
||||||
type: type,
|
pointerEvent.type = type;
|
||||||
button: button,
|
pointerEvent.button = button;
|
||||||
clientX: position.left + x + width / 2,
|
pointerEvent.clientX = position.left + x + width / 2;
|
||||||
clientY: position.top - y + height / 2,
|
pointerEvent.clientY = position.top - y + height / 2;
|
||||||
shiftKey: shiftKey,
|
pointerEvent.shiftKey = shiftKey;
|
||||||
preventDefault: function() {}
|
pointerEvent.pointerId = 0;
|
||||||
});
|
pointerEvent.preventDefault = function() {};
|
||||||
const event = new MapBrowserPointerEvent(type, map, pointerEvent);
|
const event = new MapBrowserPointerEvent(type, map, pointerEvent);
|
||||||
event.pointerEvent.pointerId = 1;
|
event.pointerEvent.pointerId = 1;
|
||||||
map.handleMapBrowserEvent(event);
|
map.handleMapBrowserEvent(event);
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import Point from '../../../../src/ol/geom/Point.js';
|
|||||||
import Polygon from '../../../../src/ol/geom/Polygon.js';
|
import Polygon from '../../../../src/ol/geom/Polygon.js';
|
||||||
import Modify, {ModifyEvent} from '../../../../src/ol/interaction/Modify.js';
|
import Modify, {ModifyEvent} from '../../../../src/ol/interaction/Modify.js';
|
||||||
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
||||||
import PointerEvent from '../../../../src/ol/pointer/PointerEvent.js';
|
|
||||||
import VectorSource from '../../../../src/ol/source/Vector.js';
|
import VectorSource from '../../../../src/ol/source/Vector.js';
|
||||||
|
import Event from '../../../../src/ol/events/Event.js';
|
||||||
|
|
||||||
|
|
||||||
describe('ol.interaction.Modify', function() {
|
describe('ol.interaction.Modify', function() {
|
||||||
@@ -81,19 +81,17 @@ describe('ol.interaction.Modify', function() {
|
|||||||
const viewport = map.getViewport();
|
const viewport = map.getViewport();
|
||||||
// calculated in case body has top < 0 (test runner with small window)
|
// calculated in case body has top < 0 (test runner with small window)
|
||||||
const position = viewport.getBoundingClientRect();
|
const position = viewport.getBoundingClientRect();
|
||||||
const pointerEvent = new PointerEvent(type, {
|
const pointerEvent = new Event();
|
||||||
type: type,
|
pointerEvent.type = type;
|
||||||
clientX: position.left + x + width / 2,
|
pointerEvent.clientX = position.left + x + width / 2;
|
||||||
clientY: position.top + y + height / 2,
|
pointerEvent.clientY = position.top + y + height / 2;
|
||||||
shiftKey: modifiers.shift || false,
|
pointerEvent.shiftKey = modifiers.shift || false;
|
||||||
altKey: modifiers.alt || false,
|
pointerEvent.altKey = modifiers.alt || false;
|
||||||
preventDefault: function() {}
|
pointerEvent.pointerId = 1;
|
||||||
}, {
|
pointerEvent.preventDefault = function() {};
|
||||||
button: button,
|
pointerEvent.button = button;
|
||||||
isPrimary: true
|
pointerEvent.isPrimary = true;
|
||||||
});
|
|
||||||
const event = new MapBrowserPointerEvent(type, map, pointerEvent);
|
const event = new MapBrowserPointerEvent(type, map, pointerEvent);
|
||||||
event.pointerEvent.pointerId = 1;
|
|
||||||
map.handleMapBrowserEvent(event);
|
map.handleMapBrowserEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Map from '../../../../src/ol/Map.js';
|
import Map from '../../../../src/ol/Map.js';
|
||||||
import MapBrowserPointerEvent from '../../../../src/ol/MapBrowserPointerEvent.js';
|
import MapBrowserPointerEvent from '../../../../src/ol/MapBrowserPointerEvent.js';
|
||||||
import PointerEvent from '../../../../src/ol/pointer/PointerEvent.js';
|
import Event from '../../../../src/ol/events/Event.js';
|
||||||
import PointerInteraction from '../../../../src/ol/interaction/Pointer.js';
|
import PointerInteraction from '../../../../src/ol/interaction/Pointer.js';
|
||||||
|
|
||||||
describe('ol.interaction.Pointer', function() {
|
describe('ol.interaction.Pointer', function() {
|
||||||
@@ -12,12 +12,12 @@ describe('ol.interaction.Pointer', function() {
|
|||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
const type = 'pointerdown';
|
const type = 'pointerdown';
|
||||||
const pointerEvent = new PointerEvent(type, {
|
const pointerEvent = new Event();
|
||||||
type: type,
|
pointerEvent.type = type;
|
||||||
preventDefault: function() {
|
pointerEvent.pointerId = 0;
|
||||||
defaultPrevented = true;
|
pointerEvent.preventDefault = function() {
|
||||||
}
|
defaultPrevented = true;
|
||||||
});
|
};
|
||||||
event = new MapBrowserPointerEvent(type, new Map(), pointerEvent);
|
event = new MapBrowserPointerEvent(type, new Map(), pointerEvent);
|
||||||
defaultPrevented = false;
|
defaultPrevented = false;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import Polygon from '../../../../src/ol/geom/Polygon.js';
|
|||||||
import Interaction from '../../../../src/ol/interaction/Interaction.js';
|
import Interaction from '../../../../src/ol/interaction/Interaction.js';
|
||||||
import Select from '../../../../src/ol/interaction/Select.js';
|
import Select from '../../../../src/ol/interaction/Select.js';
|
||||||
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
||||||
import PointerEvent from '../../../../src/ol/pointer/PointerEvent.js';
|
|
||||||
import VectorSource from '../../../../src/ol/source/Vector.js';
|
import VectorSource from '../../../../src/ol/source/Vector.js';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import Point from '../../../../src/ol/geom/Point.js';
|
|||||||
import Translate, {TranslateEvent} from '../../../../src/ol/interaction/Translate.js';
|
import Translate, {TranslateEvent} from '../../../../src/ol/interaction/Translate.js';
|
||||||
import Interaction from '../../../../src/ol/interaction/Interaction.js';
|
import Interaction from '../../../../src/ol/interaction/Interaction.js';
|
||||||
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
import VectorLayer from '../../../../src/ol/layer/Vector.js';
|
||||||
import PointerEvent from '../../../../src/ol/pointer/PointerEvent.js';
|
|
||||||
import VectorSource from '../../../../src/ol/source/Vector.js';
|
import VectorSource from '../../../../src/ol/source/Vector.js';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import Map from '../../../src/ol/Map.js';
|
|||||||
import MapBrowserEventHandler from '../../../src/ol/MapBrowserEventHandler.js';
|
import MapBrowserEventHandler from '../../../src/ol/MapBrowserEventHandler.js';
|
||||||
import {listen} from '../../../src/ol/events.js';
|
import {listen} from '../../../src/ol/events.js';
|
||||||
import {DEVICE_PIXEL_RATIO} from '../../../src/ol/has.js';
|
import {DEVICE_PIXEL_RATIO} from '../../../src/ol/has.js';
|
||||||
import PointerEvent from '../../../src/ol/pointer/PointerEvent.js';
|
import Event from '../../../src/ol/events/Event.js';
|
||||||
|
|
||||||
describe('ol.MapBrowserEventHandler', function() {
|
describe('ol.MapBrowserEventHandler', function() {
|
||||||
describe('#emulateClick_', function() {
|
describe('#emulateClick_', function() {
|
||||||
@@ -36,22 +36,22 @@ describe('ol.MapBrowserEventHandler', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('emulates click', function() {
|
it('emulates click', function() {
|
||||||
handler.emulateClick_(new PointerEvent('pointerdown', {
|
const event = new Event();
|
||||||
type: 'mousedown',
|
event.type = 'pointerdown';
|
||||||
target: target,
|
event.target = target,
|
||||||
clientX: 0,
|
event.clientX = 0;
|
||||||
clientY: 0
|
event.clientY = 0;
|
||||||
}));
|
handler.emulateClick_(event);
|
||||||
expect(clickSpy.called).to.be.ok();
|
expect(clickSpy.called).to.be.ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('emulates singleclick', function() {
|
it('emulates singleclick', function() {
|
||||||
handler.emulateClick_(new PointerEvent('pointerdown', {
|
const event = new Event();
|
||||||
type: 'mousedown',
|
event.type = 'pointerdown';
|
||||||
target: target,
|
event.target = target;
|
||||||
clientX: 0,
|
event.clientX = 0;
|
||||||
clientY: 0
|
event.clientY = 0;
|
||||||
}));
|
handler.emulateClick_(event);
|
||||||
expect(singleclickSpy.called).to.not.be.ok();
|
expect(singleclickSpy.called).to.not.be.ok();
|
||||||
expect(dblclickSpy.called).to.not.be.ok();
|
expect(dblclickSpy.called).to.not.be.ok();
|
||||||
|
|
||||||
@@ -59,32 +59,22 @@ describe('ol.MapBrowserEventHandler', function() {
|
|||||||
expect(singleclickSpy.calledOnce).to.be.ok();
|
expect(singleclickSpy.calledOnce).to.be.ok();
|
||||||
expect(dblclickSpy.called).to.not.be.ok();
|
expect(dblclickSpy.called).to.not.be.ok();
|
||||||
|
|
||||||
handler.emulateClick_(new PointerEvent('pointerdown', {
|
handler.emulateClick_(event);
|
||||||
type: 'mousedown',
|
|
||||||
target: target,
|
|
||||||
clientX: 0,
|
|
||||||
clientY: 0
|
|
||||||
}));
|
|
||||||
expect(singleclickSpy.calledOnce).to.be.ok();
|
expect(singleclickSpy.calledOnce).to.be.ok();
|
||||||
expect(dblclickSpy.called).to.not.be.ok();
|
expect(dblclickSpy.called).to.not.be.ok();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('emulates dblclick', function() {
|
it('emulates dblclick', function() {
|
||||||
handler.emulateClick_(new PointerEvent('pointerdown', {
|
const event = new Event();
|
||||||
type: 'mousedown',
|
event.type = 'pointerdown';
|
||||||
target: target,
|
event.target = target;
|
||||||
clientX: 0,
|
event.clientX = 0;
|
||||||
clientY: 0
|
event.clientY = 0;
|
||||||
}));
|
handler.emulateClick_(event);
|
||||||
expect(singleclickSpy.called).to.not.be.ok();
|
expect(singleclickSpy.called).to.not.be.ok();
|
||||||
expect(dblclickSpy.called).to.not.be.ok();
|
expect(dblclickSpy.called).to.not.be.ok();
|
||||||
|
|
||||||
handler.emulateClick_(new PointerEvent('pointerdown', {
|
handler.emulateClick_(event);
|
||||||
type: 'mousedown',
|
|
||||||
target: target,
|
|
||||||
clientX: 0,
|
|
||||||
clientY: 0
|
|
||||||
}));
|
|
||||||
expect(singleclickSpy.called).to.not.be.ok();
|
expect(singleclickSpy.called).to.not.be.ok();
|
||||||
expect(dblclickSpy.calledOnce).to.be.ok();
|
expect(dblclickSpy.calledOnce).to.be.ok();
|
||||||
|
|
||||||
@@ -107,7 +97,7 @@ describe('ol.MapBrowserEventHandler', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('is an event after handlePointerDown_ has been called', function() {
|
it('is an event after handlePointerDown_ has been called', function() {
|
||||||
const event = new PointerEvent('pointerdown', {});
|
const event = new Event('pointerdown');
|
||||||
handler.handlePointerDown_(event);
|
handler.handlePointerDown_(event);
|
||||||
expect(handler.down_).to.be(event);
|
expect(handler.down_).to.be(event);
|
||||||
});
|
});
|
||||||
@@ -121,65 +111,65 @@ describe('ol.MapBrowserEventHandler', function() {
|
|||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
defaultHandler = new MapBrowserEventHandler(new Map({}));
|
defaultHandler = new MapBrowserEventHandler(new Map({}));
|
||||||
moveToleranceHandler = new MapBrowserEventHandler(new Map({}), 8);
|
moveToleranceHandler = new MapBrowserEventHandler(new Map({}), 8);
|
||||||
pointerdownAt0 = new PointerEvent('pointerdown', {}, {
|
pointerdownAt0 = new Event();
|
||||||
clientX: 0,
|
pointerdownAt0.type = 'pointerdown';
|
||||||
clientY: 0
|
pointerdownAt0.clientX = 0;
|
||||||
});
|
pointerdownAt0.clientY = 0;
|
||||||
defaultHandler.handlePointerDown_(pointerdownAt0);
|
defaultHandler.handlePointerDown_(pointerdownAt0);
|
||||||
moveToleranceHandler.handlePointerDown_(pointerdownAt0);
|
moveToleranceHandler.handlePointerDown_(pointerdownAt0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is not moving if distance is 0', function() {
|
it('is not moving if distance is 0', function() {
|
||||||
const pointerdownAt0 = new PointerEvent('pointerdown', {}, {
|
pointerdownAt0 = new Event();
|
||||||
clientX: 0,
|
pointerdownAt0.type = 'pointerdown';
|
||||||
clientY: 0
|
pointerdownAt0.clientX = 0;
|
||||||
});
|
pointerdownAt0.clientY = 0;
|
||||||
expect(defaultHandler.isMoving_(pointerdownAt0)).to.be(false);
|
expect(defaultHandler.isMoving_(pointerdownAt0)).to.be(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is moving if distance is 2', function() {
|
it('is moving if distance is 2', function() {
|
||||||
const pointerdownAt2 = new PointerEvent('pointerdown', {}, {
|
const pointerdownAt2 = new Event();
|
||||||
clientX: DEVICE_PIXEL_RATIO + 1,
|
pointerdownAt2.type = 'pointerdown';
|
||||||
clientY: DEVICE_PIXEL_RATIO + 1
|
pointerdownAt2.clientX = DEVICE_PIXEL_RATIO + 1;
|
||||||
});
|
pointerdownAt2.clientY = DEVICE_PIXEL_RATIO + 1;
|
||||||
expect(defaultHandler.isMoving_(pointerdownAt2)).to.be(true);
|
expect(defaultHandler.isMoving_(pointerdownAt2)).to.be(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is moving with negative distance', function() {
|
it('is moving with negative distance', function() {
|
||||||
const pointerdownAt2 = new PointerEvent('pointerdown', {}, {
|
const pointerdownAt2 = new Event();
|
||||||
clientX: -(DEVICE_PIXEL_RATIO + 1),
|
pointerdownAt2.type = 'pointerdown';
|
||||||
clientY: -(DEVICE_PIXEL_RATIO + 1)
|
pointerdownAt2.clientX = -(DEVICE_PIXEL_RATIO + 1);
|
||||||
});
|
pointerdownAt2.clientY = -(DEVICE_PIXEL_RATIO + 1);
|
||||||
expect(defaultHandler.isMoving_(pointerdownAt2)).to.be(true);
|
expect(defaultHandler.isMoving_(pointerdownAt2)).to.be(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is not moving if distance is less than move tolerance', function() {
|
it('is not moving if distance is less than move tolerance', function() {
|
||||||
const pointerdownAt2 = new PointerEvent('pointerdown', {}, {
|
const pointerdownAt2 = new Event();
|
||||||
clientX: DEVICE_PIXEL_RATIO + 1,
|
pointerdownAt2.type = 'pointerdown';
|
||||||
clientY: DEVICE_PIXEL_RATIO + 1
|
pointerdownAt2.clientX = DEVICE_PIXEL_RATIO + 1;
|
||||||
});
|
pointerdownAt2.clientY = DEVICE_PIXEL_RATIO + 1;
|
||||||
expect(moveToleranceHandler.isMoving_(pointerdownAt2)).to.be(false);
|
expect(moveToleranceHandler.isMoving_(pointerdownAt2)).to.be(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is moving if distance is greater than move tolerance', function() {
|
it('is moving if distance is greater than move tolerance', function() {
|
||||||
const pointerdownAt9 = new PointerEvent('pointerdown', {}, {
|
const pointerdownAt9 = new Event();
|
||||||
clientX: (DEVICE_PIXEL_RATIO * 8) + 1,
|
pointerdownAt9.type = 'pointerdown';
|
||||||
clientY: (DEVICE_PIXEL_RATIO * 8) + 1
|
pointerdownAt9.clientX = (DEVICE_PIXEL_RATIO * 8) + 1;
|
||||||
});
|
pointerdownAt9.clientY = (DEVICE_PIXEL_RATIO * 8) + 1;
|
||||||
expect(moveToleranceHandler.isMoving_(pointerdownAt9)).to.be(true);
|
expect(moveToleranceHandler.isMoving_(pointerdownAt9)).to.be(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is moving when moving back close to the down pixel', function() {
|
it('is moving when moving back close to the down pixel', function() {
|
||||||
const pointermoveAt9 = new PointerEvent('pointermove', {}, {
|
const pointermoveAt9 = new Event();
|
||||||
clientX: (DEVICE_PIXEL_RATIO * 8) + 1,
|
pointermoveAt9.type = 'pointermove';
|
||||||
clientY: (DEVICE_PIXEL_RATIO * 8) + 1
|
pointermoveAt9.clientX = (DEVICE_PIXEL_RATIO * 8) + 1;
|
||||||
});
|
pointermoveAt9.clientY = (DEVICE_PIXEL_RATIO * 8) + 1;
|
||||||
moveToleranceHandler.handlePointerMove_(pointermoveAt9);
|
moveToleranceHandler.handlePointerMove_(pointermoveAt9);
|
||||||
expect(moveToleranceHandler.isMoving_(pointermoveAt9)).to.be(true);
|
expect(moveToleranceHandler.isMoving_(pointermoveAt9)).to.be(true);
|
||||||
const pointermoveAt2 = new PointerEvent('pointermove', {}, {
|
const pointermoveAt2 = new Event();
|
||||||
clientX: DEVICE_PIXEL_RATIO + 1,
|
pointermoveAt2.type = 'pointermove';
|
||||||
clientY: DEVICE_PIXEL_RATIO + 1
|
pointermoveAt2.clientX = DEVICE_PIXEL_RATIO + 1;
|
||||||
});
|
pointermoveAt2.clientY = DEVICE_PIXEL_RATIO + 1;
|
||||||
moveToleranceHandler.handlePointerMove_(pointermoveAt2);
|
moveToleranceHandler.handlePointerMove_(pointermoveAt2);
|
||||||
expect(moveToleranceHandler.isMoving_(pointermoveAt2)).to.be(true);
|
expect(moveToleranceHandler.isMoving_(pointermoveAt2)).to.be(true);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
import {listen} from '../../../../src/ol/events.js';
|
|
||||||
import EventTarget from '../../../../src/ol/events/Target.js';
|
|
||||||
import PointerEventHandler from '../../../../src/ol/pointer/PointerEventHandler.js';
|
|
||||||
import TouchSource from '../../../../src/ol/pointer/TouchSource.js';
|
|
||||||
import MouseSource from '../../../../src/ol/pointer/MouseSource.js';
|
|
||||||
import MsSource from '../../../../src/ol/pointer/MsSource.js';
|
|
||||||
import NativeSource from '../../../../src/ol/pointer/NativeSource.js';
|
|
||||||
|
|
||||||
|
|
||||||
describe('ol.pointer.MouseSource', function() {
|
|
||||||
let handler;
|
|
||||||
let target;
|
|
||||||
let eventSpy;
|
|
||||||
let clock;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
clock = sinon.useFakeTimers();
|
|
||||||
target = new EventTarget();
|
|
||||||
|
|
||||||
// make sure that a mouse and touch event source is used
|
|
||||||
const POINTER = false;
|
|
||||||
const MSPOINTER = false;
|
|
||||||
const TOUCH = true;
|
|
||||||
const originalRegisterSources = PointerEventHandler.prototype.registerSources;
|
|
||||||
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) {
|
|
||||||
const touchSource = new TouchSource(this, mouseSource);
|
|
||||||
// set the timeout to a lower value, to speed up the tests
|
|
||||||
touchSource.dedupTimeout_ = 100;
|
|
||||||
|
|
||||||
this.registerSource('touch', touchSource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// register events on the viewport element
|
|
||||||
this.register_();
|
|
||||||
};
|
|
||||||
|
|
||||||
handler = new PointerEventHandler(target);
|
|
||||||
PointerEventHandler.prototype.registerSources = originalRegisterSources;
|
|
||||||
|
|
||||||
eventSpy = sinon.spy();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
clock.restore();
|
|
||||||
handler.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('simulated mouse events', function() {
|
|
||||||
it('prevents simulated mouse events', function() {
|
|
||||||
listen(handler, 'pointerdown', eventSpy);
|
|
||||||
|
|
||||||
// simulates that a mouse event is triggered from a touch
|
|
||||||
simulateTouchEvent('touchstart', 10, 20);
|
|
||||||
simulateEvent('mousedown', 10, 20);
|
|
||||||
|
|
||||||
expect(eventSpy.calledOnce).to.be.ok();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it('dispatches real mouse events', function() {
|
|
||||||
listen(handler, 'pointerdown', eventSpy);
|
|
||||||
|
|
||||||
// the two events are at different positions
|
|
||||||
simulateTouchEvent('touchstart', 10, 20);
|
|
||||||
simulateEvent('mousedown', 10, 50);
|
|
||||||
|
|
||||||
expect(eventSpy.calledTwice).to.be.ok();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('dispatches real mouse events after timeout', function() {
|
|
||||||
listen(handler, 'pointerdown', eventSpy);
|
|
||||||
|
|
||||||
// first simulate a touch event, then a mouse event
|
|
||||||
// at the same position after a timeout
|
|
||||||
simulateTouchEvent('touchstart', 10, 20);
|
|
||||||
clock.tick(150);
|
|
||||||
simulateEvent('mousedown', 10, 20);
|
|
||||||
|
|
||||||
expect(eventSpy.calledTwice).to.be.ok();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function simulateTouchEvent(type, x, y) {
|
|
||||||
const touches = [{
|
|
||||||
identifier: 4,
|
|
||||||
clientX: x,
|
|
||||||
clientY: y,
|
|
||||||
target: target
|
|
||||||
}];
|
|
||||||
|
|
||||||
const event = {
|
|
||||||
type: type,
|
|
||||||
touches: touches,
|
|
||||||
changedTouches: touches
|
|
||||||
};
|
|
||||||
target.dispatchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
function simulateEvent(type, x, y) {
|
|
||||||
const event = {
|
|
||||||
type: type,
|
|
||||||
clientX: x,
|
|
||||||
clientY: y,
|
|
||||||
target: target
|
|
||||||
};
|
|
||||||
target.dispatchEvent(event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
import {listen} from '../../../../src/ol/events.js';
|
|
||||||
import EventTarget from '../../../../src/ol/events/Target.js';
|
|
||||||
import MouseSource from '../../../../src/ol/pointer/MouseSource.js';
|
|
||||||
import PointerEvent from '../../../../src/ol/pointer/PointerEvent.js';
|
|
||||||
import PointerEventHandler from '../../../../src/ol/pointer/PointerEventHandler.js';
|
|
||||||
import TouchSource from '../../../../src/ol/pointer/TouchSource.js';
|
|
||||||
import MsSource from '../../../../src/ol/pointer/MsSource.js';
|
|
||||||
import NativeSource from '../../../../src/ol/pointer/NativeSource.js';
|
|
||||||
|
|
||||||
|
|
||||||
describe('ol.pointer.PointerEventHandler', function() {
|
|
||||||
let handler;
|
|
||||||
let target;
|
|
||||||
let eventSpy;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
target = new EventTarget();
|
|
||||||
|
|
||||||
// make sure that a mouse event source is used
|
|
||||||
const POINTER = false;
|
|
||||||
const MSPOINTER = false;
|
|
||||||
const TOUCH = false;
|
|
||||||
const originalRegisterSources = PointerEventHandler.prototype.registerSources;
|
|
||||||
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_();
|
|
||||||
};
|
|
||||||
|
|
||||||
handler = new PointerEventHandler(target);
|
|
||||||
PointerEventHandler.prototype.registerSources = originalRegisterSources;
|
|
||||||
|
|
||||||
eventSpy = sinon.spy();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
handler.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('constructor', function() {
|
|
||||||
it('registers a least one event source', function() {
|
|
||||||
expect(handler.eventSourceList_.length).to.be.greaterThan(0);
|
|
||||||
expect(handler.eventSourceList_[0]).to.be.a(MouseSource);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function simulateEvent(type, x, y) {
|
|
||||||
const event = {
|
|
||||||
type: type,
|
|
||||||
clientX: x,
|
|
||||||
clientY: y,
|
|
||||||
target: target
|
|
||||||
};
|
|
||||||
target.dispatchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('pointer down', function() {
|
|
||||||
it('fires pointerdown events', function() {
|
|
||||||
listen(handler, 'pointerdown', eventSpy);
|
|
||||||
simulateEvent('mousedown', 0, 0);
|
|
||||||
expect(eventSpy.calledOnce).to.be.ok();
|
|
||||||
|
|
||||||
const pointerEvent = eventSpy.firstCall.args[0];
|
|
||||||
expect(pointerEvent).to.be.a(PointerEvent);
|
|
||||||
expect(pointerEvent.type).to.be('pointerdown');
|
|
||||||
expect(pointerEvent.pointerId).to.be(1);
|
|
||||||
expect(pointerEvent.pointerType).to.be('mouse');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pointer up', function() {
|
|
||||||
it('fires pointerup events', function() {
|
|
||||||
listen(handler, 'pointerup', eventSpy);
|
|
||||||
simulateEvent('mousedown', 0, 0);
|
|
||||||
simulateEvent('mouseup', 0, 0);
|
|
||||||
expect(eventSpy.calledOnce).to.be.ok();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pointer move', function() {
|
|
||||||
it('fires pointermove events', function() {
|
|
||||||
listen(handler, 'pointermove', eventSpy);
|
|
||||||
simulateEvent('mousemove', 0, 0);
|
|
||||||
expect(eventSpy.calledOnce).to.be.ok();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pointer enter and over', function() {
|
|
||||||
it('fires pointerenter and pointerover events', function() {
|
|
||||||
const enterEventSpy = sinon.spy();
|
|
||||||
const overEventSpy = sinon.spy();
|
|
||||||
|
|
||||||
listen(handler, 'pointerenter', enterEventSpy);
|
|
||||||
listen(handler, 'pointerover', overEventSpy);
|
|
||||||
|
|
||||||
simulateEvent('mouseover', 0, 0);
|
|
||||||
|
|
||||||
expect(enterEventSpy.calledOnce).to.be.ok();
|
|
||||||
expect(overEventSpy.calledOnce).to.be.ok();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pointer leave and out', function() {
|
|
||||||
it('fires pointerleave and pointerout events', function() {
|
|
||||||
const leaveEventSpy = sinon.spy();
|
|
||||||
const outEventSpy = sinon.spy();
|
|
||||||
|
|
||||||
listen(handler, 'pointerleave', leaveEventSpy);
|
|
||||||
listen(handler, 'pointerout', outEventSpy);
|
|
||||||
|
|
||||||
simulateEvent('mouseout', 0, 0);
|
|
||||||
|
|
||||||
expect(leaveEventSpy.calledOnce).to.be.ok();
|
|
||||||
expect(outEventSpy.calledOnce).to.be.ok();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#cloneEvent', function() {
|
|
||||||
it('copies the properties of an event', function() {
|
|
||||||
const event = {
|
|
||||||
type: 'mousedown',
|
|
||||||
target: target,
|
|
||||||
clientX: 1,
|
|
||||||
clientY: 2
|
|
||||||
};
|
|
||||||
const browserEvent = event;
|
|
||||||
|
|
||||||
const eventClone = handler.cloneEvent(browserEvent, event);
|
|
||||||
|
|
||||||
// properties are copied from `event`
|
|
||||||
expect(eventClone.type).to.be('mousedown');
|
|
||||||
expect(eventClone.target).to.be(target);
|
|
||||||
expect(eventClone.clientX).to.be(1);
|
|
||||||
expect(eventClone.clientY).to.be(2);
|
|
||||||
|
|
||||||
// properties are copied from `browserEvent`
|
|
||||||
expect(eventClone.screenX).to.be(0);
|
|
||||||
expect(eventClone.screenY).to.be(0);
|
|
||||||
|
|
||||||
// properties are copied from the defaults
|
|
||||||
expect(eventClone.pointerId).to.be(0);
|
|
||||||
expect(eventClone.pressure).to.be(0);
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#makeEvent', function() {
|
|
||||||
it('makes a new pointer event', function() {
|
|
||||||
const event = {
|
|
||||||
type: 'mousedown',
|
|
||||||
target: target,
|
|
||||||
clientX: 1,
|
|
||||||
clientY: 2
|
|
||||||
};
|
|
||||||
const browserEvent = event;
|
|
||||||
|
|
||||||
const eventClone = handler.cloneEvent(browserEvent, event);
|
|
||||||
const pointerEvent = handler.makeEvent('pointerdown',
|
|
||||||
eventClone, browserEvent);
|
|
||||||
|
|
||||||
expect(pointerEvent.type).to.be('pointerdown');
|
|
||||||
expect(pointerEvent.clientX).to.be(1);
|
|
||||||
expect(pointerEvent.clientY).to.be(2);
|
|
||||||
|
|
||||||
expect(pointerEvent.screenX).to.be(0);
|
|
||||||
expect(pointerEvent.screenY).to.be(0);
|
|
||||||
|
|
||||||
expect(pointerEvent.pointerId).to.be(0);
|
|
||||||
expect(pointerEvent.pressure).to.be(0);
|
|
||||||
|
|
||||||
expect(pointerEvent.preventDefault).to.be.ok();
|
|
||||||
|
|
||||||
expect(pointerEvent).to.be.a(PointerEvent);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
import {listen} from '../../../../src/ol/events.js';
|
|
||||||
import Event from '../../../../src/ol/events/Event.js';
|
|
||||||
import EventTarget from '../../../../src/ol/events/Target.js';
|
|
||||||
import {assign} from '../../../../src/ol/obj.js';
|
|
||||||
import PointerEventHandler from '../../../../src/ol/pointer/PointerEventHandler.js';
|
|
||||||
import TouchSource from '../../../../src/ol/pointer/TouchSource.js';
|
|
||||||
import MouseSource from '../../../../src/ol/pointer/MouseSource.js';
|
|
||||||
import MsSource from '../../../../src/ol/pointer/MsSource.js';
|
|
||||||
import NativeSource from '../../../../src/ol/pointer/NativeSource.js';
|
|
||||||
|
|
||||||
describe('ol.pointer.TouchSource', function() {
|
|
||||||
let handler;
|
|
||||||
let target;
|
|
||||||
let eventSpy;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
target = new EventTarget();
|
|
||||||
|
|
||||||
// make sure that a mouse and touch event source is used
|
|
||||||
const POINTER = false;
|
|
||||||
const MSPOINTER = false;
|
|
||||||
const TOUCH = true;
|
|
||||||
const originalRegisterSources = PointerEventHandler.prototype.registerSources;
|
|
||||||
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_();
|
|
||||||
};
|
|
||||||
|
|
||||||
handler = new PointerEventHandler(target);
|
|
||||||
PointerEventHandler.prototype.registerSources = originalRegisterSources;
|
|
||||||
|
|
||||||
eventSpy = sinon.spy();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
handler.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pointer event creation', function() {
|
|
||||||
it('generates pointer events for each touch contact', function() {
|
|
||||||
listen(handler, 'pointerdown', eventSpy);
|
|
||||||
|
|
||||||
simulateTouchEvent('touchstart', [
|
|
||||||
{identifier: 3, clientX: 10, clientY: 11},
|
|
||||||
{identifier: 4, clientX: 30, clientY: 45}
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(eventSpy.calledTwice).to.be.ok();
|
|
||||||
|
|
||||||
// pointer event for the first touch contact
|
|
||||||
const pointerEvent1 = eventSpy.firstCall.args[0];
|
|
||||||
expect(pointerEvent1.pointerId).to.be(5);
|
|
||||||
expect(pointerEvent1.pointerType).to.be('touch');
|
|
||||||
expect(pointerEvent1.clientX).to.be(10);
|
|
||||||
expect(pointerEvent1.clientY).to.be(11);
|
|
||||||
|
|
||||||
// pointer event for the second touch contact
|
|
||||||
const pointerEvent2 = eventSpy.secondCall.args[0];
|
|
||||||
expect(pointerEvent2.pointerId).to.be(6);
|
|
||||||
expect(pointerEvent2.pointerType).to.be('touch');
|
|
||||||
expect(pointerEvent2.clientX).to.be(30);
|
|
||||||
expect(pointerEvent2.clientY).to.be(45);
|
|
||||||
|
|
||||||
expect(Object.keys(handler.pointerMap).length).to.be(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates the right pointer events', function() {
|
|
||||||
listen(handler, 'pointerdown', eventSpy);
|
|
||||||
|
|
||||||
// first touch
|
|
||||||
simulateTouchEvent('touchstart', [
|
|
||||||
{identifier: 3, clientX: 10, clientY: 11}
|
|
||||||
]);
|
|
||||||
expect(eventSpy.calledOnce).to.be.ok();
|
|
||||||
expect(Object.keys(handler.pointerMap).length).to.be(1);
|
|
||||||
|
|
||||||
// second touch (first touch still down)
|
|
||||||
simulateTouchEvent('touchstart', [
|
|
||||||
{identifier: 4, clientX: 30, clientY: 45}
|
|
||||||
], [{identifier: 3}, {identifier: 4}]
|
|
||||||
);
|
|
||||||
expect(eventSpy.calledTwice).to.be.ok();
|
|
||||||
expect(Object.keys(handler.pointerMap).length).to.be(2);
|
|
||||||
|
|
||||||
// first touch moves
|
|
||||||
const moveEventSpy = sinon.spy();
|
|
||||||
listen(handler, 'pointermove', moveEventSpy);
|
|
||||||
|
|
||||||
simulateTouchEvent('touchmove', [
|
|
||||||
{identifier: 3, clientX: 15, clientY: 16}
|
|
||||||
], [{identifier: 3}, {identifier: 4}]
|
|
||||||
);
|
|
||||||
expect(moveEventSpy.calledOnce).to.be.ok();
|
|
||||||
|
|
||||||
// and then both touches go up
|
|
||||||
const upEventSpy = sinon.spy();
|
|
||||||
listen(handler, 'pointerup', upEventSpy);
|
|
||||||
|
|
||||||
simulateTouchEvent('touchend', [
|
|
||||||
{identifier: 3, clientX: 15, clientY: 16},
|
|
||||||
{identifier: 4, clientX: 30, clientY: 45}
|
|
||||||
], [{identifier: 3}, {identifier: 4}]
|
|
||||||
);
|
|
||||||
expect(upEventSpy.calledTwice).to.be.ok();
|
|
||||||
expect(Object.keys(handler.pointerMap).length).to.be(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles flawed touches', function() {
|
|
||||||
listen(handler, 'pointerdown', eventSpy);
|
|
||||||
|
|
||||||
// first touch
|
|
||||||
simulateTouchEvent('touchstart', [
|
|
||||||
{identifier: 3, clientX: 10, clientY: 11}
|
|
||||||
]);
|
|
||||||
expect(eventSpy.calledOnce).to.be.ok();
|
|
||||||
expect(Object.keys(handler.pointerMap).length).to.be(1);
|
|
||||||
|
|
||||||
// second touch, but the first touch has disappeared
|
|
||||||
const cancelEventSpy = sinon.spy();
|
|
||||||
listen(handler, 'pointercancel', cancelEventSpy);
|
|
||||||
simulateTouchEvent('touchstart', [
|
|
||||||
{identifier: 4, clientX: 30, clientY: 45}
|
|
||||||
], [{identifier: 4}]
|
|
||||||
);
|
|
||||||
expect(eventSpy.calledTwice).to.be.ok();
|
|
||||||
|
|
||||||
// the first (broken) touch is canceled
|
|
||||||
expect(cancelEventSpy.calledOnce).to.be.ok();
|
|
||||||
expect(Object.keys(handler.pointerMap).length).to.be(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function simulateTouchEvent(type, changedTouches, touches) {
|
|
||||||
touches = touches !== undefined ? touches : changedTouches;
|
|
||||||
|
|
||||||
const event = new Event(type);
|
|
||||||
assign(event, {
|
|
||||||
touches: touches,
|
|
||||||
changedTouches: changedTouches
|
|
||||||
});
|
|
||||||
target.dispatchEvent(event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user