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

uber / deck.gl / 13779

18 Sep 2019 - 0:00 coverage decreased (-2.9%) to 79.902%
13779

Pull #3623

travis-ci-com

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
beta.2
Pull Request #3623: Bump dependency versions

3405 of 4619 branches covered (73.72%)

Branch coverage included in aggregate %.

7031 of 8442 relevant lines covered (83.29%)

5687.45 hits per line

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

76.42
/modules/core/src/lib/deck.js
1
// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
31×
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 Tooltip from './tooltip';
29
import log from '../utils/log';
30
import deckGlobal from './init';
31

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

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

48
function noop() {}
49

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

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

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

67
    // GL settings
68
    gl: PropTypes.object,
69
    glOptions: PropTypes.object,
70
    parameters: PropTypes.object,
71
    pickingRadius: PropTypes.number,
72
    useDevicePixels: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]),
73
    touchAction: PropTypes.string,
74

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

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

87
    // Experimental props
88

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

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

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

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

119
  getCursor,
120

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

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

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

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

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

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

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

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

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

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

192
    this.setProps(props);
11×
193

194
    this.animationLoop.start();
11×
195
  }
196

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

202
    if (this.layerManager) {
11×
203
      this.layerManager.finalize();
9×
204
      this.layerManager = null;
9×
205
    }
206

207
    if (this.viewManager) {
11×
208
      this.viewManager.finalize();
9×
209
      this.viewManager = null;
9×
210
    }
211

212
    if (this.effectManager) {
11×
213
      this.effectManager.finalize();
9×
214
      this.effectManager = null;
9×
215
    }
216

217
    if (this.deckRenderer) {
11×
218
      this.deckRenderer.finalize();
9×
219
      this.deckRenderer = null;
9×
220
    }
221

222
    if (this.eventManager) {
11×
223
      this.eventManager.destroy();
9×
224
    }
225

226
    if (this.tooltip) {
11×
227
      this.tooltip.remove();
9×
228
      this.tooltip = null;
9×
229
    }
230

231
    if (!this.props.canvas && !this.props.gl && this.canvas) {
Branches [[11, 0], [12, 2]] missed. 11×
232
      // remove internally created canvas
UNCOV
233
      this.canvas.parentElement.removeChild(this.canvas);
!
UNCOV
234
      this.canvas = null;
!
235
    }
236
  }
237

238
  setProps(props) {
239
    this.stats.get('setProps Time').timeStart();
33×
240

241
    if ('onLayerHover' in props) {
Branches [[13, 0]] missed. 33×
UNCOV
242
      log.removed('onLayerHover', 'onHover')();
!
243
    }
244
    if ('onLayerClick' in props) {
Branches [[14, 0]] missed. 33×
UNCOV
245
      log.removed('onLayerClick', 'onClick')();
!
246
    }
247

248
    props = Object.assign({}, this.props, props);
33×
249
    this.props = props;
33×
250

251
    // Update CSS size of canvas
252
    this._setCanvasSize(props);
33×
253

254
    // We need to overwrite CSS style width and height with actual, numeric values
255
    const newProps = Object.assign({}, props, {
33×
256
      views: this._getViews(this.props),
257
      width: this.width,
258
      height: this.height
259
    });
260

261
    const viewState = this._getViewState(props);
33×
262
    if (viewState) {
Branches [[15, 1]] missed. 33×
263
      newProps.viewState = viewState;
33×
264
    }
265

266
    // Update view manager props
267
    if (this.viewManager) {
33×
268
      this.viewManager.setProps(newProps);
10×
269
    }
270

271
    // Update layer manager props (but not size)
272
    if (this.layerManager) {
33×
273
      this.layerManager.setProps(newProps);
10×
274
    }
275

276
    if (this.effectManager) {
33×
277
      this.effectManager.setProps(newProps);
10×
278
    }
279

280
    // Update animation loop
281
    if (this.animationLoop) {
Branches [[19, 1]] missed. 33×
282
      this.animationLoop.setProps(newProps);
33×
283
    }
284

285
    if (this.deckRenderer) {
33×
286
      this.deckRenderer.setProps(newProps);
10×
287
    }
288

289
    if (this.deckPicker) {
33×
290
      this.deckPicker.setProps(newProps);
10×
291
    }
292

293
    this.stats.get('setProps Time').timeEnd();
33×
294
  }
295

296
  // Public API
297
  // Check if a redraw is needed
298
  // Returns `false` or a string summarizing the redraw reason
299
  // opts.clearRedrawFlags (Boolean) - clear the redraw flag. Default `true`
