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.
- package/build/rollup_plugins.js +1 -0
- package/dist/maplibre-gl-dev.js +54589 -0
- package/dist/maplibre-gl.css +1 -1
- package/dist/maplibre-gl.d.ts +49 -15
- package/dist/maplibre-gl.js +3 -3
- package/dist/maplibre-gl.js.map +1 -1
- package/dist/package.json +1 -0
- package/package.json +78 -100
- package/src/css/maplibre-gl.css +36 -36
- package/src/data/bucket/symbol_bucket.test.ts +1 -1
- package/src/data/bucket/symbol_bucket.ts +3 -3
- package/src/data/program_configuration.ts +1 -1
- package/src/render/draw_debug.ts +1 -1
- package/src/render/glyph_manager.ts +1 -1
- package/src/render/painter.ts +5 -3
- package/src/render/program/circle_program.ts +1 -1
- package/src/render/program/line_program.ts +3 -3
- package/src/render/program/symbol_program.ts +1 -1
- package/src/source/geojson_source.test.ts +2 -1
- package/src/source/geojson_source.ts +1 -1
- package/src/source/image_source.test.ts +153 -0
- package/src/source/raster_dem_tile_source.test.ts +2 -1
- package/src/source/raster_dem_tile_source.ts +1 -1
- package/src/source/raster_tile_source.test.ts +2 -1
- package/src/source/raster_tile_source.ts +1 -1
- package/src/source/source_cache.test.ts +1 -1
- package/src/source/tile.test.ts +1 -1
- package/src/source/tile_cache.test.ts +6 -4
- package/src/source/tile_id.test.ts +10 -12
- package/src/source/tile_id.ts +2 -2
- package/src/source/vector_tile_source.test.ts +14 -2
- package/src/source/vector_tile_source.ts +3 -4
- package/src/style/load_glyph_range.test.ts +0 -2
- package/src/style/load_sprite.ts +2 -1
- package/src/style/properties.ts +1 -1
- package/src/style/style.test.ts +24 -13
- package/src/style/style.ts +1 -1
- package/src/style/style_layer/custom_style_layer.ts +2 -2
- package/src/style/style_layer/fill_extrusion_style_layer.ts +1 -1
- package/src/style/style_layer/symbol_style_layer.ts +19 -0
- package/src/style/style_layer/symbol_style_layer_properties.ts +6 -0
- package/src/style-spec/CHANGELOG.md +6 -0
- package/src/style-spec/package.json +1 -1
- package/src/style-spec/reference/v8.json +68 -2
- package/src/style-spec/types.ts +2 -0
- package/src/symbol/collision_index.ts +19 -19
- package/src/symbol/grid_index.test.ts +42 -19
- package/src/symbol/grid_index.ts +62 -33
- package/src/symbol/placement.ts +82 -53
- package/src/symbol/symbol_style_layer.test.ts +48 -1
- package/src/ui/camera.test.ts +4 -4
- package/src/ui/camera.ts +8 -0
- package/src/ui/control/logo_control.test.ts +1 -0
- package/src/ui/handler/scroll_zoom.test.ts +2 -1
- package/src/ui/map.test.ts +77 -10
- package/src/ui/map.ts +33 -8
- package/src/util/ajax.test.ts +206 -0
- 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':
|
|
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':
|
|
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 *
|
|
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':
|
|
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:
|
|
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) {
|
package/src/source/tile.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {createSymbolBucket} from '../../test/util/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
57
|
-
expect(new CanonicalTileID(1, 0, 0).url(['r={ratio}'])).toBe('r
|
|
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
|
});
|
package/src/source/tile_id.ts
CHANGED
|
@@ -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,
|
|
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:
|
|
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');
|
package/src/style/load_sprite.ts
CHANGED
|
@@ -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 =
|
|
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;
|
package/src/style/properties.ts
CHANGED
|
@@ -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) {
|
package/src/style/style.test.ts
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
938
|
+
const style = createStyle();
|
|
928
939
|
style.loadJSON(extend(createStyleJSON(), {
|
|
929
940
|
'sources': {
|
|
930
941
|
'mapLibre': {
|
package/src/style/style.ts
CHANGED
|
@@ -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;
|