maplibre-gl 3.3.0 → 3.4.0
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/LICENSE.txt +1 -1
- package/README.md +3 -2
- package/build/generate-dist-package.js +7 -2
- package/build/generate-typings.ts +1 -1
- package/dist/LICENSE.txt +116 -0
- package/dist/maplibre-gl-csp-worker.js +1 -1
- package/dist/maplibre-gl-csp-worker.js.map +1 -1
- package/dist/maplibre-gl-csp.js +1 -1
- package/dist/maplibre-gl-csp.js.map +1 -1
- package/dist/maplibre-gl-dev.js +243 -100
- package/dist/maplibre-gl-dev.js.map +1 -1
- package/dist/maplibre-gl.d.ts +28 -15
- package/dist/maplibre-gl.js +4 -4
- package/dist/maplibre-gl.js.map +1 -1
- package/dist/package.json +1 -1
- package/package.json +48 -47
- package/src/data/dem_data.test.ts +120 -165
- package/src/data/dem_data.ts +38 -18
- package/src/render/program.ts +15 -0
- package/src/source/image_source.test.ts +17 -24
- package/src/source/raster_dem_tile_source.ts +15 -2
- package/src/source/raster_dem_tile_worker_source.ts +2 -2
- package/src/source/raster_tile_source.test.ts +1 -1
- package/src/source/raster_tile_source.ts +1 -1
- package/src/source/terrain_source_cache.test.ts +1 -1
- package/src/source/vector_tile_source.test.ts +1 -1
- package/src/source/vector_tile_source.ts +0 -1
- package/src/source/vector_tile_worker_source.test.ts +45 -1
- package/src/source/vector_tile_worker_source.ts +19 -6
- package/src/source/video_source.ts +4 -0
- package/src/source/worker_source.ts +6 -2
- package/src/style/load_glyph_range.test.ts +6 -8
- package/src/style/load_sprite.test.ts +48 -71
- package/src/style/style.test.ts +19 -49
- package/src/style/style.ts +14 -8
- package/src/style/style_layer/line_style_layer.test.ts +50 -0
- package/src/style/style_layer/line_style_layer.ts +8 -4
- package/src/style/style_layer/variable_text_anchor.ts +1 -1
- package/src/ui/control/navigation_control.ts +0 -1
- package/src/ui/handler/scroll_zoom.ts +6 -0
- package/src/ui/handler_manager.ts +2 -1
- package/src/ui/map.test.ts +37 -8
- package/src/ui/map.ts +15 -13
- package/src/ui/marker.test.ts +25 -0
- package/src/ui/marker.ts +9 -2
- package/src/ui/popup.ts +1 -1
- package/src/util/ajax.test.ts +1 -1
- package/src/util/image_request.test.ts +1 -1
- package/src/util/test/util.ts +12 -0
- package/src/util/throttle.ts +7 -3
|
@@ -2,7 +2,7 @@ import {ImageSource} from './image_source';
|
|
|
2
2
|
import {Evented} from '../util/evented';
|
|
3
3
|
import {Transform} from '../geo/transform';
|
|
4
4
|
import {extend} from '../util/util';
|
|
5
|
-
import {
|
|
5
|
+
import {type FakeServer, fakeServer} from 'nise';
|
|
6
6
|
import {RequestManager} from '../util/request_manager';
|
|
7
7
|
import {Dispatcher} from '../util/dispatcher';
|
|
8
8
|
import {stubAjaxGetImage} from '../util/test/util';
|
|
@@ -44,20 +44,15 @@ class StubMap extends Evented {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
describe('ImageSource', () => {
|
|
47
|
-
const requests = [];
|
|
48
|
-
fakeXhr.useFakeXMLHttpRequest().onCreate = (req) => { requests.push(req); };
|
|
49
47
|
stubAjaxGetImage(undefined);
|
|
48
|
+
let server: FakeServer;
|
|
49
|
+
|
|
50
50
|
beforeEach(() => {
|
|
51
51
|
global.fetch = null;
|
|
52
|
+
server = fakeServer.create();
|
|
53
|
+
server.respondWith(new ArrayBuffer(1));
|
|
52
54
|
});
|
|
53
55
|
|
|
54
|
-
const respond = () => {
|
|
55
|
-
const req = requests.shift();
|
|
56
|
-
req.setStatus(200);
|
|
57
|
-
req.response = new ArrayBuffer(1);
|
|
58
|
-
req.onload();
|
|
59
|
-
};
|
|
60
|
-
|
|
61
56
|
test('constructor', () => {
|
|
62
57
|
const source = createSource({url: '/image.png'});
|
|
63
58
|
|
|
@@ -72,7 +67,7 @@ describe('ImageSource', () => {
|
|
|
72
67
|
expect(e.dataType).toBe('source');
|
|
73
68
|
});
|
|
74
69
|
source.onAdd(new StubMap() as any);
|
|
75
|
-
respond();
|
|
70
|
+
server.respond();
|
|
76
71
|
expect(source.image).toBeTruthy();
|
|
77
72
|
});
|
|
78
73
|
|
|
@@ -81,7 +76,7 @@ describe('ImageSource', () => {
|
|
|
81
76
|
const map = new StubMap() as any;
|
|
82
77
|
const spy = jest.spyOn(map._requestManager, 'transformRequest');
|
|
83
78
|
source.onAdd(map);
|
|
84
|
-
respond();
|
|
79
|
+
server.respond();
|
|
85
80
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
86
81
|
expect(spy.mock.calls[0][0]).toBe('/image.png');
|
|
87
82
|
expect(spy.mock.calls[0][1]).toBe('Image');
|
|
@@ -92,12 +87,12 @@ describe('ImageSource', () => {
|
|
|
92
87
|
const map = new StubMap() as any;
|
|
93
88
|
const spy = jest.spyOn(map._requestManager, 'transformRequest');
|
|
94
89
|
source.onAdd(map);
|
|
95
|
-
respond();
|
|
90
|
+
server.respond();
|
|
96
91
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
97
92
|
expect(spy.mock.calls[0][0]).toBe('/image.png');
|
|
98
93
|
expect(spy.mock.calls[0][1]).toBe('Image');
|
|
99
94
|
source.updateImage({url: '/image2.png'});
|
|
100
|
-
respond();
|
|
95
|
+
server.respond();
|
|
101
96
|
expect(spy).toHaveBeenCalledTimes(2);
|
|
102
97
|
expect(spy.mock.calls[1][0]).toBe('/image2.png');
|
|
103
98
|
expect(spy.mock.calls[1][1]).toBe('Image');
|
|
@@ -107,7 +102,7 @@ describe('ImageSource', () => {
|
|
|
107
102
|
const source = createSource({url: '/image.png'});
|
|
108
103
|
const map = new StubMap() as any;
|
|
109
104
|
source.onAdd(map);
|
|
110
|
-
respond();
|
|
105
|
+
server.respond();
|
|
111
106
|
const beforeSerialized = source.serialize();
|
|
112
107
|
expect(beforeSerialized.coordinates).toEqual([[0, 0], [1, 0], [1, 1], [0, 1]]);
|
|
113
108
|
source.setCoordinates([[0, 0], [-1, 0], [-1, -1], [0, -1]]);
|
|
@@ -119,14 +114,14 @@ describe('ImageSource', () => {
|
|
|
119
114
|
const source = createSource({url: '/image.png'});
|
|
120
115
|
const map = new StubMap() as any;
|
|
121
116
|
source.onAdd(map);
|
|
122
|
-
respond();
|
|
117
|
+
server.respond();
|
|
123
118
|
const beforeSerialized = source.serialize();
|
|
124
119
|
expect(beforeSerialized.coordinates).toEqual([[0, 0], [1, 0], [1, 1], [0, 1]]);
|
|
125
120
|
source.updateImage({
|
|
126
121
|
url: '/image2.png',
|
|
127
122
|
coordinates: [[0, 0], [-1, 0], [-1, -1], [0, -1]]
|
|
128
123
|
});
|
|
129
|
-
respond();
|
|
124
|
+
server.respond();
|
|
130
125
|
const afterSerialized = source.serialize();
|
|
131
126
|
expect(afterSerialized.coordinates).toEqual([[0, 0], [-1, 0], [-1, -1], [0, -1]]);
|
|
132
127
|
});
|
|
@@ -140,7 +135,7 @@ describe('ImageSource', () => {
|
|
|
140
135
|
}
|
|
141
136
|
});
|
|
142
137
|
source.onAdd(new StubMap() as any);
|
|
143
|
-
respond();
|
|
138
|
+
server.respond();
|
|
144
139
|
});
|
|
145
140
|
|
|
146
141
|
test('fires data event when metadata is loaded', done => {
|
|
@@ -151,7 +146,7 @@ describe('ImageSource', () => {
|
|
|
151
146
|
}
|
|
152
147
|
});
|
|
153
148
|
source.onAdd(new StubMap() as any);
|
|
154
|
-
respond();
|
|
149
|
+
server.respond();
|
|
155
150
|
});
|
|
156
151
|
|
|
157
152
|
test('fires idle event on prepare call when there is at least one not loaded tile', done => {
|
|
@@ -164,7 +159,7 @@ describe('ImageSource', () => {
|
|
|
164
159
|
}
|
|
165
160
|
});
|
|
166
161
|
source.onAdd(new StubMap() as any);
|
|
167
|
-
respond();
|
|
162
|
+
server.respond();
|
|
168
163
|
|
|
169
164
|
source.tiles[String(tile.tileID.wrap)] = tile;
|
|
170
165
|
source.image = new ImageBitmap();
|
|
@@ -190,10 +185,9 @@ describe('ImageSource', () => {
|
|
|
190
185
|
|
|
191
186
|
source.onAdd(map);
|
|
192
187
|
|
|
193
|
-
requests.shift();
|
|
194
188
|
expect(source.image).toBeUndefined();
|
|
195
189
|
source.updateImage({url: '/image2.png'});
|
|
196
|
-
respond();
|
|
190
|
+
server.respond();
|
|
197
191
|
expect(source.image).toBeTruthy();
|
|
198
192
|
});
|
|
199
193
|
|
|
@@ -203,8 +197,7 @@ describe('ImageSource', () => {
|
|
|
203
197
|
|
|
204
198
|
source.onAdd(map);
|
|
205
199
|
|
|
206
|
-
const
|
|
207
|
-
const spy = jest.spyOn(request, 'abort');
|
|
200
|
+
const spy = jest.spyOn(server.requests[0] as any, 'abort');
|
|
208
201
|
|
|
209
202
|
source.updateImage({url: '/image2.png'});
|
|
210
203
|
expect(spy).toHaveBeenCalled();
|
|
@@ -8,6 +8,7 @@ import {OverscaledTileID} from './tile_id';
|
|
|
8
8
|
import {RasterTileSource} from './raster_tile_source';
|
|
9
9
|
// ensure DEMData is registered for worker transfer on main thread:
|
|
10
10
|
import '../data/dem_data';
|
|
11
|
+
import type {DEMEncoding} from '../data/dem_data';
|
|
11
12
|
|
|
12
13
|
import type {Source} from './source';
|
|
13
14
|
import type {Dispatcher} from '../util/dispatcher';
|
|
@@ -33,7 +34,11 @@ import type {ExpiryData} from '../util/ajax';
|
|
|
33
34
|
* @see [3D Terrain](https://maplibre.org/maplibre-gl-js/docs/examples/3d-terrain/)
|
|
34
35
|
*/
|
|
35
36
|
export class RasterDEMTileSource extends RasterTileSource implements Source {
|
|
36
|
-
encoding:
|
|
37
|
+
encoding: DEMEncoding;
|
|
38
|
+
redFactor?: number;
|
|
39
|
+
greenFactor?: number;
|
|
40
|
+
blueFactor?: number;
|
|
41
|
+
baseShift?: number;
|
|
37
42
|
|
|
38
43
|
constructor(id: string, options: RasterDEMSourceSpecification, dispatcher: Dispatcher, eventedParent: Evented) {
|
|
39
44
|
super(id, options, dispatcher, eventedParent);
|
|
@@ -41,6 +46,10 @@ export class RasterDEMTileSource extends RasterTileSource implements Source {
|
|
|
41
46
|
this.maxzoom = 22;
|
|
42
47
|
this._options = extend({type: 'raster-dem'}, options);
|
|
43
48
|
this.encoding = options.encoding || 'mapbox';
|
|
49
|
+
this.redFactor = options.redFactor;
|
|
50
|
+
this.greenFactor = options.greenFactor;
|
|
51
|
+
this.blueFactor = options.blueFactor;
|
|
52
|
+
this.baseShift = options.baseShift;
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
loadTile(tile: Tile, callback: Callback<void>) {
|
|
@@ -67,7 +76,11 @@ export class RasterDEMTileSource extends RasterTileSource implements Source {
|
|
|
67
76
|
coord: tile.tileID,
|
|
68
77
|
source: this.id,
|
|
69
78
|
rawImageData,
|
|
70
|
-
encoding: this.encoding
|
|
79
|
+
encoding: this.encoding,
|
|
80
|
+
redFactor: this.redFactor,
|
|
81
|
+
greenFactor: this.greenFactor,
|
|
82
|
+
blueFactor: this.blueFactor,
|
|
83
|
+
baseShift: this.baseShift
|
|
71
84
|
};
|
|
72
85
|
|
|
73
86
|
if (!tile.actor || tile.state === 'expired') {
|
|
@@ -19,10 +19,10 @@ export class RasterDEMTileWorkerSource {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
loadTile(params: WorkerDEMTileParameters, callback: WorkerDEMTileCallback) {
|
|
22
|
-
const {uid, encoding, rawImageData} = params;
|
|
22
|
+
const {uid, encoding, rawImageData, redFactor, greenFactor, blueFactor, baseShift} = params;
|
|
23
23
|
// Main thread will transfer ImageBitmap if offscreen decode with OffscreenCanvas is supported, else it will transfer an already decoded image.
|
|
24
24
|
const imagePixels = isImageBitmap(rawImageData) ? this.getImageData(rawImageData) : rawImageData as RGBAImage;
|
|
25
|
-
const dem = new DEMData(uid, imagePixels, encoding);
|
|
25
|
+
const dem = new DEMData(uid, imagePixels, encoding, redFactor, greenFactor, blueFactor, baseShift);
|
|
26
26
|
this.loaded = this.loaded || {};
|
|
27
27
|
this.loaded[uid] = dem;
|
|
28
28
|
callback(null, dem);
|
|
@@ -2,7 +2,7 @@ import {RasterTileSource} from './raster_tile_source';
|
|
|
2
2
|
import {OverscaledTileID} from './tile_id';
|
|
3
3
|
import {RequestManager} from '../util/request_manager';
|
|
4
4
|
import {Dispatcher} from '../util/dispatcher';
|
|
5
|
-
import {fakeServer, FakeServer} from 'nise';
|
|
5
|
+
import {fakeServer, type FakeServer} from 'nise';
|
|
6
6
|
import {Tile} from './tile';
|
|
7
7
|
import {stubAjaxGetImage} from '../util/test/util';
|
|
8
8
|
|
|
@@ -29,7 +29,7 @@ import type {
|
|
|
29
29
|
* ```ts
|
|
30
30
|
* map.addSource('raster-source', {
|
|
31
31
|
* 'type': 'raster',
|
|
32
|
-
* 'tiles': ['https://
|
|
32
|
+
* 'tiles': ['https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg'],
|
|
33
33
|
* 'tileSize': 256,
|
|
34
34
|
* });
|
|
35
35
|
* ```
|
|
@@ -2,7 +2,7 @@ import {TerrainSourceCache} from './terrain_source_cache';
|
|
|
2
2
|
import {Style} from '../style/style';
|
|
3
3
|
import {RequestManager} from '../util/request_manager';
|
|
4
4
|
import {Dispatcher} from '../util/dispatcher';
|
|
5
|
-
import {fakeServer, FakeServer} from 'nise';
|
|
5
|
+
import {fakeServer, type FakeServer} from 'nise';
|
|
6
6
|
import {Transform} from '../geo/transform';
|
|
7
7
|
import {Evented} from '../util/evented';
|
|
8
8
|
import {Painter} from '../render/painter';
|
|
@@ -52,7 +52,6 @@ export type VectorTileSourceOptions = VectorSourceSpecification & {
|
|
|
52
52
|
* map.getSource('some id').setTiles(['https://d25uarhxywzl1j.cloudfront.net/v0.1/{z}/{x}/{y}.mvt']);
|
|
53
53
|
* ```
|
|
54
54
|
* @see [Add a vector tile source](https://maplibre.org/maplibre-gl-js/docs/examples/vector-source/)
|
|
55
|
-
* @see [Add a third party vector tile source](https://maplibre.org/maplibre-gl-js/docs/examples/third-party/)
|
|
56
55
|
*/
|
|
57
56
|
export class VectorTileSource extends Evented implements Source {
|
|
58
57
|
type: 'vector';
|
|
@@ -4,7 +4,7 @@ import vt from '@mapbox/vector-tile';
|
|
|
4
4
|
import Protobuf from 'pbf';
|
|
5
5
|
import {VectorTileWorkerSource} from '../source/vector_tile_worker_source';
|
|
6
6
|
import {StyleLayerIndex} from '../style/style_layer_index';
|
|
7
|
-
import {fakeServer, FakeServer} from 'nise';
|
|
7
|
+
import {fakeServer, type FakeServer} from 'nise';
|
|
8
8
|
import {Actor} from '../util/actor';
|
|
9
9
|
import {TileParameters, WorkerTileParameters, WorkerTileResult} from './worker_source';
|
|
10
10
|
import {WorkerTile} from './worker_tile';
|
|
@@ -234,6 +234,50 @@ describe('vector tile worker source', () => {
|
|
|
234
234
|
|
|
235
235
|
});
|
|
236
236
|
|
|
237
|
+
test('VectorTileWorkerSource#returns a good error message when failing to parse a tile', () => {
|
|
238
|
+
const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
|
|
239
|
+
const parse = jest.fn();
|
|
240
|
+
const callback = jest.fn();
|
|
241
|
+
|
|
242
|
+
server.respondWith(request => {
|
|
243
|
+
request.respond(200, {'Content-Type': 'application/pbf'}, 'something...');
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
source.loadTile({
|
|
247
|
+
source: 'source',
|
|
248
|
+
uid: 0,
|
|
249
|
+
tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}},
|
|
250
|
+
request: {url: 'http://localhost:2900/faketile.pbf'}
|
|
251
|
+
} as any as WorkerTileParameters, callback);
|
|
252
|
+
|
|
253
|
+
server.respond();
|
|
254
|
+
|
|
255
|
+
expect(parse).not.toHaveBeenCalled();
|
|
256
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
257
|
+
expect(callback.mock.calls[0][0].message).toContain('Unable to parse the tile at');
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test('VectorTileWorkerSource#returns a good error message when failing to parse a gzipped tile', () => {
|
|
261
|
+
const source = new VectorTileWorkerSource(actor, new StyleLayerIndex(), []);
|
|
262
|
+
const parse = jest.fn();
|
|
263
|
+
const callback = jest.fn();
|
|
264
|
+
|
|
265
|
+
server.respondWith(new Uint8Array([0x1f, 0x8b]).buffer);
|
|
266
|
+
|
|
267
|
+
source.loadTile({
|
|
268
|
+
source: 'source',
|
|
269
|
+
uid: 0,
|
|
270
|
+
tileID: {overscaledZ: 0, wrap: 0, canonical: {x: 0, y: 0, z: 0, w: 0}},
|
|
271
|
+
request: {url: 'http://localhost:2900/faketile.pbf'}
|
|
272
|
+
} as any as WorkerTileParameters, callback);
|
|
273
|
+
|
|
274
|
+
server.respond();
|
|
275
|
+
|
|
276
|
+
expect(parse).not.toHaveBeenCalled();
|
|
277
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
278
|
+
expect(callback.mock.calls[0][0].message).toContain('gzipped');
|
|
279
|
+
});
|
|
280
|
+
|
|
237
281
|
test('VectorTileWorkerSource provides resource timing information', done => {
|
|
238
282
|
const rawTileData = fs.readFileSync(path.join(__dirname, '/../../test/unit/assets/mbsv5-6-18-23.vector.pbf'));
|
|
239
283
|
|
|
@@ -46,12 +46,25 @@ function loadVectorTile(params: WorkerTileParameters, callback: LoadVectorDataCa
|
|
|
46
46
|
if (err) {
|
|
47
47
|
callback(err);
|
|
48
48
|
} else if (data) {
|
|
49
|
-
|
|
50
|
-
vectorTile
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
try {
|
|
50
|
+
const vectorTile = new vt.VectorTile(new Protobuf(data));
|
|
51
|
+
callback(null, {
|
|
52
|
+
vectorTile,
|
|
53
|
+
rawData: data,
|
|
54
|
+
cacheControl,
|
|
55
|
+
expires
|
|
56
|
+
});
|
|
57
|
+
} catch (ex) {
|
|
58
|
+
const bytes = new Uint8Array(data);
|
|
59
|
+
const isGzipped = bytes[0] === 0x1f && bytes[1] === 0x8b;
|
|
60
|
+
let errorMessage = `Unable to parse the tile at ${params.request.url}, `;
|
|
61
|
+
if (isGzipped) {
|
|
62
|
+
errorMessage += 'please make sure the data is not gzipped and that you have configured the relevant header in the server';
|
|
63
|
+
} else {
|
|
64
|
+
errorMessage += `got error: ${ex.messge}`;
|
|
65
|
+
}
|
|
66
|
+
callback(new Error(errorMessage));
|
|
67
|
+
}
|
|
55
68
|
}
|
|
56
69
|
});
|
|
57
70
|
return () => {
|
|
@@ -48,6 +48,10 @@ import type {VideoSourceSpecification} from '@maplibre/maplibre-gl-style-spec';
|
|
|
48
48
|
* map.removeSource('some id'); // remove
|
|
49
49
|
* ```
|
|
50
50
|
* @see [Add a video](https://maplibre.org/maplibre-gl-js/docs/examples/video-on-a-map/)
|
|
51
|
+
*
|
|
52
|
+
* Note that when rendered as a raster layer, the layer's `raster-fade-duration` property will cause the video to fade in.
|
|
53
|
+
* This happens when playback is started, paused and resumed, or when the video's coordinates are updated. To avoid this behavior,
|
|
54
|
+
* set the layer's `raster-fade-duration` property to `0`.
|
|
51
55
|
*/
|
|
52
56
|
export class VideoSource extends ImageSource {
|
|
53
57
|
options: VideoSourceSpecification;
|
|
@@ -6,7 +6,7 @@ import type {OverscaledTileID} from './tile_id';
|
|
|
6
6
|
import type {Bucket} from '../data/bucket';
|
|
7
7
|
import type {FeatureIndex} from '../data/feature_index';
|
|
8
8
|
import type {CollisionBoxArray} from '../data/array_types.g';
|
|
9
|
-
import type {DEMData} from '../data/dem_data';
|
|
9
|
+
import type {DEMData, DEMEncoding} from '../data/dem_data';
|
|
10
10
|
import type {StyleGlyph} from '../style/style_glyph';
|
|
11
11
|
import type {StyleImage} from '../style/style_image';
|
|
12
12
|
import type {PromoteIdSpecification} from '@maplibre/maplibre-gl-style-spec';
|
|
@@ -37,7 +37,11 @@ export type WorkerDEMTileParameters = TileParameters & {
|
|
|
37
37
|
w: number;
|
|
38
38
|
};
|
|
39
39
|
rawImageData: RGBAImage | ImageBitmap;
|
|
40
|
-
encoding:
|
|
40
|
+
encoding: DEMEncoding;
|
|
41
|
+
redFactor: number;
|
|
42
|
+
greenFactor: number;
|
|
43
|
+
blueFactor: number;
|
|
44
|
+
baseShift: number;
|
|
41
45
|
};
|
|
42
46
|
|
|
43
47
|
/**
|
|
@@ -2,7 +2,8 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import {RequestManager} from '../util/request_manager';
|
|
4
4
|
import {loadGlyphRange} from './load_glyph_range';
|
|
5
|
-
import {
|
|
5
|
+
import {fakeServer} from 'nise';
|
|
6
|
+
import {bufferToArrayBuffer} from '../util/test/util';
|
|
6
7
|
|
|
7
8
|
test('loadGlyphRange', done => {
|
|
8
9
|
global.fetch = null;
|
|
@@ -13,8 +14,8 @@ test('loadGlyphRange', done => {
|
|
|
13
14
|
|
|
14
15
|
const manager = new RequestManager(transform);
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
const server = fakeServer.create();
|
|
18
|
+
server.respondWith(bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/0-255.pbf'))));
|
|
18
19
|
|
|
19
20
|
loadGlyphRange('Arial Unicode MS', 0, 'https://localhost/fonts/v1/{fontstack}/{range}.pbf', manager, (err, result) => {
|
|
20
21
|
expect(err).toBeFalsy();
|
|
@@ -35,9 +36,6 @@ test('loadGlyphRange', done => {
|
|
|
35
36
|
}
|
|
36
37
|
done();
|
|
37
38
|
});
|
|
38
|
-
|
|
39
|
-
expect(
|
|
40
|
-
request.setStatus(200);
|
|
41
|
-
request.response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/0-255.pbf'));
|
|
42
|
-
request.onload();
|
|
39
|
+
server.respond();
|
|
40
|
+
expect(server.requests[0].url).toBe('https://localhost/fonts/v1/Arial Unicode MS/0-255.pbf');
|
|
43
41
|
});
|
|
@@ -2,18 +2,25 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import {RequestManager} from '../util/request_manager';
|
|
4
4
|
import {loadSprite} from './load_sprite';
|
|
5
|
-
import {
|
|
5
|
+
import {type FakeServer, fakeServer} from 'nise';
|
|
6
6
|
import * as util from '../util/util';
|
|
7
|
+
import {bufferToArrayBuffer} from '../util/test/util';
|
|
7
8
|
|
|
8
9
|
describe('loadSprite', () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
|
|
11
|
+
let server: FakeServer;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
jest.spyOn(util, 'arrayBufferToImageBitmap').mockImplementation((data: ArrayBuffer, callback: (err?: Error | null, image?: ImageBitmap | null) => void) => {
|
|
15
|
+
createImageBitmap(new ImageData(1024, 824)).then((imgBitmap) => {
|
|
16
|
+
callback(null, imgBitmap);
|
|
17
|
+
}).catch((e) => {
|
|
18
|
+
callback(new Error(`Could not load image because of ${e.message}. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.`));
|
|
19
|
+
});
|
|
14
20
|
});
|
|
21
|
+
global.fetch = null;
|
|
22
|
+
server = fakeServer.create();
|
|
15
23
|
});
|
|
16
|
-
global.fetch = null;
|
|
17
24
|
|
|
18
25
|
test('backwards compatibility: single string is treated as a URL for the default sprite', done => {
|
|
19
26
|
const transform = jest.fn().mockImplementation((url, type) => {
|
|
@@ -22,8 +29,8 @@ describe('loadSprite', () => {
|
|
|
22
29
|
|
|
23
30
|
const manager = new RequestManager(transform);
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString());
|
|
33
|
+
server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png'))));
|
|
27
34
|
|
|
28
35
|
loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 1, (err, result) => {
|
|
29
36
|
expect(err).toBeFalsy();
|
|
@@ -43,15 +50,10 @@ describe('loadSprite', () => {
|
|
|
43
50
|
done();
|
|
44
51
|
});
|
|
45
52
|
|
|
46
|
-
|
|
47
|
-
requests[0].setStatus(200);
|
|
48
|
-
requests[0].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json'));
|
|
49
|
-
requests[0].onload();
|
|
53
|
+
server.respond();
|
|
50
54
|
|
|
51
|
-
expect(requests[
|
|
52
|
-
requests[1].
|
|
53
|
-
requests[1].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')).buffer;
|
|
54
|
-
requests[1].onload();
|
|
55
|
+
expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
|
|
56
|
+
expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
|
|
55
57
|
});
|
|
56
58
|
|
|
57
59
|
test('array of objects support', done => {
|
|
@@ -61,8 +63,10 @@ describe('loadSprite', () => {
|
|
|
61
63
|
|
|
62
64
|
const manager = new RequestManager(transform);
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString());
|
|
67
|
+
server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png'))));
|
|
68
|
+
server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite2.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.json')).toString());
|
|
69
|
+
server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite2.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.png'))));
|
|
66
70
|
|
|
67
71
|
loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}, {id: 'sprite2', url: 'http://localhost:9966/test/unit/assets/sprite2'}], manager, 1, (err, result) => {
|
|
68
72
|
expect(err).toBeFalsy();
|
|
@@ -90,25 +94,11 @@ describe('loadSprite', () => {
|
|
|
90
94
|
done();
|
|
91
95
|
});
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
requests[0].
|
|
95
|
-
requests[
|
|
96
|
-
requests[
|
|
97
|
-
|
|
98
|
-
expect(requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
|
|
99
|
-
requests[1].setStatus(200);
|
|
100
|
-
requests[1].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')).buffer;
|
|
101
|
-
requests[1].onload();
|
|
102
|
-
|
|
103
|
-
expect(requests[2].url).toBe('http://localhost:9966/test/unit/assets/sprite2.json');
|
|
104
|
-
requests[2].setStatus(200);
|
|
105
|
-
requests[2].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.json'));
|
|
106
|
-
requests[2].onload();
|
|
107
|
-
|
|
108
|
-
expect(requests[3].url).toBe('http://localhost:9966/test/unit/assets/sprite2.png');
|
|
109
|
-
requests[3].setStatus(200);
|
|
110
|
-
requests[3].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite2.png')).buffer;
|
|
111
|
-
requests[3].onload();
|
|
97
|
+
server.respond();
|
|
98
|
+
expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
|
|
99
|
+
expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
|
|
100
|
+
expect(server.requests[2].url).toBe('http://localhost:9966/test/unit/assets/sprite2.json');
|
|
101
|
+
expect(server.requests[3].url).toBe('http://localhost:9966/test/unit/assets/sprite2.png');
|
|
112
102
|
});
|
|
113
103
|
|
|
114
104
|
test('error in callback', done => {
|
|
@@ -118,20 +108,19 @@ describe('loadSprite', () => {
|
|
|
118
108
|
|
|
119
109
|
const manager = new RequestManager(transform);
|
|
120
110
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
111
|
+
server.respondWith((xhr) => xhr.respond(500));
|
|
112
|
+
let last = false;
|
|
124
113
|
loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}], manager, 1, (err, result) => {
|
|
125
114
|
expect(err).toBeTruthy();
|
|
126
115
|
expect(result).toBeUndefined();
|
|
127
|
-
|
|
128
|
-
|
|
116
|
+
if (!last) {
|
|
117
|
+
done();
|
|
118
|
+
last = true;
|
|
119
|
+
}
|
|
129
120
|
});
|
|
130
121
|
|
|
131
|
-
|
|
132
|
-
requests[0].
|
|
133
|
-
requests[0].response = undefined;
|
|
134
|
-
requests[0].onload();
|
|
122
|
+
server.respond();
|
|
123
|
+
expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
|
|
135
124
|
});
|
|
136
125
|
|
|
137
126
|
test('request canceling', done => {
|
|
@@ -141,30 +130,24 @@ describe('loadSprite', () => {
|
|
|
141
130
|
|
|
142
131
|
const manager = new RequestManager(transform);
|
|
143
132
|
|
|
144
|
-
|
|
145
|
-
|
|
133
|
+
server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString());
|
|
134
|
+
server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png'))));
|
|
146
135
|
|
|
147
136
|
const cancelable = loadSprite([{id: 'sprite1', url: 'http://localhost:9966/test/unit/assets/sprite1'}], manager, 1, () => {});
|
|
148
137
|
|
|
149
138
|
setTimeout(() => {
|
|
150
139
|
cancelable.cancel();
|
|
151
140
|
|
|
152
|
-
expect(requests[0].aborted).toBeTruthy();
|
|
153
|
-
expect(requests[1].aborted).toBeTruthy();
|
|
141
|
+
expect((server.requests[0] as any).aborted).toBeTruthy();
|
|
142
|
+
expect((server.requests[1] as any).aborted).toBeTruthy();
|
|
154
143
|
|
|
155
144
|
done();
|
|
156
145
|
});
|
|
157
146
|
|
|
158
147
|
setTimeout(() => {
|
|
159
|
-
|
|
160
|
-
requests[0].
|
|
161
|
-
requests[
|
|
162
|
-
requests[0].onload();
|
|
163
|
-
|
|
164
|
-
expect(requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
|
|
165
|
-
requests[1].setStatus(200);
|
|
166
|
-
requests[1].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')).buffer;
|
|
167
|
-
requests[1].onload();
|
|
148
|
+
server.respond();
|
|
149
|
+
expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1.json');
|
|
150
|
+
expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1.png');
|
|
168
151
|
}, 10);
|
|
169
152
|
});
|
|
170
153
|
|
|
@@ -175,8 +158,8 @@ describe('loadSprite', () => {
|
|
|
175
158
|
|
|
176
159
|
const manager = new RequestManager(transform);
|
|
177
160
|
|
|
178
|
-
|
|
179
|
-
|
|
161
|
+
server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1@2x.json', fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.json')).toString());
|
|
162
|
+
server.respondWith('GET', 'http://localhost:9966/test/unit/assets/sprite1@2x.png', bufferToArrayBuffer(fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png'))));
|
|
180
163
|
|
|
181
164
|
loadSprite('http://localhost:9966/test/unit/assets/sprite1', manager, 2, (err, result) => {
|
|
182
165
|
expect(err).toBeFalsy();
|
|
@@ -196,14 +179,8 @@ describe('loadSprite', () => {
|
|
|
196
179
|
done();
|
|
197
180
|
});
|
|
198
181
|
|
|
199
|
-
|
|
200
|
-
requests[0].
|
|
201
|
-
requests[
|
|
202
|
-
requests[0].onload();
|
|
203
|
-
|
|
204
|
-
expect(requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.png');
|
|
205
|
-
requests[1].setStatus(200);
|
|
206
|
-
requests[1].response = fs.readFileSync(path.join(__dirname, '../../test/unit/assets/sprite1.png')).buffer;
|
|
207
|
-
requests[1].onload();
|
|
182
|
+
server.respond();
|
|
183
|
+
expect(server.requests[0].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.json');
|
|
184
|
+
expect(server.requests[1].url).toBe('http://localhost:9966/test/unit/assets/sprite1@2x.png');
|
|
208
185
|
});
|
|
209
186
|
});
|