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

uber / deck.gl / 13758

17 Sep 2019 - 21:06 coverage increased (+2.9%) to 82.762%
13758

Pull #3621

travis-ci-com

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
fix CI
Pull Request #3621: Support spring transition in UniformTransitionManager

3406 of 4621 branches covered (73.71%)

Branch coverage included in aggregate %.

59 of 63 new or added lines in 6 files covered. (93.65%)

499 existing lines in 85 files now uncovered.

7200 of 8194 relevant lines covered (87.87%)

4274.03 hits per line

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

93.48
/modules/aggregation-layers/src/contour-layer/contour-layer.js
1
// Copyright (c) 2015 - 2018 Uber Technologies, Inc.
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 {equals} from 'math.gl';
22
import {CompositeLayer} from '@deck.gl/core';
23
import {LineLayer, SolidPolygonLayer} from '@deck.gl/layers';
24
import {generateContours} from './contour-utils';
25

26
import GPUGridAggregator from '../utils/gpu-grid-aggregation/gpu-grid-aggregator';
27
import {pointToDensityGridData} from '../utils/gpu-grid-aggregation/grid-aggregation-utils';
28

29
const DEFAULT_COLOR = [255, 255, 255, 255];
1×
30
const DEFAULT_STROKE_WIDTH = 1;
10×
31
const DEFAULT_THRESHOLD = 1;
1×
32

33
const defaultProps = {
1×
34
  // grid aggregation
35
  cellSize: {type: 'number', min: 1, max: 1000, value: 1000},
36
  getPosition: {type: 'accessor', value: x => x.position},
1×
37
  getWeight: {type: 'accessor', value: x => 1},
1×
38

39
  // contour lines
40
  contours: [{threshold: DEFAULT_THRESHOLD}],
41

42
  fp64: false,
43
  zOffset: 0.005
44
};
45