300
  needsRedraw(opts = {clearRedrawFlags: false}) {
Branches [[22, 0]] missed.
301
    if (this.props._animate) {
Branches [[23, 0]] missed. 14×
UNCOV
302
      return 'Deck._animate';
!
303
    }
304

305
    let redraw = this._needsRedraw;
14×
306

307
    if (opts.clearRedrawFlags) {
Branches [[24, 1]] missed. 14×
308
      this._needsRedraw = false;
14×
309
    }
310

311
    const viewManagerNeedsRedraw = this.viewManager.needsRedraw(opts);
14×
312
    const layerManagerNeedsRedraw = this.layerManager.needsRedraw(opts);
14×
313
    const effectManagerNeedsRedraw = this.effectManager.needsRedraw(opts);
14×
314
    const deckRendererNeedsRedraw = this.deckRenderer.needsRedraw(opts);
14×
315

316
    redraw =
14×
317
      redraw ||
318
      viewManagerNeedsRedraw ||
319
      layerManagerNeedsRedraw ||
320
      effectManagerNeedsRedraw ||
321
      deckRendererNeedsRedraw;
322
    return redraw;
14×
323
  }
324

325
  redraw(force) {
326
    if (!this.layerManager) {
16×
327
      // Not yet initialized
328
      return;
2×
329
    }
330
    // If force is falsy, check if we need to redraw
331
    const redrawReason = force || this.needsRedraw({clearRedrawFlags: true});
14×
332

333
    if (!redrawReason) {
14×
334
      return;
6×
335
    }
336

337
    this.stats.get('Redraw Count').incrementCount();
8×
338
    if (this.props._customRender) {
8×
339
      this.props._customRender(redrawReason);
1×
340
    } else {
341
      this._drawLayers(redrawReason);
7×
342
    }
343
  }
344

345
  getViews() {
UNCOV
346
    return this.viewManager.views;
!
347
  }
348

349
  // Get a set of viewports for a given width and height
350
  getViewports(rect) {
351
    return this.viewManager.getViewports(rect);
4×
352
  }
353

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

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

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

410
  // Private Methods
411

412
  // canvas, either string, canvas or `null`
413
  _createCanvas(props) {
414
    let canvas = props.canvas;
2×
415

416
    // TODO EventManager should accept element id
417
    if (typeof canvas === 'string') {
Branches [[39, 0]] missed. 2×
418
      /* global document */
UNCOV
419
      canvas = document.getElementById(canvas);
!
UNCOV
420
      assert(canvas);
!
421
    }
422

423
    if (!canvas) {
Branches [[40, 0]] missed. 2×
UNCOV
424
      canvas = document.createElement('canvas');
!
UNCOV
425
      const parent = props.parent || document.body;
Branches [[41, 0], [41, 1]] missed. !
UNCOV
426
      parent.appendChild(canvas);
!
427
    }
428

429
    const {id, style} = props;
2×
430
    canvas.id = id;
2×
431
    Object.assign(canvas.style, style);
2×
432

433
    return canvas;
2×
434
  }
435

436
  // Updates canvas width and/or height, if provided as props
437
  _setCanvasSize(props) {
438
    if (!this.canvas) {
33×
439
      return;
15×
440
    }
441

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

456
  // If canvas size has changed, updates
457
  _updateCanvasSize() {
458
    if (this._checkForCanvasSizeChange()) {
23×
459
      const {width, height} = this;
9×
460
      this.viewManager.setProps({width, height});
9×
461
      this.props.onResize({width: this.width, height: this.height});
9×
462
    }
463
  }
464

465
  // If canvas size has changed, reads out the new size and returns true
466
  _checkForCanvasSizeChange() {
467
    const {canvas} = this;
23×
468
    if (!canvas) {
Branches [[50, 0]] missed. 23×
UNCOV
469
      return false;
!
470
    }
471
    // Fallback to width/height when clientWidth/clientHeight are 0 or undefined.
472
    const newWidth = canvas.clientWidth || canvas.width;
23×
473
    const newHeight = canvas.clientHeight || canvas.height;
23×
474
    if (newWidth !== this.width || newHeight !== this.height) {
23×
475
      this.width = newWidth;
9×
476
      this.height = newHeight;
9×
477
      return true;
9×
478
    }
479
    return false;
14×
480
  }
481

482
  _createAnimationLoop(props) {
483
    const {width, height, gl, glOptions, debug, useDevicePixels, autoResizeDrawingBuffer} = props;
11×
484

485
    return new AnimationLoop({
11×
486
      width,
487
      height,
488
      useDevicePixels,
489
      autoResizeDrawingBuffer,
490
      gl,
491
      onCreateContext: opts =>
UNCOV
492
        createGLContext(Object.assign({}, glOptions, opts, {canvas: this.canvas, debug})),
!
493
      onInitialize: this._onRendererInitialized,
494
      onRender: this._onRenderFrame,
495
      onBeforeRender: props.onBeforeRender,
496
      onAfterRender: props.onAfterRender
497
    });
498
  }
499

500
  // Get the most relevant view state: props.viewState, if supplied, shadows internal viewState
501
  // TODO: For backwards compatibility ensure numeric width and height is added to the viewState
502
  _getViewState(props) {
503
    return props.viewState || this.viewState;
42×
504
  }
505

506
  // Get the view descriptor list
507
  _getViews(props) {
508
    // Default to a full screen map view port
509
    let views = props.views || [new MapView({id: 'default-view'})];
42×
510
    views = Array.isArray(views) ? views : [views];
Branches [[57, 1]] missed. 42×
511
    if (views.length && props.controller) {
42×
512
      // Backward compatibility: support controller prop
513
      views[0].props.controller = props.controller;
3×
514
    }
515
    return views;
42×
516
  }
517

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

542
    if (this.layerManager) {
Branches [[64, 0]] missed. 2×
UNCOV
543
      this.layerManager.context.mousePosition = {x: _pickRequest.x, y: _pickRequest.y};
!
544
    }
545

546
    _pickRequest.callback = this.props.onHover;
2×
547
    _pickRequest.event = event;
2×
548
    _pickRequest.mode = 'hover';
2×
549
  }
