maplibre-gl 2.0.3 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/build/rollup_plugins.js +1 -0
  2. package/dist/maplibre-gl-dev.js +54589 -0
  3. package/dist/maplibre-gl.css +1 -1
  4. package/dist/maplibre-gl.d.ts +49 -15
  5. package/dist/maplibre-gl.js +3 -3
  6. package/dist/maplibre-gl.js.map +1 -1
  7. package/dist/package.json +1 -0
  8. package/package.json +78 -100
  9. package/src/css/maplibre-gl.css +36 -36
  10. package/src/data/bucket/symbol_bucket.test.ts +1 -1
  11. package/src/data/bucket/symbol_bucket.ts +3 -3
  12. package/src/data/program_configuration.ts +1 -1
  13. package/src/render/draw_debug.ts +1 -1
  14. package/src/render/glyph_manager.ts +1 -1
  15. package/src/render/painter.ts +5 -3
  16. package/src/render/program/circle_program.ts +1 -1
  17. package/src/render/program/line_program.ts +3 -3
  18. package/src/render/program/symbol_program.ts +1 -1
  19. package/src/source/geojson_source.test.ts +2 -1
  20. package/src/source/geojson_source.ts +1 -1
  21. package/src/source/image_source.test.ts +153 -0
  22. package/src/source/raster_dem_tile_source.test.ts +2 -1
  23. package/src/source/raster_dem_tile_source.ts +1 -1
  24. package/src/source/raster_tile_source.test.ts +2 -1
  25. package/src/source/raster_tile_source.ts +1 -1
  26. package/src/source/source_cache.test.ts +1 -1
  27. package/src/source/tile.test.ts +1 -1
  28. package/src/source/tile_cache.test.ts +6 -4
  29. package/src/source/tile_id.test.ts +10 -12
  30. package/src/source/tile_id.ts +2 -2
  31. package/src/source/vector_tile_source.test.ts +14 -2
  32. package/src/source/vector_tile_source.ts +3 -4
  33. package/src/style/load_glyph_range.test.ts +0 -2
  34. package/src/style/load_sprite.ts +2 -1
  35. package/src/style/properties.ts +1 -1
  36. package/src/style/style.test.ts +24 -13
  37. package/src/style/style.ts +1 -1
  38. package/src/style/style_layer/custom_style_layer.ts +2 -2
  39. package/src/style/style_layer/fill_extrusion_style_layer.ts +1 -1
  40. package/src/style/style_layer/symbol_style_layer.ts +19 -0
  41. package/src/style/style_layer/symbol_style_layer_properties.ts +6 -0
  42. package/src/style-spec/CHANGELOG.md +6 -0
  43. package/src/style-spec/package.json +1 -1
  44. package/src/style-spec/reference/v8.json +68 -2
  45. package/src/style-spec/types.ts +2 -0
  46. package/src/symbol/collision_index.ts +19 -19
  47. package/src/symbol/grid_index.test.ts +42 -19
  48. package/src/symbol/grid_index.ts +62 -33
  49. package/src/symbol/placement.ts +82 -53
  50. package/src/symbol/symbol_style_layer.test.ts +48 -1
  51. package/src/ui/camera.test.ts +4 -4
  52. package/src/ui/camera.ts +8 -0
  53. package/src/ui/control/logo_control.test.ts +1 -0
  54. package/src/ui/handler/scroll_zoom.test.ts +2 -1
  55. package/src/ui/map.test.ts +77 -10
  56. package/src/ui/map.ts +33 -8
  57. package/src/util/ajax.test.ts +206 -0
  58. package/src/util/test/util.ts +14 -0