46
export default class ContourLayer extends CompositeLayer {
47
  initializeState() {
48
    const {gl} = this.context;
1×
49
    const options = {
1×
50
      id: `${this.id}-gpu-aggregator`
51
    };
52
    this.state = {
1×
53
      contourData: {},
54
      gridAggregator: new GPUGridAggregator(gl, options),
55
      colorTrigger: 0,
56
      strokeWidthTrigger: 0
57
    };
58
  }
59

60
  updateState({oldProps, props, changeFlags}) {
61
    let dataChanged = false;
1×
62
    let contoursChanged = false;
2×
63
    const aggregationFlags = this._getAggregationFlags({oldProps, props, changeFlags});
1×
64
    if (aggregationFlags) {
1×
65
      dataChanged = true;
1×
66
      // Clear countsData cache
67
      this.setState({countsData: null});
2×
68
      this._aggregateData(aggregationFlags);
1×
69
    }
70

71
    if (this._shouldRebuildContours({oldProps, props})) {
1×
72
      contoursChanged = true;
1×
73
      this._updateThresholdData(props);
1×
74
    }
75

UNCOV
76
    if (dataChanged || contoursChanged) {
!
77
      this._generateContours();
5,055×
78
    } else {
79
      // data for sublayers not changed check if color or strokeWidth need to be updated
80
      this._updateSubLayerTriggers(oldProps, props);
3×
81
    }
82
  }
83

84
  finalizeState() {
85
    super.finalizeState();
3×
86
    this.state.gridAggregator.delete();
3×
87
  }
88

89
  renderLayers() {
90
    const {contourSegments, contourPolygons} = this.state.contourData;
14×
91
    const hasIsolines = contourSegments && contourSegments.length > 0;
14×
92
    const hasIsobands = contourPolygons && contourPolygons.length > 0;
14×
93

94
    const lineLayer = hasIsolines && new LineLayer(this._getLineLayerProps());
14×
95
    const solidPolygonLayer =
96
      hasIsobands && new SolidPolygonLayer(this._getSolidPolygonLayerProps());
9×
97
    return [lineLayer, solidPolygonLayer];
9×
98
  }
99

100
  // Private
101

102
  _aggregateData(aggregationFlags) {
103
    const {
104
      data,
105
      cellSize: cellSizeMeters,
106
      getPosition,
107
      getWeight,
108
      gpuAggregation,
109
      fp64,
110
      coordinateSystem
111
    } = this.props;
9×
112
    const {weights, gridSize, gridOrigin, cellSize, boundingBox} = pointToDensityGridData({
14×
113
      data,
114
      cellSizeMeters,
115
      getPosition,
116
      weightParams: {count: {getWeight}},
117
      gpuAggregation,
118
      gpuGridAggregator: this.state.gridAggregator,
119
      fp64,
120
      coordinateSystem,
121
      viewport: this.context.viewport,
122
      boundingBox: this.state.boundingBox, // avoid parsing data when it is not changed.
123
      aggregationFlags
124
    });
125

126
    this.setState({
6×
127
      countsData: weights.count.aggregationData,
128
      countsBuffer: weights.count.aggregationBuffer,
129
      gridSize,
130
      gridOrigin,
131
      cellSize,
132
      boundingBox
133
    });
134
  }
135

136
  _generateContours() {
137
    const {gridSize, gridOrigin, cellSize, thresholdData} = this.state;
6×
138
    let {countsData} = this.state;
14×
139
    if (!countsData) {
Branches [[8, 0]] missed. 12×
140
      const {countsBuffer} = this.state;
2×
141
      countsData = countsBuffer.getData();
2×
142
      this.setState({countsData});
2×
143
    }
144

145
    const {cellWeights} = GPUGridAggregator.getCellData({countsData});
15×
146
    // const thresholds = this.props.contours.map(x => x.threshold);
147
    const contourData = generateContours({
15×
148
      thresholdData,
149
      cellWeights,
150
      gridSize,
151
      gridOrigin,
152
      cellSize
153
    });
154

155
    // contourData contains both iso-lines and iso-bands if requested.
156
    this.setState({contourData});
15×
157
  }
158

159
  _getAggregationFlags({oldProps, props, changeFlags}) {
160
    let aggregationFlags = null;
15×
161
    if (
15×
162
      changeFlags.dataChanged ||
Branches [[10, 3], [10, 4]] missed.
163
      oldProps.gpuAggregation !== props.gpuAggregation ||
164
      (changeFlags.updateTriggersChanged &&
165
        (changeFlags.updateTriggersChanged.all || changeFlags.updateTriggersChanged.getPosition))
166
    ) {
167
      aggregationFlags = Object.assign({}, aggregationFlags, {dataChanged: true});
15×
168
    }
169
    if (oldProps.cellSize !== props.cellSize) {
9×
170
      aggregationFlags = Object.assign({}, aggregationFlags, {cellSizeChanged: true});
9×
171
    }
172
    return aggregationFlags;
9×
173
  }
174

175
  _getLineLayerProps() {
176
    const {colorTrigger, strokeWidthTrigger} = this.state;
12×
177

178
    return this.getSubLayerProps({
12×
179
      id: 'contour-line-layer',
180
      data: this.state.contourData.contourSegments,
181
      getSourcePosition: d => d.start,
12×
UNCOV
182
      getTargetPosition: d => d.end,
!
183
      getColor: this._onGetSublayerColor.bind(this),
184
      getWidth: this._onGetSublayerStrokeWidth.bind(this),
185
      widthUnits: 'pixels',
186
      updateTriggers: {
187
        getColor: colorTrigger,
188
        getWidth: strokeWidthTrigger
189
      }
190
    });
191
  }
192

193
  _getSolidPolygonLayerProps() {
UNCOV
194
    const {colorTrigger} = this.state;
!
195

UNCOV
196
    return this.getSubLayerProps({
!
197
      id: 'contour-solid-polygon-layer',
198
      data: this.state.contourData.contourPolygons,
199
      getPolygon: d => d.vertices,
12×
200
      getFillColor: this._onGetSublayerColor.bind(this),
201
      updateTriggers: {
202
        getFillColor: colorTrigger
203
      }
204
    });
205
  }
206

207
  _onGetSublayerColor(element) {
208
    // element is either a line segment or polygon
209
    const {contours} = this.props;
12×
210
    let color = DEFAULT_COLOR;
12×
211
    contours.forEach(data => {
14×
212
      if (equals(data.threshold, element.threshold)) {
14×
213
        color = data.color || DEFAULT_COLOR;
8×
214
      }
215
    });
216
    return color;
14×
217
  }
218

219
  _onGetSublayerStrokeWidth(segment) {
220
    const {contours} = this.props;
4×
221
    let strokeWidth = DEFAULT_STROKE_WIDTH;
14×
222
    // Linearly searches the contours, but there should only be few contours
223
    contours.some(contour => {
14×
224
      if (contour.threshold === segment.threshold) {
14×
225
        strokeWidth = contour.strokeWidth || DEFAULT_STROKE_WIDTH;
4,934×
226
        return true;
4,934×
227
      }
228
      return false;
7×
229
    });
230
    return strokeWidth;
7×
231
  }
232

233
  _shouldRebuildContours({oldProps, props}) {
234
    if (
3,094×
235
      !oldProps.contours ||
236
      !oldProps.zOffset ||
237
      oldProps.contours.length !== props.contours.length ||
238
      oldProps.zOffset !== props.zOffset
239
    ) {
240
      return true;
6,881×
241
    }
242
    const oldThresholds = oldProps.contours.map(x => x.threshold);
6,881×
243
    const thresholds = props.contours.map(x => x.threshold);
19,318×
244

245
    return thresholds.some((_, i) => !equals(thresholds[i], oldThresholds[i]));
6,881×
246
  }
247

248
  _updateSubLayerTriggers(oldProps, props) {
249
    if (oldProps && oldProps.contours && props && props.contours) {
Branches [[18, 1]] missed. 4,934×
250
      if (props.contours.some((contour, i) => contour.color !== oldProps.contours[i].color)) {
6,234×
251
        this.state.colorTrigger++;
4,934×
252
      }
253
      if (
Branches [[21, 0]] missed. 4,934×
254
        props.contours.some(
255
          (contour, i) => contour.strokeWidth !== oldProps.contours[i].strokeWidth
1,300×
256
        )
257
      ) {
258
        this.state.strokeWidthTrigger++;
4,934×
259
      }
260
    }
261
  }
262

263
  _updateThresholdData(props) {
264
    const thresholdData = props.contours.map((x, index) => {
14×
265
      return {
5×
266
        threshold: x.threshold,
267
        zIndex: x.zIndex || index,
268
        zOffset: props.zOffset
269
      };
270
    });
271
    this.setState({thresholdData});
9×
272
  }
273
}
274

275
ContourLayer.layerName = 'ContourLayer';
13×
276
ContourLayer.defaultProps = defaultProps;
9×
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