550

551
  // Actually run picking
552
  _pickAndCallback() {
553
    const {_pickRequest} = this;
14×
554

555
    if (_pickRequest.mode) {
Branches [[65, 0]] missed. 14×
556
      // perform picking
UNCOV
557
      const {result, emptyInfo} = this.deckPicker.pickObject(
!
558
        Object.assign(
559
          {
560
            layers: this.layerManager.getLayers(),
561
            viewports: this.getViewports(_pickRequest),
562
            activateViewport: this.layerManager.activateViewport,
563
            depth: 1
564
          },
565
          _pickRequest
566
        )
567
      );
UNCOV
568
      const shouldGenerateInfo = _pickRequest.callback || this.props.getTooltip;
Branches [[66, 0], [66, 1]] missed. !
UNCOV
569
      const pickedInfo = shouldGenerateInfo && (result.find(info => info.index >= 0) || emptyInfo);
Branches [[67, 0], [67, 1], [67, 2]] missed. !
UNCOV
570
      if (this.props.getTooltip) {
Branches [[68, 0], [68, 1]] missed. !
UNCOV
571
        const displayInfo = this.props.getTooltip(pickedInfo);
!
UNCOV
572
        this.tooltip.setTooltip(displayInfo, pickedInfo.x, pickedInfo.y);
!
573
      }
UNCOV
574
      if (_pickRequest.callback) {
Branches [[69, 0], [69, 1]] missed. !
UNCOV
575
        _pickRequest.callback(pickedInfo, _pickRequest.event);
!
576
      }
UNCOV
577
      _pickRequest.mode = null;
!
578
    }
579
  }
580

581
  _updateCursor() {
582
    if (this.canvas) {
Branches [[70, 1]] missed. 14×
583
      this.canvas.style.cursor = this.props.getCursor(this.interactiveState);
14×
584
    }
585
  }
586

