123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- import Cartesian2 from '../Core/Cartesian2.js';
- import defined from '../Core/defined.js';
- import defineProperties from '../Core/defineProperties.js';
- import destroyObject from '../Core/destroyObject.js';
- import DeveloperError from '../Core/DeveloperError.js';
- import KeyboardEventModifier from '../Core/KeyboardEventModifier.js';
- import CesiumMath from '../Core/Math.js';
- import ScreenSpaceEventHandler from '../Core/ScreenSpaceEventHandler.js';
- import ScreenSpaceEventType from '../Core/ScreenSpaceEventType.js';
- import CameraEventType from './CameraEventType.js';
- function getKey(type, modifier) {
- var key = type;
- if (defined(modifier)) {
- key += '+' + modifier;
- }
- return key;
- }
- function clonePinchMovement(pinchMovement, result) {
- Cartesian2.clone(pinchMovement.distance.startPosition, result.distance.startPosition);
- Cartesian2.clone(pinchMovement.distance.endPosition, result.distance.endPosition);
- Cartesian2.clone(pinchMovement.angleAndHeight.startPosition, result.angleAndHeight.startPosition);
- Cartesian2.clone(pinchMovement.angleAndHeight.endPosition, result.angleAndHeight.endPosition);
- }
- function listenToPinch(aggregator, modifier, canvas) {
- var key = getKey(CameraEventType.PINCH, modifier);
- var update = aggregator._update;
- var isDown = aggregator._isDown;
- var eventStartPosition = aggregator._eventStartPosition;
- var pressTime = aggregator._pressTime;
- var releaseTime = aggregator._releaseTime;
- update[key] = true;
- isDown[key] = false;
- eventStartPosition[key] = new Cartesian2();
- var movement = aggregator._movement[key];
- if (!defined(movement)) {
- movement = aggregator._movement[key] = {};
- }
- movement.distance = {
- startPosition : new Cartesian2(),
- endPosition : new Cartesian2()
- };
- movement.angleAndHeight = {
- startPosition : new Cartesian2(),
- endPosition : new Cartesian2()
- };
- movement.prevAngle = 0.0;
- aggregator._eventHandler.setInputAction(function(event) {
- aggregator._buttonsDown++;
- isDown[key] = true;
- pressTime[key] = new Date();
- // Compute center position and store as start point.
- Cartesian2.lerp(event.position1, event.position2, 0.5, eventStartPosition[key]);
- }, ScreenSpaceEventType.PINCH_START, modifier);
- aggregator._eventHandler.setInputAction(function() {
- aggregator._buttonsDown = Math.max(aggregator._buttonsDown - 1, 0);
- isDown[key] = false;
- releaseTime[key] = new Date();
- }, ScreenSpaceEventType.PINCH_END, modifier);
- aggregator._eventHandler.setInputAction(function(mouseMovement) {
- if (isDown[key]) {
- // Aggregate several input events into a single animation frame.
- if (!update[key]) {
- Cartesian2.clone(mouseMovement.distance.endPosition, movement.distance.endPosition);
- Cartesian2.clone(mouseMovement.angleAndHeight.endPosition, movement.angleAndHeight.endPosition);
- } else {
- clonePinchMovement(mouseMovement, movement);
- update[key] = false;
- movement.prevAngle = movement.angleAndHeight.startPosition.x;
- }
- // Make sure our aggregation of angles does not "flip" over 360 degrees.
- var angle = movement.angleAndHeight.endPosition.x;
- var prevAngle = movement.prevAngle;
- var TwoPI = Math.PI * 2;
- while (angle >= (prevAngle + Math.PI)) {
- angle -= TwoPI;
- }
- while (angle < (prevAngle - Math.PI)) {
- angle += TwoPI;
- }
- movement.angleAndHeight.endPosition.x = -angle * canvas.clientWidth / 12;
- movement.angleAndHeight.startPosition.x = -prevAngle * canvas.clientWidth / 12;
- }
- }, ScreenSpaceEventType.PINCH_MOVE, modifier);
- }
- function listenToWheel(aggregator, modifier) {
- var key = getKey(CameraEventType.WHEEL, modifier);
- var update = aggregator._update;
- update[key] = true;
- var movement = aggregator._movement[key];
- if (!defined(movement)) {
- movement = aggregator._movement[key] = {};
- }
- movement.startPosition = new Cartesian2();
- movement.endPosition = new Cartesian2();
- aggregator._eventHandler.setInputAction(function(delta) {
- // TODO: magic numbers
- var arcLength = 15.0 * CesiumMath.toRadians(delta);
- if (!update[key]) {
- movement.endPosition.y = movement.endPosition.y + arcLength;
- } else {
- Cartesian2.clone(Cartesian2.ZERO, movement.startPosition);
- movement.endPosition.x = 0.0;
- movement.endPosition.y = arcLength;
- update[key] = false;
- }
- }, ScreenSpaceEventType.WHEEL, modifier);
- }
- function listenMouseButtonDownUp(aggregator, modifier, type) {
- var key = getKey(type, modifier);
- var isDown = aggregator._isDown;
- var eventStartPosition = aggregator._eventStartPosition;
- var pressTime = aggregator._pressTime;
- var releaseTime = aggregator._releaseTime;
- isDown[key] = false;
- eventStartPosition[key] = new Cartesian2();
- var lastMovement = aggregator._lastMovement[key];
- if (!defined(lastMovement)) {
- lastMovement = aggregator._lastMovement[key] = {
- startPosition : new Cartesian2(),
- endPosition : new Cartesian2(),
- valid : false
- };
- }
- var down;
- var up;
- if (type === CameraEventType.LEFT_DRAG) {
- down = ScreenSpaceEventType.LEFT_DOWN;
- up = ScreenSpaceEventType.LEFT_UP;
- } else if (type === CameraEventType.RIGHT_DRAG) {
- down = ScreenSpaceEventType.RIGHT_DOWN;
- up = ScreenSpaceEventType.RIGHT_UP;
- } else if (type === CameraEventType.MIDDLE_DRAG) {
- down = ScreenSpaceEventType.MIDDLE_DOWN;
- up = ScreenSpaceEventType.MIDDLE_UP;
- }
- aggregator._eventHandler.setInputAction(function(event) {
- aggregator._buttonsDown++;
- lastMovement.valid = false;
- isDown[key] = true;
- pressTime[key] = new Date();
- Cartesian2.clone(event.position, eventStartPosition[key]);
- }, down, modifier);
- aggregator._eventHandler.setInputAction(function() {
- aggregator._buttonsDown = Math.max(aggregator._buttonsDown - 1, 0);
- isDown[key] = false;
- releaseTime[key] = new Date();
- }, up, modifier);
- }
- function cloneMouseMovement(mouseMovement, result) {
- Cartesian2.clone(mouseMovement.startPosition, result.startPosition);
- Cartesian2.clone(mouseMovement.endPosition, result.endPosition);
- }
- function listenMouseMove(aggregator, modifier) {
- var update = aggregator._update;
- var movement = aggregator._movement;
- var lastMovement = aggregator._lastMovement;
- var isDown = aggregator._isDown;
- for ( var typeName in CameraEventType) {
- if (CameraEventType.hasOwnProperty(typeName)) {
- var type = CameraEventType[typeName];
- if (defined(type)) {
- var key = getKey(type, modifier);
- update[key] = true;
- if (!defined(aggregator._lastMovement[key])) {
- aggregator._lastMovement[key] = {
- startPosition : new Cartesian2(),
- endPosition : new Cartesian2(),
- valid : false
- };
- }
- if (!defined(aggregator._movement[key])) {
- aggregator._movement[key] = {
- startPosition : new Cartesian2(),
- endPosition : new Cartesian2()
- };
- }
- }
- }
- }
- aggregator._eventHandler.setInputAction(function(mouseMovement) {
- for ( var typeName in CameraEventType) {
- if (CameraEventType.hasOwnProperty(typeName)) {
- var type = CameraEventType[typeName];
- if (defined(type)) {
- var key = getKey(type, modifier);
- if (isDown[key]) {
- if (!update[key]) {
- Cartesian2.clone(mouseMovement.endPosition, movement[key].endPosition);
- } else {
- cloneMouseMovement(movement[key], lastMovement[key]);
- lastMovement[key].valid = true;
- cloneMouseMovement(mouseMovement, movement[key]);
- update[key] = false;
- }
- }
- }
- }
- }
- Cartesian2.clone(mouseMovement.endPosition, aggregator._currentMousePosition);
- }, ScreenSpaceEventType.MOUSE_MOVE, modifier);
- }
- /**
- * Aggregates input events. For example, suppose the following inputs are received between frames:
- * left mouse button down, mouse move, mouse move, left mouse button up. These events will be aggregated into
- * one event with a start and end position of the mouse.
- *
- * @alias CameraEventAggregator
- * @constructor
- *
- * @param {Canvas} [canvas=document] The element to handle events for.
- *
- * @see ScreenSpaceEventHandler
- */
- function CameraEventAggregator(canvas) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(canvas)) {
- throw new DeveloperError('canvas is required.');
- }
- //>>includeEnd('debug');
- this._eventHandler = new ScreenSpaceEventHandler(canvas);
- this._update = {};
- this._movement = {};
- this._lastMovement = {};
- this._isDown = {};
- this._eventStartPosition = {};
- this._pressTime = {};
- this._releaseTime = {};
- this._buttonsDown = 0;
- this._currentMousePosition = new Cartesian2();
- listenToWheel(this, undefined);
- listenToPinch(this, undefined, canvas);
- listenMouseButtonDownUp(this, undefined, CameraEventType.LEFT_DRAG);
- listenMouseButtonDownUp(this, undefined, CameraEventType.RIGHT_DRAG);
- listenMouseButtonDownUp(this, undefined, CameraEventType.MIDDLE_DRAG);
- listenMouseMove(this, undefined);
- for ( var modifierName in KeyboardEventModifier) {
- if (KeyboardEventModifier.hasOwnProperty(modifierName)) {
- var modifier = KeyboardEventModifier[modifierName];
- if (defined(modifier)) {
- listenToWheel(this, modifier);
- listenToPinch(this, modifier, canvas);
- listenMouseButtonDownUp(this, modifier, CameraEventType.LEFT_DRAG);
- listenMouseButtonDownUp(this, modifier, CameraEventType.RIGHT_DRAG);
- listenMouseButtonDownUp(this, modifier, CameraEventType.MIDDLE_DRAG);
- listenMouseMove(this, modifier);
- }
- }
- }
- }
- defineProperties(CameraEventAggregator.prototype, {
- /**
- * Gets the current mouse position.
- * @memberof CameraEventAggregator.prototype
- * @type {Cartesian2}
- */
- currentMousePosition : {
- get : function() {
- return this._currentMousePosition;
- }
- },
- /**
- * Gets whether any mouse button is down, a touch has started, or the wheel has been moved.
- * @memberof CameraEventAggregator.prototype
- * @type {Boolean}
- */
- anyButtonDown : {
- get : function() {
- var wheelMoved = !this._update[getKey(CameraEventType.WHEEL)] ||
- !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.SHIFT)] ||
- !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.CTRL)] ||
- !this._update[getKey(CameraEventType.WHEEL, KeyboardEventModifier.ALT)];
- return this._buttonsDown > 0 || wheelMoved;
- }
- }
- });
- /**
- * Gets if a mouse button down or touch has started and has been moved.
- *
- * @param {CameraEventType} type The camera event type.
- * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
- * @returns {Boolean} Returns <code>true</code> if a mouse button down or touch has started and has been moved; otherwise, <code>false</code>
- */
- CameraEventAggregator.prototype.isMoving = function(type, modifier) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(type)) {
- throw new DeveloperError('type is required.');
- }
- //>>includeEnd('debug');
- var key = getKey(type, modifier);
- return !this._update[key];
- };
- /**
- * Gets the aggregated start and end position of the current event.
- *
- * @param {CameraEventType} type The camera event type.
- * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
- * @returns {Object} An object with two {@link Cartesian2} properties: <code>startPosition</code> and <code>endPosition</code>.
- */
- CameraEventAggregator.prototype.getMovement = function(type, modifier) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(type)) {
- throw new DeveloperError('type is required.');
- }
- //>>includeEnd('debug');
- var key = getKey(type, modifier);
- var movement = this._movement[key];
- return movement;
- };
- /**
- * Gets the start and end position of the last move event (not the aggregated event).
- *
- * @param {CameraEventType} type The camera event type.
- * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
- * @returns {Object|undefined} An object with two {@link Cartesian2} properties: <code>startPosition</code> and <code>endPosition</code> or <code>undefined</code>.
- */
- CameraEventAggregator.prototype.getLastMovement = function(type, modifier) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(type)) {
- throw new DeveloperError('type is required.');
- }
- //>>includeEnd('debug');
- var key = getKey(type, modifier);
- var lastMovement = this._lastMovement[key];
- if (lastMovement.valid) {
- return lastMovement;
- }
- return undefined;
- };
- /**
- * Gets whether the mouse button is down or a touch has started.
- *
- * @param {CameraEventType} type The camera event type.
- * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
- * @returns {Boolean} Whether the mouse button is down or a touch has started.
- */
- CameraEventAggregator.prototype.isButtonDown = function(type, modifier) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(type)) {
- throw new DeveloperError('type is required.');
- }
- //>>includeEnd('debug');
- var key = getKey(type, modifier);
- return this._isDown[key];
- };
- /**
- * Gets the mouse position that started the aggregation.
- *
- * @param {CameraEventType} type The camera event type.
- * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
- * @returns {Cartesian2} The mouse position.
- */
- CameraEventAggregator.prototype.getStartMousePosition = function(type, modifier) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(type)) {
- throw new DeveloperError('type is required.');
- }
- //>>includeEnd('debug');
- if (type === CameraEventType.WHEEL) {
- return this._currentMousePosition;
- }
- var key = getKey(type, modifier);
- return this._eventStartPosition[key];
- };
- /**
- * Gets the time the button was pressed or the touch was started.
- *
- * @param {CameraEventType} type The camera event type.
- * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
- * @returns {Date} The time the button was pressed or the touch was started.
- */
- CameraEventAggregator.prototype.getButtonPressTime = function(type, modifier) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(type)) {
- throw new DeveloperError('type is required.');
- }
- //>>includeEnd('debug');
- var key = getKey(type, modifier);
- return this._pressTime[key];
- };
- /**
- * Gets the time the button was released or the touch was ended.
- *
- * @param {CameraEventType} type The camera event type.
- * @param {KeyboardEventModifier} [modifier] The keyboard modifier.
- * @returns {Date} The time the button was released or the touch was ended.
- */
- CameraEventAggregator.prototype.getButtonReleaseTime = function(type, modifier) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(type)) {
- throw new DeveloperError('type is required.');
- }
- //>>includeEnd('debug');
- var key = getKey(type, modifier);
- return this._releaseTime[key];
- };
- /**
- * Signals that all of the events have been handled and the aggregator should be reset to handle new events.
- */
- CameraEventAggregator.prototype.reset = function() {
- for ( var name in this._update) {
- if (this._update.hasOwnProperty(name)) {
- this._update[name] = true;
- }
- }
- };
- /**
- * Returns true if this object was destroyed; otherwise, false.
- * <br /><br />
- * If this object was destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
- *
- * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
- *
- * @see CameraEventAggregator#destroy
- */
- CameraEventAggregator.prototype.isDestroyed = function() {
- return false;
- };
- /**
- * Removes mouse listeners held by this object.
- * <br /><br />
- * Once an object is destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
- * assign the return value (<code>undefined</code>) to the object as done in the example.
- *
- * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
- *
- *
- * @example
- * handler = handler && handler.destroy();
- *
- * @see CameraEventAggregator#isDestroyed
- */
- CameraEventAggregator.prototype.destroy = function() {
- this._eventHandler = this._eventHandler && this._eventHandler.destroy();
- return destroyObject(this);
- };
- export default CameraEventAggregator;
|