Skip to content

Commit d99827d

Browse files
mgermeriegchoqueux
authored andcommittedJul 29, 2021
refacto(GlobeControls): switch travel animation to StateControl
1 parent 9ce7213 commit d99827d

File tree

4 files changed

+89
-15
lines changed

4 files changed

+89
-15
lines changed
 

‎src/Controls/GlobeControls.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class GlobeControls extends THREE.EventDispatcher {
174174
this.camera = view.camera.camera3D;
175175

176176
// State control
177-
this.states = new StateControl();
177+
this.states = new StateControl(this.view);
178178
this.state = this.states.NONE;
179179

180180
// Set to false to disable this control
@@ -242,7 +242,7 @@ class GlobeControls extends THREE.EventDispatcher {
242242
this._onMouseDown = this.onMouseDown.bind(this);
243243
this._onMouseWheel = this.onMouseWheel.bind(this);
244244
this._onContextMenuListener = this.onContextMenuListener.bind(this);
245-
this._ondblclick = this.ondblclick.bind(this);
245+
this._onTravel = this.travel.bind(this);
246246
this._onTouchStart = this.onTouchStart.bind(this);
247247
this._update = this.update.bind(this);
248248
this._onTouchMove = this.onTouchMove.bind(this);
@@ -253,12 +253,13 @@ class GlobeControls extends THREE.EventDispatcher {
253253
this.view.domElement.addEventListener('contextmenu', this._onContextMenuListener, false);
254254
this.view.domElement.addEventListener('mousedown', this._onMouseDown, false);
255255
this.view.domElement.addEventListener('mousewheel', this._onMouseWheel, false);
256-
this.view.domElement.addEventListener('dblclick', this._ondblclick, false);
257256
this.view.domElement.addEventListener('DOMMouseScroll', this._onMouseWheel, false); // firefox
258257
this.view.domElement.addEventListener('touchstart', this._onTouchStart, false);
259258
this.view.domElement.addEventListener('touchend', this._onMouseUp, false);
260259
this.view.domElement.addEventListener('touchmove', this._onTouchMove, false);
261260

261+
this.states.addEventListener('travel_in', this._onTravel, false);
262+
262263
// refresh control for each animation's frame
263264
this.player.addEventListener('animation-frame', this._update);
264265

@@ -675,10 +676,10 @@ class GlobeControls extends THREE.EventDispatcher {
675676
}
676677
}
677678

678-
ondblclick(event) {
679-
if (this.enabled === false || currentKey) { return; }
679+
travel(event) {
680+
if (this.enabled === false) { return; }
680681
this.player.stop();
681-
const point = this.view.getPickingPositionFromDepth(this.view.eventToViewCoords(event));
682+
const point = this.view.getPickingPositionFromDepth(event.viewCoords);
682683
const range = this.getRange(point);
683684
if (point && range > this.minDistance) {
684685
return this.lookAtCoordinate({
@@ -910,12 +911,14 @@ class GlobeControls extends THREE.EventDispatcher {
910911
this.view.domElement.removeEventListener('DOMMouseScroll', this._onMouseWheel, false); // firefox
911912
this.view.domElement.removeEventListener('mouseup', this._onMouseUp, false);
912913
this.view.domElement.removeEventListener('mouseleave', this._onMouseUp, false);
913-
this.view.domElement.removeEventListener('dblclick', this._ondblclick, false);
914914

915915
this.view.domElement.removeEventListener('touchstart', this._onTouchStart, false);
916916
this.view.domElement.removeEventListener('touchend', this._onMouseUp, false);
917917
this.view.domElement.removeEventListener('touchmove', this._onTouchMove, false);
918918

919+
this.states.dispose();
920+
this.states.removeEventListener('travel_in', this._onTravel, false);
921+
919922
this.player.removeEventListener('animation-frame', this._onKeyUp);
920923

921924
window.removeEventListener('keydown', this._onKeyDown, false);

‎src/Controls/StateControl.js

+61-4
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,28 @@ const CONTROL_KEYS = {
1212
};
1313

1414

15+
function stateToTrigger(state) {
16+
if (!state) {
17+
return undefined;
18+
} else if (state.mouseButton === THREE.MOUSE.LEFT && state.double) {
19+
return 'dblclick';
20+
} else if (state.mouseButton === THREE.MOUSE.RIGHT && state.double) {
21+
return 'dblclick-right';
22+
} else if (state.keyboard) {
23+
return 'keydown';
24+
}
25+
}
26+
27+
1528
/**
1629
* @typedef {Object} StateControl~State
1730
* @property {boolean} enable=true Indicate whether the state is enabled or not.
1831
* @property {Number} [mouseButton] The mouse button bound to this state.
1932
* @property {Number} [keyboard] The keyCode of the keyboard input bound to this state.
2033
* @property {Number} [finger] The number of fingers on the pad bound to this state.
34+
* @property {boolean} [double] True if the mouse button bound to this state must be pressed twice. For
35+
* example, if `double` is set to true with a `mouseButton` set to left click,
36+
* the State will be bound to a double click mouse button.
2137
*/
2238

2339
/**
@@ -37,24 +53,48 @@ const CONTROL_KEYS = {
3753
* to give the feeling that the view is dragged under a static camera.
3854
* @property {State} PANORAMIC {@link State} describing camera panoramic movement : the camera is rotated around
3955
* its own position.
56+
* @property {State} TRAVEL_IN {@link State} describing camera travel in movement : the camera is zoomed in toward
57+
* a given position. The choice of the target position is made in the Controls
58+
* associated to this StateControl.
59+
* This state can only be associated to double click on mouse buttons (left or right)
60+
* or a keyboard key.
4061
*/
41-
class StateControl {
42-
constructor(options = {}) {
62+
class StateControl extends THREE.EventDispatcher {
63+
constructor(view, options = {}) {
64+
super();
65+
66+
this._view = view;
67+
this._domElement = view.domElement;
68+
4369
this.NONE = {};
4470

71+
this._handleTravelInEvent = (event) => {
72+
if (this.TRAVEL_IN === this.inputToState(event.button, event.keyCode, this.TRAVEL_IN.double)) {
73+
this.dispatchEvent({
74+
type: 'travel_in',
75+
viewCoords: this._view.eventToViewCoords(event),
76+
});
77+
}
78+
};
79+
4580
this.setFromOptions(options);
4681
}
4782

4883
/**
4984
* get the state corresponding to the mouse button and the keyboard key
5085
* @param {Number} mouseButton The mouse button
5186
* @param {Number} keyboard The keyboard
87+
* @param {Boolean} [double] Value of the searched state `double` property
5288
* @return {state} the state corresponding
5389
*/
54-
inputToState(mouseButton, keyboard) {
90+
inputToState(mouseButton, keyboard, double) {
5591
for (const key of Object.keys(this)) {
5692
const state = this[key];
57-
if (state.enable && state.mouseButton === mouseButton && state.keyboard === keyboard) {
93+
if (state.enable
94+
&& state.mouseButton === mouseButton
95+
&& state.keyboard === keyboard
96+
&& state.double === double
97+
) {
5898
return state;
5999
}
60100
}
@@ -124,6 +164,23 @@ class StateControl {
124164
keyboard: CONTROL_KEYS.SHIFT,
125165
enable: true,
126166
};
167+
168+
const newTravelIn = options.TRAVEL_IN || this.TRAVEL_IN || {
169+
enable: true,
170+
mouseButton: THREE.MOUSE.LEFT,
171+
double: true,
172+
};
173+
174+
this._domElement.removeEventListener(stateToTrigger(this.TRAVEL_IN), this._handleTravelInEvent, false);
175+
this._domElement.addEventListener(stateToTrigger(newTravelIn), this._handleTravelInEvent, false);
176+
this.TRAVEL_IN = newTravelIn;
177+
}
178+
179+
/**
180+
* Remove all event listeners created within this instance of `StateControl`
181+
*/
182+
dispose() {
183+
this._domElement.removeEventListener(this.TRAVEL_IN.trigger, this._handleTravelInEvent, false);
127184
}
128185
}
129186

‎test/unit/globecontrol.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,12 @@ describe('GlobeControls', function () {
189189
assert.ok(controls.getRange() < startRange);
190190
});
191191

192-
it('mouse dblclick', function (done) {
192+
it('travel in', function (done) {
193193
controls.setAnimationEnabled(false);
194194
const startRange = controls.getRange();
195-
controls.ondblclick(event).then(() => {
195+
controls.travel({
196+
viewCoords: viewer.eventToViewCoords(event),
197+
}).then(() => {
196198
assert.ok(controls.getRange() < startRange);
197199
done();
198200
});

‎test/unit/statecontrol.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import { MOUSE } from 'three';
22
import assert from 'assert';
3-
import StateControl from 'Controls/StateControl';
3+
import Coordinates from 'Core/Geographic/Coordinates';
4+
import GlobeView from 'Core/Prefab/GlobeView';
5+
import Renderer from './bootstrap';
46

57
describe('StateControl', function () {
6-
const states = new StateControl();
8+
const renderer = new Renderer();
9+
10+
const placement = { coord: new Coordinates('EPSG:4326', 2.351323, 48.856712), range: 250000, proxy: false };
11+
const viewer = new GlobeView(renderer.domElement, placement, { renderer });
12+
const states = viewer.controls.states;
713

814
it('inputToState should return the correct state', function () {
915
assert.strictEqual(
@@ -44,6 +50,7 @@ describe('StateControl', function () {
4450
ORBIT: { enable: true, mouseButton: MOUSE.MIDDLE },
4551
DOLLY: { enable: true, mouseButton: MOUSE.RIGHT },
4652
PANORAMIC: { enable: true, mouseButton: MOUSE.LEFT, keyboard: 17 },
53+
TRAVEL_IN: { enable: true, mouseButton: MOUSE.LEFT, double: true },
4754
};
4855
states.setFromOptions(options);
4956

@@ -52,5 +59,10 @@ describe('StateControl', function () {
5259
assert.strictEqual(JSON.stringify(options.ORBIT), JSON.stringify(states.ORBIT));
5360
assert.strictEqual(JSON.stringify(options.DOLLY), JSON.stringify(states.DOLLY));
5461
assert.strictEqual(JSON.stringify(options.PANORAMIC), JSON.stringify(states.PANORAMIC));
62+
assert.strictEqual(JSON.stringify(options.TRAVEL_IN), JSON.stringify(states.TRAVEL_IN));
63+
});
64+
65+
it('should dispose event listeners', function () {
66+
states.dispose();
5567
});
5668
});

0 commit comments

Comments
 (0)
Please sign in to comment.