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

uber / deck.gl / 13340

10 Sep 2019 - 3:13 coverage decreased (-2.6%) to 80.892%
13340

Pull #3552

travis-ci-com

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
[#3548 - Part 4] Modify setup.py to specify that README is markdown
Pull Request #3552: [#3548 - Part 4] Update notebook documentation to include additional pydeck features

3330 of 4491 branches covered (74.15%)

Branch coverage included in aggregate %.

6860 of 8106 relevant lines covered (84.63%)

5923.39 hits per line

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

77.17
/modules/core/src/lib/deck.js
1
// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
29×
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a copy
4
// of this software and associated documentation files (the "Software"), to deal
5
// in the Software without restriction, including without limitation the rights
6
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
// copies of the Software, and to permit persons to whom the Software is
8
// furnished to do so, subject to the following conditions:
9
//
10
// The above copyright notice and this permission notice shall be included in
11
// all copies or substantial portions of the Software.
12
//
13
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
// THE SOFTWARE.
20

21
import LayerManager from './layer-manager';
22
import ViewManager from './view-manager';
23
import MapView from '../views/map-view';
24
import EffectManager from './effect-manager';
25
import Effect from './effect';
26
import DeckRenderer from './deck-renderer';
27
import DeckPicker from './deck-picker';
28
import log from '../utils/log';
29
import deckGlobal from './init';
30

31
import GL from '@luma.gl/constants';
32
import {
33
  AnimationLoop,
34
  createGLContext,
35
  trackContextState,
36
  setParameters,
37
  lumaStats
38
} from '@luma.gl/core';
39
import {Timeline} from '@luma.gl/addons';
40
import {Stats} from 'probe.gl';
41
import {EventManager} from 'mjolnir.js';
42

43
import assert from '../utils/assert';
44
import {EVENTS} from './constants';
45
/* global window, document */
46

47
function noop() {}
48

49
const getCursor = ({isDragging}) => (isDragging ? 'grabbing' : 'grab');
Branches [[0, 0]] missed. 13×
50

51
function getPropTypes(PropTypes) {
52
  // Note: Arrays (layers, views, ) can contain falsy values
53
  return {
1×
54
    id: PropTypes.string,
55
    width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
56
    height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
57

58
    // layer/view/controller settings
59
    layers: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
60
    layerFilter: PropTypes.func,
61
    views: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
62
    viewState: PropTypes.object,
63
    effects: PropTypes.arrayOf(PropTypes.instanceOf(Effect)),
64
    controller: PropTypes.oneOfType([PropTypes.func, PropTypes.bool, PropTypes.object]),
65

66
    // GL settings
67
    gl: PropTypes.object,
68
    glOptions: PropTypes.object,
69
    parameters: PropTypes.object,
70
    pickingRadius: PropTypes.number,
71
    useDevicePixels: PropTypes.bool,
72
    touchAction: PropTypes.string,
73

74
    // Callbacks
75
    onWebGLInitialized: PropTypes.func,
76
    onResize: PropTypes.func,
77
    onViewStateChange: PropTypes.func,
78
    onBeforeRender: PropTypes.func,
79
    onAfterRender: PropTypes.func,
80
    onLoad: PropTypes.func,
81

82
    // Debug settings
83
    debug: PropTypes.bool,
84
    drawPickingColors: PropTypes.bool,
85

86
    // Experimental props
87

88
    // Forces a redraw every animation frame
89
    _animate: PropTypes.bool
90
  };
91
}
92

93
const defaultProps = {
1×
94
  id: 'deckgl-overlay',
95
  width: '100%',
96
  height: '100%',
97

98
  pickingRadius: 0,
99
  layerFilter: null,
100
  glOptions: {},
101
  gl: null,
102
  layers: [],
103
  effects: [],
104
  views: null,
105
  controller: null, // Rely on external controller, e.g. react-map-gl
106
  useDevicePixels: true,
107
  touchAction: 'none',
108
  _animate: false,
109

110
  onWebGLInitialized: noop,
111
  onResize: noop,
112
  onViewStateChange: noop,
113
  onBeforeRender: noop,
114
  onAfterRender: noop,
115
  onLoad: noop,
116
  _onMetrics: null,
117

118
  getCursor,
119

120
  debug: false,
121
  drawPickingColors: false
122
};
123

124
/* eslint-disable max-statements */
125
export default class Deck {
126
  constructor(props) {
127
    props = Object.assign({}, defaultProps, props);
10×
128

129
    this.width = 0; // "read-only", auto-updated from canvas
10×
130
    this.height = 0; // "read-only", auto-updated from canvas
10×
131

132
    // Maps view descriptors to vieports, rebuilds when width/height/viewState/views change
133
    this.viewManager = null;
10×
134
    this.layerManager = null;
10×
135
    this.effectManager = null;
10×
136
    this.deckRenderer = null;
10×
137
    this.deckPicker = null;
10×
138

139
    this._needsRedraw = true;
10×
140
    this._pickRequest = {};
10×
141
    // Pick and store the object under the pointer on `pointerdown`.
142
    // This object is reused for subsequent `onClick` and `onDrag*` callbacks.
143
    this._lastPointerDownInfo = null;
10×
144

145
    this.viewState = props.initialViewState || null; // Internal view state if no callback is supplied
10×
146
    this.interactiveState = {
10×
147
      isDragging: false // Whether the cursor is down
148
    };
149

150
    // Bind methods
151
    this._onEvent = this._onEvent.bind(this);
10×
152
    this._onPointerDown = this._onPointerDown.bind(this);
10×
153
    this._onPointerMove = this._onPointerMove.bind(this);
10×
154
    this._pickAndCallback = this._pickAndCallback.bind(this);
10×
155
    this._onRendererInitialized = this._onRendererInitialized.bind(this);
10×
156
    this._onRenderFrame = this._onRenderFrame.bind(this);
10×
157
    this._onViewStateChange = this._onViewStateChange.bind(this);
10×
158
    this._onInteractiveStateChange = this._onInteractiveStateChange.bind(this);
10×
159

160
    if (isIE11()) {
Branches [[2, 0]] missed. 10×
UNCOV
161
      log.warn('IE 11 support will be deprecated in v8.0')();
!
162
    }
163

164
    if (!props.gl) {
10×
165
      // Note: LayerManager creation deferred until gl context available
166
      if (typeof document !== 'undefined') {
Branches [[4, 1]] missed. 2×
167
        this.canvas = this._createCanvas(props);
2×
168
      }
169
    }
170
    this.animationLoop = this._createAnimationLoop(props);
10×
171

172
    this.stats = new Stats({id: 'deck.gl'});
10×
173
    this.metrics = {
10×
174
      fps: 0,
175
      setPropsTime: 0,
176
      updateAttributesTime: 0,
177
      framesRedrawn: 0,
178
      pickTime: 0,
179
      pickCount: 0,
180
      gpuTime: 0,
181
      gpuTimePerFrame: 0,
182
      cpuTime: 0,
183
      cpuTimePerFrame: 0,
184
      bufferMemory: 0,
185
      textureMemory: 0,
186
      renderbufferMemory: 0,
187
      gpuMemory: 0
188
    };
189
    this._metricsCounter = 0;
10×
190

191
    this.setProps(props);
10×
192

193
    this.animationLoop.start();
10×
194
  }
195

196
  finalize() {
197
    this.animationLoop.stop();
10×
198
    this.animationLoop = null;
10×
199
    this._lastPointerDownInfo = null;
10×
200

201
    if (this.layerManager) {
10×
202
      this.layerManager.finalize();
8×
203
      this.layerManager = null;
8×
204
    }
205

206
    if (this.viewManager) {
10×
207
      this.viewManager.finalize();
8×
208
      this.viewManager = null;
8×
209
    }
210

211
    if (this.effectManager) {
10×
212
      this.effectManager.finalize();
8×
213
      this.effectManager = null;
8×
214
    }
215

216
    if (this.deckRenderer) {
10×
217
      this.deckRenderer.finalize();
8×
218
      this.deckRenderer = null;
8×
219
    }
220

221
    if (this.eventManager) {
10×
222
      this.eventManager.destroy();
8×
223
    }
224

225
    if (!this.props.canvas && !this.props.gl && this.canvas) {
Branches [[10, 0], [11, 2]] missed. 10×
226
      // remove internally created canvas
UNCOV
227
      this.canvas.parentElement.removeChild(this.canvas);
!
UNCOV
228
      this.canvas = null;
!
229
    }
230
  }
231

232
  setProps(props) {
233
    this.stats.get('setProps Time').timeStart();
31×
234

235
    if ('onLayerHover' in props) {
Branches [[12, 0]] missed. 31×
UNCOV
236
      log.removed('onLayerHover', 'onHover')();
!
237
    }
238
    if ('onLayerClick' in props) {
Branches [[13, 0]] missed. 31×
UNCOV
239
      log.removed('onLayerClick', 'onClick')();
!
240
    }
241

242
    props = Object.assign({}, this.props, props);
31×
243
    this.props = props;
31×
244

245
    // Update CSS size of canvas
246
    this._setCanvasSize(props);
31×
247

248
    // We need to overwrite CSS style width and height with actual, numeric values
249
    const newProps = Object.assign({}, props, {
31×
250
      views: this._getViews(this.props),
251
      width: this.width,
252
      height: this.height
253
    });
254

255
    const viewState = this._getViewState(props);
31×
256
    if (viewState) {
Branches [[14, 1]] missed. 31×
257
      newProps.viewState = viewState;
31×
258
    }
259

260
    // Update view manager props
261
    if (this.viewManager) {
31×
262
      this.viewManager.setProps(newProps);
9×
263
    }
264

265
    // Update layer manager props (but not size)
266
    if (this.layerManager) {
31×
267
      this.layerManager.setProps(newProps);
9×
268
    }
269

270
    if (this.effectManager) {
31×
271
      this.effectManager.setProps(newProps);
9×
272
    }
273

274
    // Update animation loop
275
    if (this.animationLoop) {
Branches [[18, 1]] missed. 31×
276
      this.animationLoop.setProps(newProps);
31×
277
    }
278

279
    if (this.deckRenderer) {
31×
280
      this.deckRenderer.setProps(newProps);
9×
281
    }
282

283
    if (this.deckPicker) {
31×
284
      this.deckPicker.setProps(newProps);
9×
285
    }
286

287
    this.stats.get('setProps Time').timeEnd();
31×
288
  }
289

290
  // Public API
291
  // Check if a redraw is needed
292
  // Returns `false` or a string summarizing the redraw reason
293
  // opts.clearRedrawFlags (Boolean) - clear the redraw flag. Default `true`
294
  needsRedraw(opts = {clearRedrawFlags: false}) {
Branches [[21, 0]] missed.
295
    if (this.props._animate) {
Branches [[22, 0]] missed. 13×
UNCOV
296
      return 'Deck._animate';
!
297
    }
298

299
    let redraw = this._needsRedraw;
13×
300

301
    if (opts.clearRedrawFlags) {
Branches [[23, 1]] missed. 13×
302
      this._needsRedraw = false;
13×
303
    }
304

305
    const viewManagerNeedsRedraw = this.viewManager.needsRedraw(opts);
13×
306
    const layerManagerNeedsRedraw = this.layerManager.needsRedraw(opts);
13×
307
    const effectManagerNeedsRedraw = this.effectManager.needsRedraw(opts);
13×
308
    const deckRendererNeedsRedraw = this.deckRenderer.needsRedraw(opts);
13×
309

310
    redraw =
13×
311
      redraw ||
312
      viewManagerNeedsRedraw ||
313
      layerManagerNeedsRedraw ||
314
      effectManagerNeedsRedraw ||
315
      deckRendererNeedsRedraw;
316
    return redraw;
13×
317
  }
318

319
  redraw(force) {
320
    if (!this.layerManager) {
15×
321
      // Not yet initialized
322
      return;
2×
323
    }
324
    // If force is falsy, check if we need to redraw
325
    const redrawReason = force || this.needsRedraw({clearRedrawFlags: true});
13×
326

327
    if (!redrawReason) {
13×
328
      return;
6×
329
    }
330

331
    this.stats.get('Redraw Count').incrementCount();
7×
332
    if (this.props._customRender) {
7×
333
      this.props._customRender(redrawReason);
1×
334
    } else {
335
      this._drawLayers(redrawReason);
6×
336
    }
337
  }
338

339
  getViews() {
UNCOV
340
    return this.viewManager.views;
!
341
  }
342

343
  // Get a set of viewports for a given width and height
344
  getViewports(rect) {
345
    return this.viewManager.getViewports(rect);
4×
346
  }
347

348
  pickObject({x, y, radius = 0, layerIds = null}) {
349
    this.stats.get('Pick Count').incrementCount();
1×
350
    this.stats.get('pickObject Time').timeStart();
1×
351
    const layers = this.layerManager.getLayers({layerIds});
1×
352
    const activateViewport = this.layerManager.activateViewport;
1×
353
    const selectedInfos = this.deckPicker.pickObject({
1×
354
      x,
355
      y,
356
      radius,
357
      layers,
358
      viewports: this.getViewports({x, y}),
359
      activateViewport,
360
      mode: 'query',
361
      depth: 1
362
    }).result;
363
    this.stats.get('pickObject Time').timeEnd();
1×
364
    return selectedInfos.length ? selectedInfos[0] : null;
Branches [[31, 1]] missed. 1×
365
  }
366

367
  pickMultipleObjects({x, y, radius = 0, layerIds = null, depth = 10}) {
368
    this.stats.get('Pick Count').incrementCount();
1×
369
    this.stats.get('pickMultipleObjects Time').timeStart();
1×
370
    const layers = this.layerManager.getLayers({layerIds});
1×
371
    const activateViewport = this.layerManager.activateViewport;
1×
372
    const selectedInfos = this.deckPicker.pickObject({
1×
373
      x,
374
      y,
375
      radius,
376
      layers,
377
      viewports: this.getViewports({x, y}),
378
      activateViewport,
379
      mode: 'query',
380
      depth
381
    }).result;
382
    this.stats.get('pickMultipleObjects Time').timeEnd();
1×
383
    return selectedInfos;
1×
384
  }
385

386
  pickObjects({x, y, width = 1, height = 1, layerIds = null}) {
Branches [[35, 0], [36, 0]] missed.
387
    this.stats.get('Pick Count').incrementCount();
1×
388
    this.stats.get('pickObjects Time').timeStart();
1×
389
    const layers = this.layerManager.getLayers({layerIds});
1×
390
    const activateViewport = this.layerManager.activateViewport;
1×
391
    const infos = this.deckPicker.pickObjects({
1×
392
      x,
393
      y,
394
      width,
395
      height,
396
      layers,
397
      viewports: this.getViewports({x, y, width, height}),
398
      activateViewport
399
    });
400
    this.stats.get('pickObjects Time').timeEnd();
1×
401
    return infos;
1×
402
  }
403

404
  // Private Methods
405

406
  // canvas, either string, canvas or `null`
407
  _createCanvas(props) {
408
    let canvas = props.canvas;
2×
409

410
    // TODO EventManager should accept element id
411
    if (typeof canvas === 'string') {
Branches [[38, 0]] missed. 2×
412
      /* global document */
UNCOV
413
      canvas = document.getElementById(canvas);
!
UNCOV
414
      assert(canvas);
!
415
    }
416

417
    if (!canvas) {
Branches [[39, 0]] missed. 2×
UNCOV
418
      canvas = document.createElement('canvas');
!
UNCOV
419
      const parent = props.parent || document.body;
Branches [[40, 0], [40, 1]] missed. !
UNCOV
420
      parent.appendChild(canvas);
!
421
    }
422

423
    const {id, style} = props;
2×
424
    canvas.id = id;
2×
425
    Object.assign(canvas.style, style);
2×
426

427
    return canvas;
2×
428
  }
429

430
  // Updates canvas width and/or height, if provided as props
431
  _setCanvasSize(props) {
432
    if (!this.canvas) {
31×
433
      return;
14×
434
    }
435

436
    let {width, height} = props;
17×
437
    // Set size ONLY if props are being provided, otherwise let canvas be layouted freely
438
    if (width || width === 0) {
17×
439
      width = Number.isFinite(width) ? `${width}px` : width;
16×
440
      this.canvas.style.width = width;
16×
441
    }
442
    if (height || height === 0) {
17×
443
      height = Number.isFinite(height) ? `${height}px` : height;
16×
444
      // Note: position==='absolute' required for height 100% to work
445
      this.canvas.style.position = 'absolute';
16×
446
      this.canvas.style.height = height;
16×
447
    }
448
  }
449

450
  // If canvas size has changed, updates
451
  _updateCanvasSize() {
452
    if (this._checkForCanvasSizeChange()) {
21×
453
      const {width, height} = this;
2×
454
      this.viewManager.setProps({width, height});
2×
455
      this.props.onResize({width: this.width, height: this.height});
2×
456
    }
457
  }
458

459
  // If canvas size has changed, reads out the new size and returns true
460
  _checkForCanvasSizeChange() {
461
    const {canvas} = this;
21×
462
    if (!canvas) {
Branches [[49, 0]] missed. 21×
UNCOV
463
      return false;
!
464
    }
465
    // Fallback to width/height when clientWidth/clientHeight are 0 or undefined.
466
    const newWidth = canvas.clientWidth || canvas.width;
21×
467
    const newHeight = canvas.clientHeight || canvas.height;
21×
468
    if (newWidth !== this.width || newHeight !== this.height) {
21×
469
      this.width = newWidth;
2×
470
      this.height = newHeight;
2×
471
      return true;
2×
472
    }
473
    return false;
19×
474
  }
475

476
  _createAnimationLoop(props) {
477
    const {width, height, gl, glOptions, debug, useDevicePixels, autoResizeDrawingBuffer} = props;
10×
478

479
    return new AnimationLoop({
10×
480
      width,
481
      height,
482
      useDevicePixels,
483
      autoResizeDrawingBuffer,
484
      gl,
485
      onCreateContext: opts =>
UNCOV
486
        createGLContext(Object.assign({}, glOptions, opts, {canvas: this.canvas, debug})),
!
487
      onInitialize: this._onRendererInitialized,
488
      onRender: this._onRenderFrame,
489
      onBeforeRender: props.onBeforeRender,
490
      onAfterRender: props.onAfterRender
491
    });
492
  }
493

494
  // Get the most relevant view state: props.viewState, if supplied, shadows internal viewState
495
  // TODO: For backwards compatibility ensure numeric width and height is added to the viewState
496
  _getViewState(props) {
497
    return props.viewState || this.viewState;
39×
498
  }
499

500
  // Get the view descriptor list
501
  _getViews(props) {
502
    // Default to a full screen map view port
503
    let views = props.views || [new MapView({id: 'default-view'})];
39×
504
    views = Array.isArray(views) ? views : [views];
Branches [[56, 1]] missed. 39×
505
    if (views.length && props.controller) {
Branches [[57, 0]] missed. 39×
506
      // Backward compatibility: support controller prop
507
      views[0].props.controller = props.controller;
!
508
    }
509
    return views;
39×
510
  }
511

512
  // The `pointermove` event may fire multiple times in between two animation frames,
513
  // it's a waste of time to run picking without rerender. Instead we save the last pick
514
  // request and only do it once on the next animation frame.
515
  _onPointerMove(event) {
516
    const {_pickRequest} = this;
2×
517
    if (event.type === 'pointerleave') {
2×
518
      _pickRequest.x = -1;
1×
519
      _pickRequest.y = -1;
1×
520
      _pickRequest.radius = 0;
1×
521
    } else if (event.leftButton || event.rightButton) {
Branches [[60, 0]] missed. 1×
522
      // Do not trigger onHover callbacks if mouse button is down.
UNCOV
523
      return;
!
524
    } else {
525
      const pos = event.offsetCenter;
1×
526
      // Do not trigger callbacks when click/hover position is invalid. Doing so will cause a
527
      // assertion error when attempting to unproject the position.
528
      if (!pos) {
Branches [[62, 0]] missed. 1×
UNCOV
529
        return;
!
530
      }
531
      _pickRequest.x = pos.x;
1×
532
      _pickRequest.y = pos.y;
1×
533
      _pickRequest.radius = this.props.pickingRadius;
1×
534
    }
535

536
    if (this.layerManager) {
Branches [[63, 0]] missed. 2×
UNCOV
537
      this.layerManager.context.mousePosition = {x: _pickRequest.x, y: _pickRequest.y};
!
538
    }
539

540
    _pickRequest.callback = this.props.onHover;
2×
541
    _pickRequest.event = event;
2×
542
    _pickRequest.mode = 'hover';
2×
543
  }
544

545
  // Actually run picking
546
  _pickAndCallback() {
547
    const {_pickRequest} = this;
13×
548

549
    if (_pickRequest.mode) {
Branches [[64, 0]] missed. 13×
550
      // perform picking
UNCOV
551
      const {result, emptyInfo} = this.deckPicker.pickObject(
!
552
        Object.assign(
553
          {
554
            layers: this.layerManager.getLayers(),
555
            viewports: this.getViewports(_pickRequest),
556
            activateViewport: this.layerManager.activateViewport,
557
            depth: 1
558
          },
559
          _pickRequest
560
        )
561
      );
562
      if (_pickRequest.callback) {
Branches [[65, 0], [65, 1]] missed. !
UNCOV
563
        const pickedInfo = result.find(info => info.index >= 0) || emptyInfo;
Branches [[66, 0], [66, 1]] missed. !
UNCOV
564
        _pickRequest.callback(pickedInfo, _pickRequest.event);
!
565
      }
UNCOV
566
      _pickRequest.mode = null;
!
567
    }
568
  }
569

570
  _updateCursor() {
571
    if (this.canvas) {
Branches [[67, 1]] missed. 13×
572
      this.canvas.style.cursor = this.props.getCursor(this.interactiveState);
13×
573
    }
574
  }
575

576
  _setGLContext(gl) {
577
    if (this.layerManager) {
Branches [[68, 0]] missed. 8×
UNCOV
578
      return;
!
579
    }
580

581
    // if external context...
582
    if (!this.canvas) {
Branches [[69, 1]] missed. 8×
583
      this.canvas = gl.canvas;
8×
584
      trackContextState(gl, {enable: true, copyState: true});
8×
585
    }
586

587
    setParameters(gl, {
8×
588
      blend: true,
589
      blendFunc: [GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA, GL.ONE, GL.ONE_MINUS_SRC_ALPHA],
590
      polygonOffsetFill: true,
591
      depthTest: true,
592
      depthFunc: GL.LEQUAL
593
    });
594

595
    this.props.onWebGLInitialized(gl);
8×
596

597
    // timeline for transitions
598
    const timeline = new Timeline();
8×
599
    timeline.play();
8×
600
    this.animationLoop.attachTimeline(timeline);
8×
601

602
    this.eventManager = new EventManager(gl.canvas, {
8×
603
      touchAction: this.props.touchAction,
604
      events: {
605
        pointerdown: this._onPointerDown,
606
        pointermove: this._onPointerMove,
607
        pointerleave: this._onPointerMove
608
      }
609
    });
610
    for (const eventType in EVENTS) {
8×
611
      this.eventManager.on(eventType, this._onEvent);
32×
612
    }
613

614
    this.viewManager = new ViewManager({
8×
615
      timeline,
616
      eventManager: this.eventManager,
617
      onViewStateChange: this._onViewStateChange,
618
      onInteractiveStateChange: this._onInteractiveStateChange,
619
      views: this._getViews(this.props),
620
      viewState: this._getViewState(this.props),
621
      width: this.width,
622
      height: this.height
623
    });
624

625
    // viewManager must be initialized before layerManager
626
    // layerManager depends on viewport created by viewManager.
627
    assert(this.viewManager);
8×
628
    const viewport = this.viewManager.getViewports()[0];
8×
629

630
    // Note: avoid React setState due GL animation loop / setState timing issue
631
    this.layerManager = new LayerManager(gl, {
8×
632
      deck: this,
633
      stats: this.stats,
634
      viewport,
635
      timeline
636
    });
637

638
    this.effectManager = new EffectManager();
8×
639

640
    this.deckRenderer = new DeckRenderer(gl);
8×
641

642
    this.deckPicker = new DeckPicker(gl);
8×
643

644
    this.setProps(this.props);
8×
645

646
    this._updateCanvasSize();
8×
647
    this.props.onLoad();
8×
648
  }
649

650
  _drawLayers(redrawReason, renderOptions) {
651
    const {gl} = this.layerManager.context;
7×
652

653
    setParameters(gl, this.props.parameters);
7×
654

655
    this.props.onBeforeRender({gl});
7×
656

657
    const layers = this.layerManager.getLayers();
7×
658
    const activateViewport = this.layerManager.activateViewport;
7×
659

660
    this.deckRenderer.renderLayers(
7×
661
      Object.assign(
662
        {
663
          layers,
664
          viewports: this.viewManager.getViewports(),
665
          activateViewport,
666
          views: this.viewManager.getViews(),
667
          pass: 'screen',
668
          redrawReason,
669
          effects: this.effectManager.getEffects()
670
        },
671
        renderOptions
672
      )
673
    );
674

675
    this.props.onAfterRender({gl});
7×
676
  }
677

678
  // Callbacks
679

680
  _onRendererInitialized({gl}) {
681
    this._setGLContext(gl);
8×
682
  }
683

684
  _onRenderFrame(animationProps) {
685
    this._getFrameStats();
13×
686

687
    // Log perf stats every second
688
    if (this._metricsCounter++ % 60 === 0) {
13×
689
      this._getMetrics();
5×
690
      this.stats.reset();
5×
691
      log.table(3, this.metrics)();
5×
692

693
      // Experimental: report metrics
694
      if (this.props._onMetrics) {
Branches [[71, 0]] missed. 5×
UNCOV
695
        this.props._onMetrics(this.metrics);
!
696
      }
697
    }
698

699
    this._updateCanvasSize();
13×
700

701
    this._updateCursor();
13×
702

703
    // Update layers if needed (e.g. some async prop has loaded)
704
    // Note: This can trigger a redraw
705
    this.layerManager.updateLayers();
13×
706

707
    // Perform picking request if any
708
    this._pickAndCallback();
13×
709

710
    // Redraw if necessary
711
    this.redraw(false);
13×
712

713
    // Update viewport transition if needed
714
    // Note: this can trigger `onViewStateChange`, and affect layers
715
    // We want to defer these changes to the next frame
716
    if (this.viewManager) {
13×
717
      this.viewManager.updateViewStates();
10×
718
    }
719
  }
720

721
  // Callbacks
722

723
  _onViewStateChange(params) {
724
    // Let app know that view state is changing, and give it a chance to change it
UNCOV
725
    const viewState = this.props.onViewStateChange(params) || params.viewState;
Branches [[73, 0], [73, 1]] missed. !
726

727
    // If initialViewState was set on creation, auto track position
UNCOV
728
    if (this.viewState) {
Branches [[74, 0], [74, 1]] missed. !
UNCOV
729
      this.viewState[params.viewId] = viewState;
!
UNCOV
730
      this.viewManager.setProps({viewState});
!
731
    }
732
  }
733

734
  _onInteractiveStateChange({isDragging = false}) {
Branches [[75, 0]] missed.
UNCOV
735
    if (isDragging !== this.interactiveState.isDragging) {
Branches [[76, 0], [76, 1]] missed. !
UNCOV
736
      this.interactiveState.isDragging = isDragging;
!
737
    }
738
  }
739

740
  _onEvent(event) {
UNCOV
741
    const eventOptions = EVENTS[event.type];
!
UNCOV
742
    const pos = event.offsetCenter;
!
743

UNCOV
744
    if (!eventOptions || !pos) {
Branches [[77, 0], [77, 1], [78, 0], [78, 1]] missed. !
UNCOV
745
      return;
!
746
    }
747

748
    // Reuse last picked object
UNCOV
749
    const layers = this.layerManager.getLayers();
!
UNCOV
750
    const info = this.deckPicker.getLastPickedObject(
!
751
      {
752
        x: pos.x,
753
        y: pos.y,
754
        layers,
755
        viewports: this.getViewports(pos)
756
      },
757
      this._lastPointerDownInfo
758
    );
759

UNCOV
760
    const {layer} = info;
!
761
    const layerHandler =
UNCOV
762
      layer && (layer[eventOptions.handler] || layer.props[eventOptions.handler]);
Branches [[79, 0], [79, 1], [79, 2]] missed. !
UNCOV
763
    const rootHandler = this.props[eventOptions.handler];
!
UNCOV
764
    let handled = false;
!
765

UNCOV
766
    if (layerHandler) {
Branches [[80, 0], [80, 1]] missed. !
UNCOV
767
      handled = layerHandler.call(layer, info, event);
!
768
    }
UNCOV
769
    if (!handled && rootHandler) {
Branches [[81, 0], [81, 1], [82, 0], [82, 1]] missed. !
UNCOV
770
      rootHandler(info, event);
!
771
    }
772
  }
773

774
  _onPointerDown(event) {
UNCOV
775
    const pos = event.offsetCenter;
!
UNCOV
776
    this._lastPointerDownInfo = this.pickObject({
!
777
      x: pos.x,
778
      y: pos.y,
779
      radius: this.props.pickingRadius
780
    });
781
  }
782

783
  _getFrameStats() {
784
    const {stats} = this;
13×
785
    stats.get('frameRate').timeEnd();
13×
786
    stats.get('frameRate').timeStart();
13×
787

788
    // Get individual stats from luma.gl so reset works
789
    const animationLoopStats = this.animationLoop.stats;
13×
790
    stats.get('GPU Time').addTime(animationLoopStats.get('GPU Time').lastTiming);
13×
791
    stats.get('CPU Time').addTime(animationLoopStats.get('CPU Time').lastTiming);
13×
792
  }
793

794
  _getMetrics() {
795
    const {metrics, stats} = this;
5×
796
    metrics.fps = stats.get('frameRate').getHz();
5×
797
    metrics.setPropsTime = stats.get('setProps Time').time;
5×
798
    metrics.updateAttributesTime = stats.get('Update Attributes').time;
5×
799
    metrics.framesRedrawn = stats.get('Redraw Count').count;
5×
800
    metrics.pickTime =
5×
801
      stats.get('pickObject Time').time +
802
      stats.get('pickMultipleObjects Time').time +
803
      stats.get('pickObjects Time').time;
804
    metrics.pickCount = stats.get('Pick Count').count;
5×
805

806
    // Luma stats
807
    metrics.gpuTime = stats.get('GPU Time').time;
5×
808
    metrics.cpuTime = stats.get('CPU Time').time;
5×
809
    metrics.gpuTimePerFrame = stats.get('GPU Time').getAverageTime();
5×
810
    metrics.cpuTimePerFrame = stats.get('CPU Time').getAverageTime();
5×
811

812
    const memoryStats = lumaStats.get('Memory Usage');
5×
813
    metrics.bufferMemory = memoryStats.get('Buffer Memory').count;
5×
814
    metrics.textureMemory = memoryStats.get('Texture Memory').count;
5×
815
    metrics.renderbufferMemory = memoryStats.get('Renderbuffer Memory').count;
5×
816
    metrics.gpuMemory = memoryStats.get('GPU Memory').count;
5×
817
  }
818
}
819

820
function isIE11() {
821
  if (typeof window === undefined) {
Branches [[83, 0]] missed. 10×
822
    return false;
!
823
  }
824
  const navigator = window.navigator || {};
Branches [[84, 1]] missed. 10×
825
  const userAgent = navigator.userAgent || '';
Branches [[85, 1]] missed. 10×
826
  return userAgent.indexOf('Trident/') !== -1;
10×
827
}
828

829
Deck.getPropTypes = getPropTypes;
1×
830
Deck.defaultProps = defaultProps;
1×
831

832
// This is used to defeat tree shaking of init.js
833
// https://github.com/uber/deck.gl/issues/3213
834
Deck.VERSION = deckGlobal.VERSION;
1×
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