Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Sign In

uber / deck.gl / 14011

20 Sep 2019 - 23:54 coverage increased (+2.7%) to 82.999%
14011

Pull #3672

travis-ci-com

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
bump loaders.gl version
Pull Request #3672: Fix bugs in pre-bundled version

3393 of 4577 branches covered (74.13%)

Branch coverage included in aggregate %.

7157 of 8134 relevant lines covered (87.99%)

4305.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.12
/modules/core/src/controllers/orbit-controller.js
1
import {clamp, Vector2} from 'math.gl';
2
import Controller from './controller';
3
import ViewState from './view-state';
4
import LinearInterpolator from '../transitions/linear-interpolator';
5
import {TRANSITION_EVENTS} from './transition-manager';
6

7
const MOVEMENT_SPEED = 50; // per keyboard click
1×
8

9
const DEFAULT_STATE = {
10×
10
  orbitAxis: 'Z',
11
  rotationX: 0,
12
  rotationOrbit: 0,
13
  fovy: 50,
14
  zoom: 0,
15
  target: [0, 0, 0],
16
  minRotationX: -90,
17
  maxRotationX: 90,
18
  minZoom: -Infinity,
19
  maxZoom: Infinity
20
};
21

22
const LINEAR_TRANSITION_PROPS = {
10×
23
  transitionDuration: 300,
24
  transitionEasing: t => t,
1×
25
  transitionInterpolator: new LinearInterpolator(['target', 'zoom', 'rotationX', 'rotationOrbit']),
26
  transitionInterruption: TRANSITION_EVENTS.BREAK
27
};
28

29
/* Helpers */
30

31
const zoom2Scale = zoom => Math.pow(2, zoom);
1×
32

33
// const mod = (value, divisor) => {
34
//   const modulus = value % divisor;
35
//   return modulus < 0 ? divisor + modulus : modulus;
36
// };
37