587
  _setGLContext(gl) {
588
    if (this.layerManager) {
Branches [[71, 0]] missed. 9×
589
      return;
!
590
    }
591

592
    // if external context...
593
    if (!this.canvas) {
Branches [[72, 1]] missed. 9×
594
      this.canvas = gl.canvas;
9×
595
      trackContextState(gl, {enable: true, copyState: true});
9×
596
    }
597

598
    this.tooltip = new Tooltip(this.canvas);
9×
599

600
    setParameters(gl, {
9×
601
      blend: true,
602
      blendFunc: [GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA, GL.ONE, GL.ONE_MINUS_SRC_ALPHA],
603
      polygonOffsetFill: true,
604
      depthTest: true,
605
      depthFunc: GL.LEQUAL
606
    });
607

608
    this.props.onWebGLInitialized(gl);
9×
609

610
    // timeline for transitions
611
    const timeline = new Timeline();
9×
612
    timeline.play();
9×
613
    this.animationLoop.attachTimeline(timeline);
9×
614

615
    this.eventManager = new EventManager(gl.canvas, {
9×
616
      touchAction: this.props.touchAction,
617
      events: {
618
        pointerdown: this._onPointerDown,
619
        pointermove: this._onPointerMove,
620
        pointerleave: this._onPointerMove
621
      }
622
    });
623
    for (const eventType in EVENTS) {
9×
624
      this.eventManager.on(eventType, this._onEvent);
36×
625
    }
626

627
    this.viewManager = new ViewManager({
9×
628
      timeline,
629
      eventManager: this.eventManager,
630
      onViewStateChange: this._onViewStateChange,
631
      onInteractiveStateChange: this._onInteractiveStateChange,
632
      views: this._getViews(this.props),
633
      viewState: this._getViewState(this.props),
634
      width: this.width,
635
      height: this.height
636
    });
637

638
    // viewManager must be initialized before layerManager
639
    // layerManager depends on viewport created by viewManager.
640
    assert(this.viewManager);
9×
641
    const viewport = this.viewManager.getViewports()[0];
9×
642

643
    // Note: avoid React setState due GL animation loop / setState timing issue
644
    this.layerManager = new LayerManager(gl, {
9×
645
      deck: this,
646
      stats: this.stats,
647
      viewport,
648
      timeline
649
    });
650

651
    this.effectManager = new EffectManager();
9×
652

653
    this.deckRenderer = new DeckRenderer(gl);
9×
654

655
    this.deckPicker = new DeckPicker(gl);
9×
656

657
    this.setProps(this.props);
9×
658

659
    this._updateCanvasSize();
9×
660
    this.props.onLoad();
9×
661
  }
662

663
  _drawLayers(redrawReason, renderOptions) {
664
    const {gl} = this.layerManager.context;
8×
665

666
    setParameters(gl, this.props.parameters);
8×
667

668
    this.props.onBeforeRender({gl});
8×
669

670
    const layers = this.layerManager.getLayers();
8×
671
    const activateViewport = this.layerManager.activateViewport;
8×
672

673
    this.deckRenderer.renderLayers(
8×
674
      Object.assign(
675
        {
676
          layers,
677
          viewports: this.viewManager.getViewports(),
678
          activateViewport,
679
          views: this.viewManager.getViews(),
680
          pass: 'screen',
681
          redrawReason,
682
          effects: this.effectManager.getEffects()
683
        },
684
        renderOptions
685
      )
686
    );
687

688
    this.props.onAfterRender({gl});
8×
689
  }
690

691
  // Callbacks
692

693
  _onRendererInitialized({gl}) {
694
    this._setGLContext(gl);
9×
695
  }
696

697
  _onRenderFrame(animationProps) {
698
    this._getFrameStats();
14×
699

700
    // Log perf stats every second
701
    if (this._metricsCounter++ % 60 === 0) {
14×
702
      this._getMetrics();
6×
703
      this.stats.reset();
6×
704
      log.table(3, this.metrics)();
6×
705

706
      // Experimental: report metrics
707
      if (this.props._onMetrics) {
Branches [[74, 0]] missed. 6×
UNCOV
708
        this.props._onMetrics(this.metrics);
!
709
      }
710
    }
711

712
    this._updateCanvasSize();
14×
713

714
    this._updateCursor();
14×
715

716
    // Update layers if needed (e.g. some async prop has loaded)
717
    // Note: This can trigger a redraw
718
    this.layerManager.updateLayers();
14×
719

720
    // Perform picking request if any
721
    this._pickAndCallback();
14×
722

723
    // Redraw if necessary
724
    this.redraw(false);
14×
725

726
    // Update viewport transition if needed
727
    // Note: this can trigger `onViewStateChange`, and affect layers
728
    // We want to defer these changes to the next frame
729
    if (this.viewManager) {
14×
730
      this.viewManager.updateViewStates();
10×
731
    }
732
  }
733

734
  // Callbacks
735

736
  _onViewStateChange(params) {
737
    // Let app know that view state is changing, and give it a chance to change it
UNCOV
738
    const viewState = this.props.onViewStateChange(params) || params.viewState;
Branches [[76, 0], [76, 1]] missed. !
739

740
    // If initialViewState was set on creation, auto track position
UNCOV
741
    if (this.viewState) {
Branches [[77, 0], [77, 1]] missed. !
UNCOV
742
      this.viewState[params.viewId] = viewState;
!
UNCOV
743
      this.viewManager.setProps({viewState});
!
744
    }
745
  }
746

747
  _onInteractiveStateChange({isDragging = false}) {
Branches [[78, 0]] missed.
UNCOV
748
    if (isDragging !== this.interactiveState.isDragging) {
Branches [[79, 0], [79, 1]] missed. !
UNCOV
749
      this.interactiveState.isDragging = isDragging;
!
750
    }
751
  }
