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

uber / deck.gl / 13873

19 Sep 2019 - 20:02 coverage increased (+2.8%) to 82.702%
13873

Pull #3639

travis-ci-com

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
Update
Pull Request #3639: Set default pydeck notebook width to 700px

3398 of 4611 branches covered (73.69%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

488 existing lines in 85 files now uncovered.

7192 of 8194 relevant lines covered (87.77%)

4273.96 hits per line

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

91.67
/modules/layers/src/icon-layer/icon-layer.js
1
// Copyright (c) 2015 - 2017 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
import {Layer} from '@deck.gl/core';
21
import GL from '@luma.gl/constants';
22
import {Model, Geometry} from '@luma.gl/core';
23

24
import vs from './icon-layer-vertex.glsl';
25
import fs from './icon-layer-fragment.glsl';
26
import IconManager from './icon-manager';
27

28
const DEFAULT_COLOR = [0, 0, 0, 255];
1×
29
/*
30
 * @param {object} props
31
 * @param {Texture2D | string} props.iconAtlas - atlas image url or texture
32
 * @param {object} props.iconMapping - icon names mapped to icon definitions
33
 * @param {object} props.iconMapping[icon_name].x - x position of icon on the atlas image
34
 * @param {object} props.iconMapping[icon_name].y - y position of icon on the atlas image
35
 * @param {object} props.iconMapping[icon_name].width - width of icon on the atlas image
36
 * @param {object} props.iconMapping[icon_name].height - height of icon on the atlas image
37
 * @param {object} props.iconMapping[icon_name].anchorX - x anchor of icon on the atlas image,
38
 *   default to width / 2
39
 * @param {object} props.iconMapping[icon_name].anchorY - y anchor of icon on the atlas image,
40
 *   default to height / 2
41
 * @param {object} props.iconMapping[icon_name].mask - whether icon is treated as a transparency
42
 *   mask. If true, user defined color is applied. If false, original color from the image is
43
 *   applied. Default to false.
44
 * @param {number} props.size - icon size in pixels
45
 * @param {func} props.getPosition - returns anchor position of the icon, in [lng, lat, z]
46
 * @param {func} props.getIcon - returns icon name as a string
47
 * @param {func} props.getSize - returns icon size multiplier as a number
48
 * @param {func} props.getColor - returns color of the icon in [r, g, b, a]. Only works on icons
49
 *   with mask: true.
50
 * @param {func} props.getAngle - returns rotating angle (in degree) of the icon.
51
 */
52
const defaultProps = {
14×
53
  iconAtlas: {type: 'object', value: null, async: true},
54
  iconMapping: {type: 'object', value: {}, async: true},
55
  sizeScale: {type: 'number', value: 1, min: 0},
56
  billboard: true,
57
  sizeUnits: 'pixels',
58
  sizeMinPixels: {type: 'number', min: 0, value: 0}, //  min point radius in pixels
59
  sizeMaxPixels: {type: 'number', min: 0, value: Number.MAX_SAFE_INTEGER}, // max point radius in pixels
60
  alphaCutoff: {type: 'number', value: 0.05, min: 0, max: 1},
61

62
  getPosition: {type: 'accessor', value: x => x.position},
1×
63
  getIcon: {type: 'accessor', value: x => x.icon},
1×
64
  getColor: {type: 'accessor', value: DEFAULT_COLOR},
65
  getSize: {type: 'accessor', value: 1},
66
  getAngle: {type: 'accessor', value: 0}
67
};
68

69
export default class IconLayer extends Layer {
70
  getShaders() {
71
    return super.getShaders({vs, fs, modules: ['project32', 'picking']});
1×
72
  }
73

74
  initializeState() {
75
    this.state = {
1×
76
      iconManager: new IconManager(this.context.gl, {onUpdate: () => this._onUpdate()})
1×
77
    };
78

79
    const attributeManager = this.getAttributeManager();
1×
80
    /* eslint-disable max-len */
81
    attributeManager.addInstanced({
1×
82
      instancePositions: {
83
        size: 3,
84
        type: this.use64bitPositions() ? GL.DOUBLE : GL.FLOAT,
Branches [[0, 1]] missed.
85
        transition: true,
86
        accessor: 'getPosition'
87
      },
88
      instanceSizes: {
89
        size: 1,
90
        transition: true,
91
        accessor: 'getSize',
92
        defaultValue: 1
93
      },
94
      instanceOffsets: {size: 2, accessor: 'getIcon', transform: this.getInstanceOffset},
95
      instanceIconFrames: {size: 4, accessor: 'getIcon', transform: this.getInstanceIconFrame},
96
      instanceColorModes: {
97
        size: 1,
98
        type: GL.UNSIGNED_BYTE,
99
        accessor: 'getIcon',
100
        transform: this.getInstanceColorMode
101
      },
102
      instanceColors: {
103
        size: this.props.colorFormat.length,
104
        type: GL.UNSIGNED_BYTE,
105
        normalized: true,
106
        transition: true,
107
        accessor: 'getColor',
108
        defaultValue: DEFAULT_COLOR
109
      },
110
      instanceAngles: {
111
        size: 1,
112
        transition: true,
113
        accessor: 'getAngle',
114
        defaultValue: 0
115
      }
116
    });
117
    /* eslint-enable max-len */
118
  }
119

120
  /* eslint-disable max-statements, complexity */
121
  updateState({oldProps, props, changeFlags}) {
122
    super.updateState({props, oldProps, changeFlags});
1×
123

124
    const attributeManager = this.getAttributeManager();
2×
125
    const {iconManager} = this.state;
1×
126
    const {iconAtlas, iconMapping, data, getIcon} = props;
2×
127

128
    let iconMappingChanged = false;
1×
129
    const prePacked = iconAtlas || this.props._asyncPropOriginalValues.iconAtlas;
3×
130

131
    // prepacked iconAtlas from user
132
    if (prePacked) {
1×
133
      if (oldProps.iconAtlas !== props.iconAtlas) {
1×
UNCOV
134
        iconManager.setProps({iconAtlas, autoPacking: false});
!
135
      }
136

UNCOV
137
      if (oldProps.iconMapping !== props.iconMapping) {
!
138
        iconManager.setProps({iconMapping});
3×
139
        iconMappingChanged = true;
3×
140
      }
141
    } else {
142
      // otherwise, use autoPacking
143
      iconManager.setProps({autoPacking: true});
3×
144
    }
145

146
    if (
3×
147
      changeFlags.dataChanged ||
148
      (changeFlags.updateTriggersChanged &&
149
        (changeFlags.updateTriggersChanged.all || changeFlags.updateTriggersChanged.getIcon))
150
    ) {
151
      iconManager.setProps({data, getIcon});
3×
152
      iconMappingChanged = true;
39×
153
    }
154

155
    if (iconMappingChanged) {
39×
156
      attributeManager.invalidate('instanceOffsets');
39×
157
      attributeManager.invalidate('instanceIconFrames');
39×
158
      attributeManager.invalidate('instanceColorModes');
39×
159
    }
160

161
    if (changeFlags.extensionsChanged) {
39×
162
      const {gl} = this.context;
39×
163
      if (this.state.model) {
Branches [[9, 0]] missed. 38×
164
        this.state.model.delete();
3×
165
      }
166
      this.setState({model: this._getModel(gl)});
38×
167
      attributeManager.invalidateAll();
3×
168
    }
169
  }
170
  /* eslint-enable max-statements, complexity */
171

172
  finalizeState() {
173
    super.finalizeState();
3×
174
    // Release resources held by the icon manager
175
    this.state.iconManager.finalize();
1×
176
  }
177

178
  draw({uniforms}) {
179
    const {sizeScale, sizeMinPixels, sizeMaxPixels, sizeUnits, billboard, alphaCutoff} = this.props;
39×
180
    const {iconManager} = this.state;
15×
181
    const {viewport} = this.context;
15×
182

183
    const iconsTexture = iconManager.getTexture();
39×
184
    if (iconsTexture && iconsTexture.loaded) {
15×
185
      this.state.model
15×
186
        .setUniforms(
187
          Object.assign({}, uniforms, {
188
            iconsTexture,
189
            iconsTextureDim: [iconsTexture.width, iconsTexture.height],
190
            sizeScale:
191
              sizeScale * (sizeUnits === 'pixels' ? viewport.distanceScales.metersPerPixel[2] : 1),
Branches [[12, 1]] missed.
192
            sizeMinPixels,
193
            sizeMaxPixels,
194
            billboard,
195
            alphaCutoff
196
          })
197
        )
198
        .draw();
199
    }
200
  }
201

202
  _getModel(gl) {
203
    const positions = [-1, -1, 0, -1, 1, 0, 1, 1, 0, 1, -1, 0];
15×
204

205
    return new Model(
39×
206
      gl,
207
      Object.assign({}, this.getShaders(), {
208
        id: this.props.id,
209
        geometry: new Geometry({
210
          drawMode: GL.TRIANGLE_FAN,
211
          attributes: {
212
            positions: new Float32Array(positions)
213
          }
214
        }),
215
        isInstanced: true
216
      })
217
    );
218
  }
219

220
  _onUpdate() {
221
    this.setNeedsRedraw();
3×
222
  }
223

224
  getInstanceOffset(icon) {
225
    const rect = this.state.iconManager.getIconMapping(icon);
3×
UNCOV
226
    return [rect.width / 2 - rect.anchorX || 0, rect.height / 2 - rect.anchorY || 0];
!
227
  }
228

229
  getInstanceColorMode(icon) {
230
    const mapping = this.state.iconManager.getIconMapping(icon);
3×
231
    return mapping.mask ? 1 : 0;
3×
232
  }
233

234
  getInstanceIconFrame(icon) {
235
    const rect = this.state.iconManager.getIconMapping(icon);
3×
236
    return [rect.x || 0, rect.y || 0, rect.width || 0, rect.height || 0];
Branches [[18, 1], [19, 1]] missed. 3×
237
  }
238
}
239

240
IconLayer.layerName = 'IconLayer';
42×
241
IconLayer.defaultProps = defaultProps;
42×
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