@@ -99,7 +99,7 @@ const lineUniformValues = (painter: Painter, tile: Tile, layer: LineStyleLayer):
99
99
  return {
100
100
  'u_matrix': calculateMatrix(painter, tile, layer),
101
101
  'u_ratio': 1 / pixelsToTileUnits(tile, 1, transform.zoom),
102
- 'u_device_pixel_ratio': devicePixelRatio,
102
+ 'u_device_pixel_ratio': painter.pixelRatio,
103
103
  'u_units_to_pixels': [
104
104
  1 / transform.pixelsToGLUnits[0],
105
105
  1 / transform.pixelsToGLUnits[1]
@@ -127,7 +127,7 @@ const linePatternUniformValues = (
127
127
  'u_texsize': tile.imageAtlasTexture.size,
128
128
  // camera zoom ratio
129
129
  'u_ratio': 1 / pixelsToTileUnits(tile, 1, transform.zoom),
130
- 'u_device_pixel_ratio': devicePixelRatio,
130
+ 'u_device_pixel_ratio': painter.pixelRatio,
131
131
  'u_image': 0,
132
132
  'u_scale': [tileZoomRatio, crossfade.fromScale, crossfade.toScale],
133
133
  'u_fade': crossfade.t,
@@ -160,7 +160,7 @@ const lineSDFUniformValues = (
160
160
  return extend(lineUniformValues(painter, tile, layer), {
161
161
  'u_patternscale_a': [tileRatio / widthA, -posA.height / 2],
162
162
  'u_patternscale_b': [tileRatio / widthB, -posB.height / 2],
163
- 'u_sdfgamma': lineAtlas.width / (Math.min(widthA, widthB) * 256 * devicePixelRatio) / 2,
163
+ 'u_sdfgamma': lineAtlas.width / (Math.min(widthA, widthB) * 256 * painter.pixelRatio) / 2,
164
164
  'u_image': 0,
165
165
  'u_tex_y_a': posA.y,
166
166
  'u_tex_y_b': posB.y,
@@ -195,7 +195,7 @@ const symbolSDFUniformValues = (
195
195
  rotateInShader, pitchWithMap, painter, matrix, labelPlaneMatrix,
196
196
  glCoordMatrix, isText, texSize), {
197
197
  'u_gamma_scale': (pitchWithMap ? Math.cos(transform._pitch) * transform.cameraToCenterDistance : 1),
198
- 'u_device_pixel_ratio': devicePixelRatio,
198
+ 'u_device_pixel_ratio': painter.pixelRatio,
199
199
  'u_is_halo': +isHalo
200
200
  });
201
201
  };
@@ -318,7 +318,8 @@ describe('GeoJSONSource#update', () => {
318
318
 
319
319
  const source = new GeoJSONSource('id', {data: {}} as GeoJSONSourceOptions, mockDispatcher, undefined);
320
320
  source.map = {
321
- transform: {} as Transform
321
+ transform: {} as Transform,
322
+ getPixelRatio() { return 1; }
322
323
  } as any;
323
324
 
324
325
  source.on('data', (e) => {
@@ -299,7 +299,7 @@ class GeoJSONSource extends Evented implements Source {
299
299
  maxZoom: this.maxzoom,
300
300
  tileSize: this.tileSize,
301
301
  source: this.id,
302
- pixelRatio: devicePixelRatio,
302
+ pixelRatio: this.map.getPixelRatio(),
303
303
  showCollisionBoxes: this.map.showCollisionBoxes,
304
304
  promoteId: this.promoteId
305
305
  };
@@ -0,0 +1,153 @@
1
+ import ImageSource from './image_source';
2
+ import {Evented} from '../util/evented';
3
+ import Transform from '../geo/transform';
4
+ import {extend} from '../util/util';
5
+ import {useFakeXMLHttpRequest} from 'sinon';
6
+ import {RequestManager} from '../util/request_manager';
7
+ import Dispatcher from '../util/dispatcher';
8
+ import {stubAjaxGetImage} from '../util/test/util';
9
+
10
+ function createSource(options) {
11
+ options = extend({
12
+ coordinates: [[0, 0], [1, 0], [1, 1], [0, 1]]
13
+ }, options);
14
+
15
+ const source = new ImageSource('id', options, {send() {}} as any as Dispatcher, options.eventedParent);
16
+ return source;
17
+ }
18
+
19
+ class StubMap extends Evented {
20
+ transform: Transform;
21
+ _requestManager: RequestManager;
22
+
23
+ constructor() {
24
+ super();
25
+ this.transform = new Transform();
26
+ this._requestManager = {
27
+ transformRequest: (url) => {
28
+ return {url};
29
+ }
30
+ } as any as RequestManager;
31
+ }
32
+ }
33
+
34
+ describe('ImageSource', () => {
35
+ const requests = [];
36
+ useFakeXMLHttpRequest().onCreate = (req) => { requests.push(req); };
37
+ stubAjaxGetImage(undefined);
38
+ beforeEach(() => {
39
+ global.fetch = null;
40
+ });
41
+
42
+ const respond = () => {
43
+ const req = requests.shift();
44
+ req.setStatus(200);
45
+ req.response = new ArrayBuffer(1);
46
+ req.onload();
47
+ };
48
+
49
+ test('constructor', () => {
50
+ const source = createSource({url : '/image.png'});
51
+
52
+ expect(source.minzoom).toBe(0);
53
+ expect(source.maxzoom).toBe(22);
54
+ expect(source.tileSize).toBe(512);
55
+ });
56
+
57
+ test('fires dataloading event', () => {
58
+ const source = createSource({url : '/image.png'});
59
+ source.on('dataloading', (e) => {
60
+ expect(e.dataType).toBe('source');
61
+ });
62
+ source.onAdd(new StubMap() as any);
63
+ respond();
64
+ expect(source.image).toBeTruthy();
65
+ });
66
+
67
+ test('transforms url request', () => {
68
+ const source = createSource({url : '/image.png'});
69
+ const map = new StubMap() as any;
70
+ const spy = jest.spyOn(map._requestManager, 'transformRequest');
71
+ source.onAdd(map);
72
+ respond();
73
+ expect(spy).toHaveBeenCalledTimes(1);
74
+ expect(spy.mock.calls[0][0]).toBe('/image.png');
75
+ expect(spy.mock.calls[0][1]).toBe('Image');
76
+ });
77
+
78
+ test('updates url from updateImage', () => {
79
+ const source = createSource({url : '/image.png'});
80
+ const map = new StubMap() as any;
81
+ const spy = jest.spyOn(map._requestManager, 'transformRequest');
82
+ source.onAdd(map);
83
+ respond();
84
+ expect(spy).toHaveBeenCalledTimes(1);
85
+ expect(spy.mock.calls[0][0]).toBe('/image.png');
86
+ expect(spy.mock.calls[0][1]).toBe('Image');
87
+ source.updateImage({url: '/image2.png'});
88
+ respond();
89
+ expect(spy).toHaveBeenCalledTimes(2);
90
+ expect(spy.mock.calls[1][0]).toBe('/image2.png');
91
+ expect(spy.mock.calls[1][1]).toBe('Image');
92
+ });
93
+
94
+ test('sets coordinates', () => {
95
+ const source = createSource({url : '/image.png'});
96
+ const map = new StubMap() as any;
97
+ source.onAdd(map);
98
+ respond();
99
+ const beforeSerialized = source.serialize();
100
+ expect(beforeSerialized.coordinates).toEqual([[0, 0], [1, 0], [1, 1], [0, 1]]);
101
+ source.setCoordinates([[0, 0], [-1, 0], [-1, -1], [0, -1]]);
102
+ const afterSerialized = source.serialize();
103
+ expect(afterSerialized.coordinates).toEqual([[0, 0], [-1, 0], [-1, -1], [0, -1]]);
104
+ });
105
+
106
+ test('sets coordinates via updateImage', () => {
107
+ const source = createSource({url : '/image.png'});
108
+ const map = new StubMap() as any;
109
+ source.onAdd(map);
110
+ respond();
111
+ const beforeSerialized = source.serialize();
112
+ expect(beforeSerialized.coordinates).toEqual([[0, 0], [1, 0], [1, 1], [0, 1]]);
113
+ source.updateImage({
114
+ url: '/image2.png',
115
+ coordinates: [[0, 0], [-1, 0], [-1, -1], [0, -1]]
116
+ });
117
+ respond();
118
+ const afterSerialized = source.serialize();
119
+ expect(afterSerialized.coordinates).toEqual([[0, 0], [-1, 0], [-1, -1], [0, -1]]);
120
+ });
121
+
122
+ test('fires data event when content is loaded', done => {
123
+ const source = createSource({url : '/image.png'});
124
+ source.on('data', (e) => {
125
+ if (e.dataType === 'source' && e.sourceDataType === 'content') {
126
+ expect(typeof source.tileID == 'object').toBeTruthy();
127
+ done();
128
+ }
129
+ });
130
+ source.onAdd(new StubMap() as any);
131
+ respond();
132
+ });
133
+
134
+ test('fires data event when metadata is loaded', done => {
135
+ const source = createSource({url : '/image.png'});
136
+ source.on('data', (e) => {
137
+ if (e.dataType === 'source' && e.sourceDataType === 'metadata') {
138
+ done();
139
+ }
140
+ });
141
+ source.onAdd(new StubMap() as any);
142
+ respond();
143
+ });
144
+
145
+ test('serialize url and coordinates', () => {
146
+ const source = createSource({url: '/image.png'});
147
+
148
+ const serialized = source.serialize();
149
+ expect(serialized.type).toBe('image');
150
+ expect(serialized.url).toBe('/image.png');
151
+ expect(serialized.coordinates).toEqual([[0, 0], [1, 0], [1, 1], [0, 1]]);
152
+ });
153
+ });
@@ -10,7 +10,8 @@ function createSource(options, transformCallback?) {
10
10
  source.onAdd({
11
11
  transform: {angle: 0, pitch: 0, showCollisionBoxes: false},
12
12
  _getMapId: () => 1,
13
- _requestManager: new RequestManager(transformCallback)
13
+ _requestManager: new RequestManager(transformCallback),
14
+ getPixelRatio() { return 1; }
14
15
  } as any);
15
16
 
16
17
  source.on('error', (e) => {
@@ -37,7 +37,7 @@ class RasterDEMTileSource extends RasterTileSource implements Source {
37
37
  }
38
38
 
39
39
  loadTile(tile: Tile, callback: Callback<void>) {
40
- const url = tile.tileID.canonical.url(this.tiles, this.scheme);
40
+ const url = tile.tileID.canonical.url(this.tiles, this.map.getPixelRatio(), this.scheme);
41
41
  tile.request = getImage(this.map._requestManager.transformRequest(url, ResourceType.Tile), imageLoaded.bind(this));
42
42
 
43
43
  tile.neighboringTiles = this._getNeighboringTiles(tile.tileID);
@@ -10,7 +10,8 @@ function createSource(options, transformCallback?) {
10
10
  source.onAdd({
11
11
  transform: {angle: 0, pitch: 0, showCollisionBoxes: false},
12
12
  _getMapId: () => 1,
13
- _requestManager: new RequestManager(transformCallback)
13
+ _requestManager: new RequestManager(transformCallback),
14
+ getPixelRatio() { return 1; }
14
15
  } as any);
15
16
 
16
17
  source.on('error', (e) => {
@@ -104,7 +104,7 @@ class RasterTileSource extends Evented implements Source {
104
104
  }
105
105
 
106
106
  loadTile(tile: Tile, callback: Callback<void>) {
107
- const url = tile.tileID.canonical.url(this.tiles, this.scheme);
107
+ const url = tile.tileID.canonical.url(this.tiles, this.map.getPixelRatio(), this.scheme);
108
108
  tile.request = getImage(this.map._requestManager.transformRequest(url, ResourceType.Tile), (err, img) => {
109
109
  delete tile.request;
110
110
 
@@ -15,7 +15,7 @@ class SourceMock extends Evented {
15
15
  id: string;
16
16
  minzoom: number;
17
17
  maxzoom: number;
18
- hasTile: (tileID: OverscaledTileID) => boolean
18
+ hasTile: (tileID: OverscaledTileID) => boolean;
19
19
  sourceOptions: any;
20
20
 
21
21
  constructor(id: string, sourceOptions: any, _dispatcher, eventedParent: Evented) {
@@ -1,4 +1,4 @@
1
- import {createSymbolBucket} from '../../test/util/create_symbol_layer_jest';
1
+ import {createSymbolBucket} from '../../test/util/create_symbol_layer';
2
2
  import Tile from '../source/tile';
3
3
  import GeoJSONWrapper, {Feature} from '../source/geojson_wrapper';
4
4
  import {OverscaledTileID} from '../source/tile_id';
@@ -30,19 +30,20 @@ describe('TileCache', () => {
30
30
  keysExpected(cache, []);
31
31
  });
32
32
 
33
- test('get without removing', () => {
33
+ test('get without removing', done => {
34
34
  const cache = new TileCache(10, () => {
35
- fail();
35
+ done('test "get without removing" failed');
36
36
  });
37
37
  expect(cache.add(idA, tileA)).toBe(cache);
38
38
  expect(cache.get(idA)).toBe(tileA);
39
39
  keysExpected(cache, [idA]);
40
40
  expect(cache.get(idA)).toBe(tileA);
41
+ done();
41
42
  });
42
43
 
43
- test('duplicate add', () => {
44
+ test('duplicate add', done => {
44
45
  const cache = new TileCache(10, () => {
45
- fail();
46
+ done('test "duplicate add" failed');
46
47
  });
47
48
 
48
49
  cache.add(idA, tileA);
@@ -53,6 +54,7 @@ describe('TileCache', () => {
53
54
  expect(cache.getAndRemove(idA)).toBe(tileA);
54
55
  expect(cache.has(idA)).toBeTruthy();
55
56
  expect(cache.getAndRemove(idA)).toBe(tileA2);
57
+ done();
56
58
  });
57
59
 
58
60
  test('expiry', () => {
@@ -33,35 +33,33 @@ describe('CanonicalTileID', () => {
33
33
  });
34
34
 
35
35
  test('.url replaces {z}/{x}/{y}', () => {
36
- expect(new CanonicalTileID(2, 1, 0).url(['{z}/{x}/{y}.json'])).toBe('2/1/0.json');
36
+ expect(new CanonicalTileID(2, 1, 0).url(['{z}/{x}/{y}.json'], 1)).toBe('2/1/0.json');
37
37
  });
38
38
 
39
39
  test('.url replaces {quadkey}', () => {
40
- expect(new CanonicalTileID(1, 0, 0).url(['quadkey={quadkey}'])).toBe('quadkey=0');
41
- expect(new CanonicalTileID(2, 0, 0).url(['quadkey={quadkey}'])).toBe('quadkey=00');
42
- expect(new CanonicalTileID(2, 1, 1).url(['quadkey={quadkey}'])).toBe('quadkey=03');
43
- expect(new CanonicalTileID(17, 22914, 52870).url(['quadkey={quadkey}'])).toBe('quadkey=02301322130000230');
40
+ expect(new CanonicalTileID(1, 0, 0).url(['quadkey={quadkey}'], 1)).toBe('quadkey=0');
41
+ expect(new CanonicalTileID(2, 0, 0).url(['quadkey={quadkey}'], 1)).toBe('quadkey=00');
42
+ expect(new CanonicalTileID(2, 1, 1).url(['quadkey={quadkey}'], 1)).toBe('quadkey=03');
43
+ expect(new CanonicalTileID(17, 22914, 52870).url(['quadkey={quadkey}'], 1)).toBe('quadkey=02301322130000230');
44
44
 
45
45
  // Test case confirmed by quadkeytools package
46
46
  // https://bitbucket.org/steele/quadkeytools/rollup/build/tsc/src/master/test/quadkey.js?fileviewer=file-view-default#quadkey.js-57
47
- expect(new CanonicalTileID(6, 29, 3).url(['quadkey={quadkey}'])).toBe('quadkey=011123');
47
+ expect(new CanonicalTileID(6, 29, 3).url(['quadkey={quadkey}'], 1)).toBe('quadkey=011123');
48
48
 
49
49
  });
50
50
 
51
51
  test('.url replaces {bbox-epsg-3857}', () => {
52
- expect(new CanonicalTileID(1, 0, 0).url(['bbox={bbox-epsg-3857}'])).toBe('bbox=-20037508.342789244,0,0,20037508.342789244');
52
+ expect(new CanonicalTileID(1, 0, 0).url(['bbox={bbox-epsg-3857}'], 1)).toBe('bbox=-20037508.342789244,0,0,20037508.342789244');
53
53
  });
54
54
 
55
55
  test('.url replaces {ratio}', () => {
56
- devicePixelRatio = 2;
57
- expect(new CanonicalTileID(1, 0, 0).url(['r={ratio}'])).toBe('r=@2x');
58
- devicePixelRatio = 1;
59
- expect(new CanonicalTileID(1, 0, 0).url(['r={ratio}'])).toBe('r=');
56
+ expect(new CanonicalTileID(1, 0, 0).url(['r={ratio}'], 2)).toBe('r=@2x');
57
+ expect(new CanonicalTileID(1, 0, 0).url(['r={ratio}'], 1)).toBe('r=');
60
58
  });
61
59
 
62
60
  //Tests that multiple values of the same placeholder are replaced.
63
61
  test('.url replaces {z}/{x}/{y}/{z}/{x}/{y}', () => {
64
- expect(new CanonicalTileID(2, 1, 0).url(['{z}/{x}/{y}/{z}/{x}/{y}.json'])).toBe('2/1/0/2/1/0.json');
62
+ expect(new CanonicalTileID(2, 1, 0).url(['{z}/{x}/{y}/{z}/{x}/{y}.json'], 1)).toBe('2/1/0/2/1/0.json');
65
63
  });
66
64
 
67
65
  });
@@ -28,7 +28,7 @@ export class CanonicalTileID {
28
28
  }
29
29
 
30
30
  // given a list of urls, choose a url template and return a tile URL
31
- url(urls: Array<string>, scheme?: string | null) {
31
+ url(urls: Array<string>, pixelRatio: number, scheme?: string | null) {
32
32
  const bbox = getTileBBox(this.x, this.y, this.z);
33
33
  const quadkey = getQuadkey(this.z, this.x, this.y);
34
34
 
@@ -37,7 +37,7 @@ export class CanonicalTileID {
37
37
  .replace(/{z}/g, String(this.z))
38
38
  .replace(/{x}/g, String(this.x))
39
39
  .replace(/{y}/g, String(scheme === 'tms' ? (Math.pow(2, this.z) - this.y - 1) : this.y))
40
- .replace(/{ratio}/g, devicePixelRatio > 1 ? '@2x' : '')
40
+ .replace(/{ratio}/g, pixelRatio > 1 ? '@2x' : '')
41
41
  .replace(/{quadkey}/g, quadkey)
42
42
  .replace(/{bbox-epsg-3857}/g, bbox);
43
43
  }
@@ -9,13 +9,14 @@ import fixturesSource from '../../test/fixtures/source.json';
9
9
  import {getMockDispatcher, getWrapDispatcher} from '../util/test/util';
10
10
  import Map from '../ui/map';
11
11
 
12
- function createSource(options, transformCallback?) {
12
+ function createSource(options, transformCallback?, clearTiles = () => {}) {
13
13
  const source = new VectorTileSource('id', options, getMockDispatcher(), options.eventedParent);
14
14
  source.onAdd({
15
15
  transform: {showCollisionBoxes: false},
16
16
  _getMapId: () => 1,
17
17
  _requestManager: new RequestManager(transformCallback),
18
- style: {sourceCaches: {id: {clearTiles: () => {}}}}
18
+ style: {sourceCaches: {id: {clearTiles}}},
19
+ getPixelRatio() { return 1; }
19
20
  } as any as Map);
20
21
 
21
22
  source.on('error', (e) => {
@@ -342,4 +343,15 @@ describe('VectorTileSource', () => {
342
343
  tiles: ['http://example2.com/{z}/{x}/{y}.png']
343
344
  });
344
345
  });
346
+
347
+ test('setTiles only clears the cache once the TileJSON has reloaded', done => {
348
+ const clearTiles = jest.fn();
349
+ const source = createSource({tiles: ['http://example.com/{z}/{x}/{y}.pbf']}, undefined, clearTiles);
350
+ source.setTiles(['http://example2.com/{z}/{x}/{y}.pbf']);
351
+ expect(clearTiles.mock.calls).toHaveLength(0);
352
+ source.once('data', () => {
353
+ expect(clearTiles.mock.calls).toHaveLength(1);
354
+ done();
355
+ });
356
+ });
345
357
  });
@@ -97,6 +97,7 @@ class VectorTileSource extends Evented implements Source {
97
97
  this._tileJSONRequest = loadTileJSON(this._options, this.map._requestManager, (err, tileJSON) => {
98
98
  this._tileJSONRequest = null;
99
99
  this._loaded = true;
100
+ this.map.style.sourceCaches[this.id].clearTiles();
100
101
  if (err) {
101
102
  this.fire(new ErrorEvent(err));
102
103
  } else if (tileJSON) {
@@ -132,8 +133,6 @@ class VectorTileSource extends Evented implements Source {
132
133
 
133
134
  callback();
134
135
 
135
- const sourceCache = this.map.style.sourceCaches[this.id];
136
- sourceCache.clearTiles();
137
136
  this.load();
138
137
  }
139
138
 
@@ -178,7 +177,7 @@ class VectorTileSource extends Evented implements Source {
178
177
  }
179
178
 
180
179
  loadTile(tile: Tile, callback: Callback<void>) {
181
- const url = tile.tileID.canonical.url(this.tiles, this.scheme);
180
+ const url = tile.tileID.canonical.url(this.tiles, this.map.getPixelRatio(), this.scheme);
182
181
  const params = {
183
182
  request: this.map._requestManager.transformRequest(url, ResourceType.Tile),
184
183
  uid: tile.uid,
@@ -187,7 +186,7 @@ class VectorTileSource extends Evented implements Source {
187
186
  tileSize: this.tileSize * tile.tileID.overscaleFactor(),
188
187
  type: this.type,
189
188
  source: this.id,
190
- pixelRatio: devicePixelRatio,
189
+ pixelRatio: this.map.getPixelRatio(),
191
190
  showCollisionBoxes: this.map.showCollisionBoxes,
192
191
  promoteId: this.promoteId
193
192
  };
@@ -26,8 +26,6 @@ test('loadGlyphRange', done => {
26
26
  const id = Number(key);
27
27
  const glyph = result[id];
28
28
 
29
- if (!glyph) return done.fail(); // appease flow
30
-
31
29
  expect(glyph.id).toBe(Number(id));
32
30
  expect(glyph.metrics).toBeTruthy();
33
31
  expect(typeof glyph.metrics.width).toBe('number');
@@ -11,10 +11,11 @@ import type {Cancelable} from '../types/cancelable';
11
11
  export default function(
12
12
  baseURL: string,
13
13
  requestManager: RequestManager,
14
+ pixelRatio: number,
14
15
  callback: Callback<{[_: string]: StyleImage}>
15
16
  ): Cancelable {
16
17
  let json: any, image, error;
17
- const format = devicePixelRatio > 1 ? '@2x' : '';
18
+ const format = pixelRatio > 1 ? '@2x' : '';
18
19
 
19
20
  let jsonRequest = getJSON(requestManager.transformRequest(requestManager.normalizeSpriteURL(baseURL, format, '.json'), ResourceType.SpriteJSON), (err?: Error | null, data?: any | null) => {
20
21
  jsonRequest = null;
@@ -730,7 +730,7 @@ export class Properties<Props> {
730
730
  defaultPropertyValues: {[K in keyof Props]: PropertyValue<unknown, any>};
731
731
  defaultTransitionablePropertyValues: {[K in keyof Props]: TransitionablePropertyValue<unknown, unknown>};
732
732
  defaultTransitioningPropertyValues: {[K in keyof Props]: TransitioningPropertyValue<unknown, unknown>};
733
- defaultPossiblyEvaluatedValues: {[K in keyof Props]: PossiblyEvaluatedPropertyValue<unknown>};;
733
+ defaultPossiblyEvaluatedValues: {[K in keyof Props]: PossiblyEvaluatedPropertyValue<unknown>};
734
734
  overridableProperties: Array<string>;
735
735
 
736
736
  constructor(properties: Props) {
@@ -48,6 +48,7 @@ function createGeoJSONSource() {
48
48
  }
49
49
 
50
50
  class StubMap extends Evented {
51
+ style: Style;
51
52
  transform: Transform;
52
53
  private _requestManager: RequestManager;
53
54
 
@@ -60,10 +61,20 @@ class StubMap extends Evented {
60
61
  _getMapId() {
61
62
  return 1;
62
63
  }
64
+
65
+ getPixelRatio() {
66
+ return 1;
67
+ }
63
68
  }
64
69
 
65
70
  const getStubMap = () => new StubMap() as any;
66
71
 
72
+ function createStyle(map = getStubMap()) {
73
+ const style = new Style(map);
74
+ map.style = style;
75
+ return style;
76
+ }
77
+
67
78
  let sinonFakeXMLServer;
68
79
  let sinonFakeServer;
69
80
  let _self;
@@ -254,7 +265,7 @@ describe('Style#loadJSON', () => {
254
265
  });
255
266
 
256
267
  test('creates sources', done => {
257
- const style = new Style(getStubMap());
268
+ const style = createStyle();
258
269
 
259
270
  style.on('style.load', () => {
260
271
  expect(style.sourceCaches['mapLibre'] instanceof SourceCache).toBeTruthy();
@@ -272,7 +283,7 @@ describe('Style#loadJSON', () => {
272
283
  });
273
284
 
274
285
  test('creates layers', done => {
275
- const style = new Style(getStubMap());
286
+ const style = createStyle();
276
287
 
277
288
  style.on('style.load', () => {
278
289
  expect(style.getLayer('fill') instanceof StyleLayer).toBeTruthy();
@@ -298,7 +309,7 @@ describe('Style#loadJSON', () => {
298
309
  test('transforms sprite json and image URLs before request', done => {
299
310
  const map = getStubMap();
300
311
  const transformSpy = jest.spyOn(map._requestManager, 'transformRequest');
301
- const style = new Style(map);
312
+ const style = createStyle(map);
302
313
 
303
314
  style.on('style.load', () => {
304
315
  expect(transformSpy).toHaveBeenCalledTimes(2);
@@ -315,7 +326,7 @@ describe('Style#loadJSON', () => {
315
326
  });
316
327
 
317
328
  test('emits an error on non-existant vector source layer', done => {
318
- const style = new Style(getStubMap());
329
+ const style = createStyle();
319
330
  style.loadJSON(createStyleJSON({
320
331
  sources: {
321
332
  '-source-id-': {type: 'vector', tiles: []}
@@ -403,7 +414,7 @@ describe('Style#_remove', () => {
403
414
 
404
415
  describe('Style#update', () => {
405
416
  test('on error', done => {
406
- const style = new Style(getStubMap());
417
+ const style = createStyle();
407
418
  style.loadJSON({
408
419
  'version': 8,
409
420
  'sources': {
@@ -445,7 +456,7 @@ describe('Style#setState', () => {
445
456
  });
446
457
 
447
458
  test('do nothing if there are no changes', done => {
448
- const style = new Style(getStubMap());
459
+ const style = createStyle();
449
460
  style.loadJSON(createStyleJSON());
450
461
  jest.spyOn(style, 'addLayer').mockImplementation(() => done('test failed'));
451
462
  jest.spyOn(style, 'removeLayer').mockImplementation(() => done('test failed'));
@@ -570,7 +581,7 @@ describe('Style#addSource', () => {
570
581
  });
571
582
 
572
583
  test('fires "data" event', done => {
573
- const style = new Style(getStubMap());
584
+ const style = createStyle();
574
585
  style.loadJSON(createStyleJSON());
575
586
  const source = createSource();
576
587
  style.once('data', () => { done(); });
@@ -581,7 +592,7 @@ describe('Style#addSource', () => {
581
592
  });
582
593
 
583
594
  test('throws on duplicates', done => {
584
- const style = new Style(getStubMap());
595
+ const style = createStyle();
585
596
  style.loadJSON(createStyleJSON());
586
597
  const source = createSource();
587
598
  style.on('style.load', () => {
@@ -603,7 +614,7 @@ describe('Style#addSource', () => {
603
614
  done();
604
615
  }
605
616
  };
606
- const style = new Style(getStubMap());
617
+ const style = createStyle();
607
618
  style.loadJSON(createStyleJSON({
608
619
  layers: [{
609
620
  id: 'background',
@@ -791,7 +802,7 @@ describe('Style#addLayer', () => {
791
802
  });
792
803
 
793
804
  test('throws on non-existant vector source layer', done => {
794
- const style = new Style(getStubMap());
805
+ const style = createStyle();
795
806
  style.loadJSON(createStyleJSON({
796
807
  sources: {
797
808
  // At least one source must be added to trigger the load event
@@ -860,7 +871,7 @@ describe('Style#addLayer', () => {
860
871
  });
861
872
 
862
873
  test('reloads source', done => {
863
- const style = new Style(getStubMap());
874
+ const style = createStyle();
864
875
  style.loadJSON(extend(createStyleJSON(), {
865
876
  'sources': {
866
877
  'mapLibre': {
@@ -887,7 +898,7 @@ describe('Style#addLayer', () => {
887
898
  });
888
899
 
889
900
  test('#3895 reloads source (instead of clearing) if adding this layer with the same type, immediately after removing it', done => {
890
- const style = new Style(getStubMap());
901
+ const style = createStyle();
891
902
  style.loadJSON(extend(createStyleJSON(), {
892
903
  'sources': {
893
904
  'mapLibre': {
@@ -924,7 +935,7 @@ describe('Style#addLayer', () => {
924
935
  });
925
936
 
926
937
  test('clears source (instead of reloading) if adding this layer with a different type, immediately after removing it', done => {
927
- const style = new Style(getStubMap());
938
+ const style = createStyle();
928
939
  style.loadJSON(extend(createStyleJSON(), {
929
940
  'sources': {
930
941
  'mapLibre': {
@@ -276,7 +276,7 @@ class Style extends Evented {
276
276
  }
277
277
 
278
278
  _loadSprite(url: string) {
279
- this._spriteRequest = loadSprite(url, this.map._requestManager, (err, images) => {
279
+ this._spriteRequest = loadSprite(url, this.map._requestManager, this.map.getPixelRatio(), (err, images) => {
280
280
  this._spriteRequest = null;
281
281
  if (err) {
282
282
  this.fire(new ErrorEvent(err));
@@ -213,13 +213,13 @@ class CustomStyleLayer extends StyleLayer {
213
213
  if (this.implementation.onAdd) {
214
214
  this.implementation.onAdd(map, map.painter.context.gl);
215
215
  }
216
- }
216
+ };
217
217
 
218
218
  onRemove = (map: Map) => {
219
219
  if (this.implementation.onRemove) {
220
220
  this.implementation.onRemove(map, map.painter.context.gl);
221
221
  }
222
- }
222
+ };
223
223
  }
224
224
 
225
225
  export default CustomStyleLayer;
@@ -15,7 +15,7 @@ import type {LayerSpecification} from '../../style-spec/types';
15
15
  import type {VectorTileFeature} from '@mapbox/vector-tile';
16
16
 
17
17
  export class Point3D extends Point {
18
- z: number
18
+ z: number;
19
19
  }
20
20
 
21
21
  class FillExtrusionStyleLayer extends StyleLayer {