38
export class OrbitState extends ViewState {
39
  constructor({
40
    ViewportType,
41

42
    /* Viewport arguments */
43
    width, // Width of viewport
44
    height, // Height of viewport
45
    orbitAxis = DEFAULT_STATE.orbitAxis,
46
    rotationX = DEFAULT_STATE.rotationX, // Rotation around x axis
47
    rotationOrbit = DEFAULT_STATE.rotationOrbit, // Rotation around orbit axis
48
    target = DEFAULT_STATE.target,
Branches [[3, 0]] missed.
49
    zoom = DEFAULT_STATE.zoom,
Branches [[4, 0]] missed.
50
    fovy = DEFAULT_STATE.fovy,
51

52
    /* Viewport constraints */
53
    minRotationX = DEFAULT_STATE.minRotationX,
54
    maxRotationX = DEFAULT_STATE.maxRotationX,
55
    minZoom = DEFAULT_STATE.minZoom,
56
    maxZoom = DEFAULT_STATE.maxZoom,
57

58
    /** Interaction states, required to calculate change during transform */
59
    // Model state when the pan operation first started
60
    startPanPosition,
61
    startTarget,
62
    // Model state when the rotate operation first started
63
    startRotationX,
64
    startRotationOrbit,
65
    // Model state when the zoom operation first started
66
    startZoomPosition,
67
    startZoom
68
  }) {
69
    super({
1×
70
      width,
71
      height,
72
      orbitAxis,
73
      rotationX,
74
      rotationOrbit,
75
      target,
76
      fovy,
77
      zoom,
78
      minRotationX,
79
      maxRotationX,
80
      minZoom,
81
      maxZoom
82
    });
83

84
    this._interactiveState = {
1×
85
      startPanPosition,
86
      startTarget,
87
      startRotationX,
88
      startRotationOrbit,
89
      startZoomPosition,
90
      startZoom
91
    };
92

93
    this.ViewportType = ViewportType;
1×
94
  }
95

96
  /* Public API */
97

98
  getViewportProps() {
99
    return this._viewportProps;
1×
100
  }
101

102
  getInteractiveState() {
103
    return this._interactiveState;
1×
104
  }
105

106
  /**
107
   * Start panning
108
   * @param {[Number, Number]} pos - position on screen where the pointer grabs
109
   */
110
  panStart({pos}) {
111
    const {target} = this._viewportProps;
1×
112

113
    return this._getUpdatedState({
1×
114
      startPanPosition: pos,
115
      startTarget: target
116
    });
117
  }
118

119
  /**
120
   * Pan
121
   * @param {[Number, Number]} pos - position on screen where the pointer is
122
   */
123
  pan({pos, startPos}) {
124
    const {startPanPosition, startTarget} = this._interactiveState;
1×
125
    const delta = new Vector2(pos).subtract(startPanPosition);
1×
126

127
    return this._getUpdatedState({
1×
128
      target: this._calculateNewTarget({startTarget, pixelOffset: delta})
129
    });
130
  }
131

132
  /**
133
   * End panning
134
   * Must call if `panStart()` was called
135
   */
136
  panEnd() {
137
    return this._getUpdatedState({
1×
138
      startPanPosition: null,
139
      startTarget: null
140
    });
141
  }
142

143
  /**
144
   * Start rotating
145
   * @param {[Number, Number]} pos - position on screen where the pointer grabs
146
   */
147
  rotateStart({pos}) {
148
    return this._getUpdatedState({
12×
149
      startRotationX: this._viewportProps.rotationX,
150
      startRotationOrbit: this._viewportProps.rotationOrbit
151
    });
152
  }
153

154
  /**
155
   * Rotate
156
   * @param {[Number, Number]} pos - position on screen where the pointer is
157
   */
158
  rotate({deltaScaleX, deltaScaleY}) {
159
    const {startRotationX, startRotationOrbit} = this._interactiveState;
1×
160

161
    if (!Number.isFinite(startRotationX) || !Number.isFinite(startRotationOrbit)) {
Branches [[10, 0]] missed. 12×
162
      return this;
250×
163
    }
164
    if (startRotationX < -90 || startRotationX > 90) {
Branches [[12, 0]] missed. 250×
165
      // When looking at the "back" side of the scene, invert horizontal drag
166
      // so that the camera movement follows user input
167
      deltaScaleX *= -1;
250×
168
    }
169

170
    return this._getUpdatedState({
145×
171
      rotationX: startRotationX + deltaScaleY * 180,
172
      rotationOrbit: startRotationOrbit + deltaScaleX * 180,
173
      isRotating: true
174
    });
175
  }
176

177
  /**
178
   * End rotating
179
   * Must call if `rotateStart()` was called
180
   */
181
  rotateEnd() {
182
    return this._getUpdatedState({
61×
183
      startRotationX: null,
184
      startRotationOrbit: null
185
    });
186
  }
187

188
  // default implementation of shortest path between two view states
189
  shortestPathFrom(viewState) {
190
    const props = Object.assign({}, this._viewportProps);
7×
191
    return props;
7×
192
  }
193

194
  /**
195
   * Start zooming
196
   * @param {[Number, Number]} pos - position on screen where the pointer grabs
197
   */
198
  zoomStart({pos}) {
199
    return this._getUpdatedState({
2×
200
      startZoomPosition: pos,
201
      startTarget: this._viewportProps.target,
202
      startZoom: this._viewportProps.zoom
203
    });
204
  }
205

206
  /**
207
   * Zoom
208
   * @param {[Number, Number]} pos - position on screen where the current target is
209
   * @param {[Number, Number]} startPos - the target position at
210
   *   the start of the operation. Must be supplied of `zoomStart()` was not called
211
   * @param {Number} scale - a number between [0, 1] specifying the accumulated
212
   *   relative scale.
213
   */
214
  zoom({pos, startPos, scale}) {
215
    const {zoom, width, height, target} = this._viewportProps;
2×
216
    let {startZoom, startZoomPosition, startTarget} = this._interactiveState;
2×
217
    if (!Number.isFinite(startZoom)) {
11×
218
      // We have two modes of zoom:
219
      // scroll zoom that are discrete events (transform from the current zoom level),
220
      // and pinch zoom that are continuous events (transform from the zoom level when
221
      // pinch started).
222
      // If startZoom state is defined, then use the startZoom state;
223
      // otherwise assume discrete zooming
224
      startZoom = zoom;
11×
225
      startTarget = target;
3×
226
      startZoomPosition = startPos || pos;
3×
227
    }
228

UNCOV
229
    const newZoom = this._calculateNewZoom({scale, startZoom});
!
230
    const startScale = zoom2Scale(startZoom);
3×
UNCOV
231
    const newScale = zoom2Scale(newZoom);
!
232

233
    const dX = (width / 2 - startZoomPosition[0]) * (newScale / startScale - 1);
3×
234
    const dY = (height / 2 - startZoomPosition[1]) * (newScale / startScale - 1);
17×
235

236
    return this._getUpdatedState({
22×
237
      zoom: newZoom,
238
      target: this._calculateNewTarget({startTarget, zoom: newZoom, pixelOffset: [dX, dY]})
239
    });
240
  }
241

242
  /**
243
   * End zooming
244
   * Must call if `zoomStart()` was called
245
   */
246
  zoomEnd() {
247
    return this._getUpdatedState({
22×
248
      startZoomPosition: null,
249
      startTarget: null,
250
      startZoom: null
251
    });
252
  }
253

254
  zoomIn() {
255
    return this._getUpdatedState({
4×
256
      zoom: this._calculateNewZoom({scale: 2})
257
    });
258
  }
259

260
  zoomOut() {
261
    return this._getUpdatedState({
6×
262
      zoom: this._calculateNewZoom({scale: 0.5})
263
    });
264
  }
265

266
  moveLeft() {
267
    const pixelOffset = [-MOVEMENT_SPEED, 0];
6×
268
    return this._getUpdatedState({
6×
269
      target: this._calculateNewTarget({pixelOffset})
270
    });
271
  }
272

273
  moveRight() {
274
    const pixelOffset = [MOVEMENT_SPEED, 0];
4×
275
    return this._getUpdatedState({
4×
276
      target: this._calculateNewTarget({pixelOffset})
277
    });
278
  }
279

280
  moveUp() {
281
    const pixelOffset = [0, -MOVEMENT_SPEED];
4×
282
    return this._getUpdatedState({
6×
283
      target: this._calculateNewTarget({pixelOffset})
284
    });
285
  }
286

287
  moveDown() {
288
    const pixelOffset = [0, MOVEMENT_SPEED];
6×
289
    return this._getUpdatedState({
6×
290
      target: this._calculateNewTarget({pixelOffset})
291
    });
292
  }
293

294
  rotateLeft() {
295
    return this._getUpdatedState({
6×
296
      rotationOrbit: this._viewportProps.rotationOrbit - 15
297
    });
298
  }
299

300
  rotateRight() {
301
    return this._getUpdatedState({
6×
302
      rotationOrbit: this._viewportProps.rotationOrbit + 15
303
    });
304
  }
305

306
  rotateUp() {
307
    return this._getUpdatedState({
6×
308
      rotationX: this._viewportProps.rotationX - 10
309
    });
310
  }
311

312
  rotateDown() {
313
    return this._getUpdatedState({
6×
314
      rotationX: this._viewportProps.rotationX + 10
315
    });
316
  }
317

318
  /* Private methods */
319

320
  // Calculates new zoom
321
  _calculateNewZoom({scale, startZoom}) {
322
    const {maxZoom, minZoom} = this._viewportProps;
6×
323
    if (!Number.isFinite(startZoom)) {
6×
324
      startZoom = this._viewportProps.zoom;
2×
325
    }
326
    const zoom = startZoom + Math.log2(scale);
2×
327
    return clamp(zoom, minZoom, maxZoom);
2×
328
  }
329

330
  _calculateNewTarget({startTarget, zoom, pixelOffset}) {
331
    const viewportProps = Object.assign({}, this._viewportProps);
2×
332
    if (Number.isFinite(zoom)) {
2×
333
      viewportProps.zoom = zoom;
2×
334
    }
335
    if (startTarget) {
2×
336
      viewportProps.target = startTarget;
2×
337
    }
338
    const viewport = new this.ViewportType(viewportProps);
2×
339
    const center = viewport.project(viewportProps.target);
2×
340
    return viewport.unproject([center[0] - pixelOffset[0], center[1] - pixelOffset[1], center[2]]);
2×
341
  }
342

343
  _getUpdatedState(newProps) {
344
    // Update _viewportProps
345
    return new OrbitState(Object.assign({}, this._viewportProps, this._interactiveState, newProps));
2×
346
  }
347

348
  // Apply any constraints (mathematical or defined by _viewportProps) to map state
349
  _applyConstraints(props) {
350
    // Ensure zoom is within specified range
351
    const {maxZoom, minZoom, zoom, maxRotationX, minRotationX} = props;
18×
352

353
    props.zoom = clamp(zoom, minZoom, maxZoom);
18×
354
    props.rotationX = clamp(props.rotationX, minRotationX, maxRotationX);
12×
355

356
    return props;
18×
357
  }
358
}
359

360
export default class OrbitController extends Controller {
361
  constructor(props) {
362
    super(OrbitState, props);
18×
363
  }
364

365
  _getTransitionProps() {
366
    // Enables Transitions on double-tap and key-down events.
367
    return LINEAR_TRANSITION_PROPS;
16×
368
  }
369
}
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
BLOG · TWITTER · Legal & Privacy · Supported CI Services · What's a CI service? · Automated Testing

© 2019 Coveralls, LLC