752

753
  _onEvent(event) {
UNCOV
754
    const eventOptions = EVENTS[event.type];
!
UNCOV
755
    const pos = event.offsetCenter;
!
756

UNCOV
757
    if (!eventOptions || !pos) {
Branches [[80, 0], [80, 1], [81, 0], [81, 1]] missed. !
UNCOV
758
      return;
!
759
    }
760

761
    // Reuse last picked object
UNCOV
762
    const layers = this.layerManager.getLayers();
!
UNCOV
763
    const info = this.deckPicker.getLastPickedObject(
!
764
      {
765
        x: pos.x,
766
        y: pos.y,
767
        layers,
768
        viewports: this.getViewports(pos)
769
      },
770
      this._lastPointerDownInfo
771
    );
772

UNCOV
773
    const {layer} = info;
!
774
    const layerHandler =
UNCOV
775
      layer && (layer[eventOptions.handler] || layer.props[eventOptions.handler]);
Branches [[82, 0], [82, 1], [82, 2]] missed. !
UNCOV
776
    const rootHandler = this.props[eventOptions.handler];
!
UNCOV
777
    let handled = false;
!
778

UNCOV
779
    if (layerHandler) {
Branches [[83, 0], [83, 1]] missed. !
UNCOV
780
      handled = layerHandler.call(layer, info, event);
!
781
    }
UNCOV
782
    if (!handled && rootHandler) {
Branches [[84, 0], [84, 1], [85, 0], [85, 1]] missed. !
UNCOV
783
      rootHandler(info, event);
!
784
    }
785
  }
786

787
  _onPointerDown(event) {
UNCOV
788
    const pos = event.offsetCenter;
!
UNCOV
789
    this._lastPointerDownInfo = this.pickObject({
!
790
      x: pos.x,
791
      y: pos.y,
792
      radius: this.props.pickingRadius
793
    });
794
  }
795

796
  _getFrameStats() {
797
    const {stats} = this;
14×
798
    stats.get('frameRate').timeEnd();
14×
799
    stats.get('frameRate').timeStart();
14×
800

801
    // Get individual stats from luma.gl so reset works
802
    const animationLoopStats = this.animationLoop.stats;
14×
803
    stats.get('GPU Time').addTime(animationLoopStats.get('GPU Time').lastTiming);
14×
804
    stats.get('CPU Time').addTime(animationLoopStats.get('CPU Time').lastTiming);
14×
805
  }
806

807
  _getMetrics() {
808
    const {metrics, stats} = this;
6×
809
    metrics.fps = stats.get('frameRate').getHz();
6×
810
    metrics.setPropsTime = stats.get('setProps Time').time;
6×
811
    metrics.updateAttributesTime = stats.get('Update Attributes').time;
6×
812
    metrics.framesRedrawn = stats.get('Redraw Count').count;
6×
813
    metrics.pickTime =
6×
814
      stats.get('pickObject Time').time +
815
      stats.get('pickMultipleObjects Time').time +
816
      stats.get('pickObjects Time').time;
817
    metrics.pickCount = stats.get('Pick Count').count;
6×
818

819
    // Luma stats
820
    metrics.gpuTime = stats.get('GPU Time').time;
6×
821
    metrics.cpuTime = stats.get('CPU Time').time;
6×
822
    metrics.gpuTimePerFrame = stats.get('GPU Time').getAverageTime();
6×
823
    metrics.cpuTimePerFrame = stats.get('CPU Time').getAverageTime();
6×
824

825
    const memoryStats = lumaStats.get('Memory Usage');
6×
826
    metrics.bufferMemory = memoryStats.get('Buffer Memory').count;
6×
827
    metrics.textureMemory = memoryStats.get('Texture Memory').count;
6×
828
    metrics.renderbufferMemory = memoryStats.get('Renderbuffer Memory').count;
6×
829
    metrics.gpuMemory = memoryStats.get('GPU Memory').count;
6×
830
  }
831
}
832

833
function isIE11() {
834
  if (typeof window === undefined) {
Branches [[86, 0]] missed. 11×
835
    return false;
!
836
  }
837
  const navigator = window.navigator || {};
Branches [[87, 1]] missed. 11×
838
  const userAgent = navigator.userAgent || '';
Branches [[88, 1]] missed. 11×
839
  return userAgent.indexOf('Trident/') !== -1;
11×
840
}
841

842
Deck.getPropTypes = getPropTypes;
1×
843
Deck.defaultProps = defaultProps;
1×
844

845
// This is used to defeat tree shaking of init.js
846
// https://github.com/uber/deck.gl/issues/3213
847
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