diff --git a/src/Controls/GlobeControls.js b/src/Controls/GlobeControls.js index 2452fb652d..529a4da5d0 100644 --- a/src/Controls/GlobeControls.js +++ b/src/Controls/GlobeControls.js @@ -257,7 +257,6 @@ class GlobeControls extends THREE.EventDispatcher { } : function empty() {}; this._onEndingMove = null; - this._onMouseWheel = this.onMouseWheel.bind(this); this._onTravel = this.travel.bind(this); this._onTouchStart = this.onTouchStart.bind(this); this._onTouchEnd = this.onTouchEnd.bind(this); @@ -271,6 +270,8 @@ class GlobeControls extends THREE.EventDispatcher { this._onPan = this.handlePan.bind(this); this._onPanoramic = this.handlePanoramic.bind(this); + this._onZoom = this.handleZoom.bind(this); + this.states.addEventListener('state-changed', this._onStateChange, false); this.states.addEventListener(this.states.ORBIT._event, this._onRotation, false); @@ -279,7 +280,8 @@ class GlobeControls extends THREE.EventDispatcher { this.states.addEventListener(this.states.PAN._event, this._onPan, false); this.states.addEventListener(this.states.PANORAMIC._event, this._onPanoramic, false); - this.view.domElement.addEventListener('wheel', this._onMouseWheel, false); + this.states.addEventListener('zoom', this._onZoom, false); + this.view.domElement.addEventListener('touchstart', this._onTouchStart, false); this.view.domElement.addEventListener('touchend', this._onTouchEnd, false); this.view.domElement.addEventListener('touchmove', this._onTouchMove, false); @@ -737,15 +739,12 @@ class GlobeControls extends THREE.EventDispatcher { } } - onMouseWheel(event) { + handleZoom(event) { this.player.stop(); - // TODO : this.states.enabled check should be removed when moving wheel events management to StateControl - if (!this.states.enabled || !this.states.DOLLY.enable) { return; } CameraUtils.stop(this.view, this.camera); - event.preventDefault(); this.updateTarget(); - const delta = -event.deltaY; + const delta = -event.delta; this.dolly(delta); const previousRange = this.getRange(pickedPosition); @@ -878,7 +877,6 @@ class GlobeControls extends THREE.EventDispatcher { } dispose() { - this.view.domElement.removeEventListener('wheel', this._onMouseWheel, false); this.view.domElement.removeEventListener('touchstart', this._onTouchStart, false); this.view.domElement.removeEventListener('touchend', this._onTouchEnd, false); this.view.domElement.removeEventListener('touchmove', this._onTouchMove, false); @@ -893,6 +891,8 @@ class GlobeControls extends THREE.EventDispatcher { this.states.removeEventListener(this.states.PAN._event, this._onPan, false); this.states.removeEventListener(this.states.PANORAMIC._event, this._onPanoramic, false); + this.states.removeEventListener('zoom', this._onZoom, false); + this.states.removeEventListener(this.states.TRAVEL_IN._event, this._onTravel, false); this.states.removeEventListener(this.states.TRAVEL_OUT._event, this._onTravel, false); diff --git a/src/Controls/StateControl.js b/src/Controls/StateControl.js index b45f5f1e8b..b0de7d51ed 100644 --- a/src/Controls/StateControl.js +++ b/src/Controls/StateControl.js @@ -65,6 +65,11 @@ const DEFAULT_STATES = { _trigger: true, _direction: 'out', }, + ZOOM: { + enable: true, + _event: 'zoom', + _trigger: true, + }, PAN_UP: { enable: true, keyboard: CONTROL_KEYS.UP, @@ -139,6 +144,7 @@ const viewCoords = new THREE.Vector2(); * a given position. The target position depends on the key/mouse binding of this * state. If bound to a mouse button, the target position is the mouse position. * Otherwise, it is the center of the screen. It is disabled by default. + * @property {State} ZOOM {@link State} describing camera zoom in and out movement. * @property {boolean} enable Defines whether all input will be communicated to the associated `Controls` or not. * Default is true. * @property {boolean} enableKeys Defines whether keyboard input will be communicated to the associated `Controls` or @@ -198,6 +204,7 @@ class StateControl extends THREE.EventDispatcher { this._onPointerDown = this.onPointerDown.bind(this); this._onPointerMove = this.onPointerMove.bind(this); this._onPointerUp = this.onPointerUp.bind(this); + this._onMouseWheel = this.onMouseWheel.bind(this); this._onKeyDown = this.onKeyDown.bind(this); this._onKeyUp = this.onKeyUp.bind(this); @@ -206,6 +213,7 @@ class StateControl extends THREE.EventDispatcher { this._onContextMenu = this.onContextMenu.bind(this); this._domElement.addEventListener('pointerdown', this._onPointerDown, false); + this._domElement.addEventListener('wheel', this._onMouseWheel, false); // The event listener is added on `window` so that key input can be accounted event if the view does not have // the focus. This can occur at page loading, when a mini map is displayed : the minimap initially has the focus @@ -374,6 +382,17 @@ class StateControl extends THREE.EventDispatcher { } + // ---------- WHEEL EVENT : ---------- + + onMouseWheel(event) { + event.preventDefault(); + + if (this.enabled && this.ZOOM.enable) { + this.dispatchEvent({ type: this.ZOOM._event, delta: event.deltaY }); + } + } + + // ---------- KEYBOARD EVENTS : ---------- onKeyDown(event) { @@ -412,6 +431,7 @@ class StateControl extends THREE.EventDispatcher { this._domElement.removeEventListener('pointerdown', this._onPointerDown, false); this._domElement.removeEventListener('pointermove', this._onPointerMove, false); this._domElement.removeEventListener('pointerup', this._onPointerUp, false); + this._domElement.removeEventListener('wheel', this._onMouseWheel, false); this._domElement.removeEventListener('keydown', this._onKeyDown, false); this._domElement.removeEventListener('keyup', this._onKeyUp, false); diff --git a/test/unit/globecontrol.js b/test/unit/globecontrol.js index ee78b252af..688b7167a0 100644 --- a/test/unit/globecontrol.js +++ b/test/unit/globecontrol.js @@ -139,14 +139,14 @@ describe('GlobeControls', function () { controls.state = controls.states.NONE; }); - it('mouse wheel', function () { + it('zoom', function () { const startRange = controls.getRange(); - event.deltaY = -10; - controls.onMouseWheel(event); + event.delta = -10; + controls.handleZoom(event); assert.ok(controls.getRange() < startRange); - event.deltaY = 10; - controls.onMouseWheel(event); - controls.onMouseWheel(event); + event.delta = 10; + controls.handleZoom(event); + controls.handleZoom(event); assert.ok(controls.getRange() > startRange); }); diff --git a/test/unit/statecontrol.js b/test/unit/statecontrol.js index e450f41401..2420611388 100644 --- a/test/unit/statecontrol.js +++ b/test/unit/statecontrol.js @@ -266,6 +266,16 @@ describe('StateControl', function () { })); }); + it('should trigger zoom event from wheel event', function () { + assert(testEventTriggering('zoom', event, states._onMouseWheel)); + }); + + it('should not trigger zoom event if zoom trigger is disabled', function () { + states.ZOOM.enable = false; + assert(!testEventTriggering('zoom', event, states._onMouseWheel)); + states.ZOOM.enable = true; + }); + it('blur event should resume currentState to NONE', function () { states.currentState = states.MOVE_GLOBE; states._onBlur(event); @@ -331,6 +341,8 @@ describe('StateControl', function () { states._onKeyUp(); })); + assert(!testEventTriggering('zoom', event, states._onMouseWheel)); + states.enabled = true; });