maplibre-gl 3.3.1 → 3.4.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/README.md +1 -1
- 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 +430 -128
- package/dist/maplibre-gl-dev.js.map +1 -1
- package/dist/maplibre-gl.d.ts +18 -9
- package/dist/maplibre-gl.js +4 -4
- package/dist/maplibre-gl.js.map +1 -1
- package/package.json +41 -41
- package/src/data/dem_data.test.ts +120 -165
- package/src/data/dem_data.ts +38 -18
- package/src/render/glyph_manager.test.ts +10 -9
- package/src/render/glyph_manager.ts +17 -10
- package/src/source/image_source.test.ts +17 -24
- package/src/source/raster_dem_tile_source.ts +36 -11
- package/src/source/raster_dem_tile_worker_source.ts +9 -26
- 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_worker_source.test.ts +45 -1
- package/src/source/vector_tile_worker_source.ts +19 -6
- 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 +3 -0
- package/src/style/style_glyph.ts +4 -3
- 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/symbol/quads.ts +4 -2
- package/src/ui/handler/scroll_zoom.ts +6 -0
- package/src/ui/handler_manager.ts +2 -1
- package/src/ui/map.test.ts +17 -0
- package/src/ui/map.ts +1 -0
- package/src/ui/marker.test.ts +25 -0
- package/src/ui/marker.ts +8 -1
- package/src/util/ajax.test.ts +1 -1
- package/src/util/image_request.test.ts +1 -1
- package/src/util/offscreen_canvas_distorted.test.ts +13 -0
- package/src/util/offscreen_canvas_distorted.ts +39 -0
- package/src/util/test/util.ts +12 -0
- package/src/util/util.test.ts +171 -1
- package/src/util/util.ts +150 -0
|
@@ -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
|
});
|
package/src/style/style.test.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from '../source/rtl_text_plugin';
|
|
14
14
|
import {browser} from '../util/browser';
|
|
15
15
|
import {OverscaledTileID} from '../source/tile_id';
|
|
16
|
-
import {
|
|
16
|
+
import {fakeServer, type FakeServer} from 'nise';
|
|
17
17
|
|
|
18
18
|
import {EvaluationParameters} from './evaluation_parameters';
|
|
19
19
|
import {LayerSpecification, GeoJSONSourceSpecification, FilterSpecification, SourceSpecification} from '@maplibre/maplibre-gl-style-spec';
|
|
@@ -78,21 +78,17 @@ function createStyle(map = getStubMap()) {
|
|
|
78
78
|
return style;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
let
|
|
82
|
-
let sinonFakeServer;
|
|
81
|
+
let server: FakeServer;
|
|
83
82
|
let mockConsoleError;
|
|
84
83
|
|
|
85
84
|
beforeEach(() => {
|
|
86
85
|
global.fetch = null;
|
|
87
|
-
|
|
88
|
-
sinonFakeXMLServer = fakeXhr.useFakeXMLHttpRequest();
|
|
89
|
-
|
|
86
|
+
server = fakeServer.create();
|
|
90
87
|
mockConsoleError = jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
91
88
|
});
|
|
92
89
|
|
|
93
90
|
afterEach(() => {
|
|
94
|
-
|
|
95
|
-
sinonFakeServer.restore();
|
|
91
|
+
server.restore();
|
|
96
92
|
mockConsoleError.mockRestore();
|
|
97
93
|
});
|
|
98
94
|
|
|
@@ -115,12 +111,12 @@ describe('Style', () => {
|
|
|
115
111
|
|
|
116
112
|
test('loads plugin immediately if already registered', done => {
|
|
117
113
|
clearRTLTextPlugin();
|
|
118
|
-
|
|
114
|
+
server.respondWith('/plugin.js', 'doesn\'t matter');
|
|
119
115
|
setRTLTextPlugin('/plugin.js', (error) => {
|
|
120
116
|
expect(error).toMatch(/Cannot set the state of the rtl-text-plugin when not in the web-worker context/);
|
|
121
117
|
done();
|
|
122
118
|
});
|
|
123
|
-
|
|
119
|
+
server.respond();
|
|
124
120
|
new Style(getStubMap());
|
|
125
121
|
});
|
|
126
122
|
|
|
@@ -152,7 +148,7 @@ describe('Style', () => {
|
|
|
152
148
|
jest.spyOn(style.sourceCaches['vector'], 'reload');
|
|
153
149
|
|
|
154
150
|
clearRTLTextPlugin();
|
|
155
|
-
|
|
151
|
+
server.respondWith('/plugin.js', 'doesn\'t matter');
|
|
156
152
|
const _broadcast = style.dispatcher.broadcast;
|
|
157
153
|
style.dispatcher.broadcast = function (type, state, callback) {
|
|
158
154
|
if (type === 'syncRTLPluginState') {
|
|
@@ -171,7 +167,7 @@ describe('Style', () => {
|
|
|
171
167
|
done();
|
|
172
168
|
}, 0);
|
|
173
169
|
});
|
|
174
|
-
|
|
170
|
+
server.respond();
|
|
175
171
|
});
|
|
176
172
|
});
|
|
177
173
|
});
|
|
@@ -211,15 +207,15 @@ describe('Style#loadURL', () => {
|
|
|
211
207
|
});
|
|
212
208
|
|
|
213
209
|
style.loadURL('style.json');
|
|
214
|
-
|
|
215
|
-
|
|
210
|
+
server.respondWith(JSON.stringify(createStyleJSON({version: 'invalid'})));
|
|
211
|
+
server.respond();
|
|
216
212
|
});
|
|
217
213
|
|
|
218
214
|
test('cancels pending requests if removed', () => {
|
|
219
215
|
const style = new Style(getStubMap());
|
|
220
216
|
style.loadURL('style.json');
|
|
221
217
|
style._remove();
|
|
222
|
-
expect(
|
|
218
|
+
expect((server.lastRequest as any).aborted).toBe(true);
|
|
223
219
|
});
|
|
224
220
|
});
|
|
225
221
|
|
|
@@ -266,21 +262,8 @@ describe('Style#loadJSON', () => {
|
|
|
266
262
|
// stub Image so we can invoke 'onload'
|
|
267
263
|
// https://github.com/jsdom/jsdom/commit/58a7028d0d5b6aacc5b435daee9fd8f9eacbb14c
|
|
268
264
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const requests = [];
|
|
272
|
-
sinonFakeXMLServer.onCreate = req => { requests.push(req); };
|
|
273
|
-
const respond = () => {
|
|
274
|
-
let req = requests.find(req => req.url === 'http://example.com/sprite.png');
|
|
275
|
-
req.setStatus(200);
|
|
276
|
-
req.response = new ArrayBuffer(8);
|
|
277
|
-
req.onload();
|
|
278
|
-
|
|
279
|
-
req = requests.find(req => req.url === 'http://example.com/sprite.json');
|
|
280
|
-
req.setStatus(200);
|
|
281
|
-
req.response = '{}';
|
|
282
|
-
req.onload();
|
|
283
|
-
};
|
|
265
|
+
server.respondWith('GET', 'http://example.com/sprite.png', new ArrayBuffer(8));
|
|
266
|
+
server.respondWith('GET', 'http://example.com/sprite.json', '{}');
|
|
284
267
|
|
|
285
268
|
const style = new Style(getStubMap());
|
|
286
269
|
|
|
@@ -303,7 +286,7 @@ describe('Style#loadJSON', () => {
|
|
|
303
286
|
done();
|
|
304
287
|
});
|
|
305
288
|
|
|
306
|
-
respond();
|
|
289
|
+
server.respond();
|
|
307
290
|
});
|
|
308
291
|
});
|
|
309
292
|
|
|
@@ -315,21 +298,8 @@ describe('Style#loadJSON', () => {
|
|
|
315
298
|
// stub Image so we can invoke 'onload'
|
|
316
299
|
// https://github.com/jsdom/jsdom/commit/58a7028d0d5b6aacc5b435daee9fd8f9eacbb14c
|
|
317
300
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const requests = [];
|
|
321
|
-
sinonFakeXMLServer.onCreate = req => { requests.push(req); };
|
|
322
|
-
const respond = () => {
|
|
323
|
-
let req = requests.find(req => req.url === 'http://example.com/sprite.png');
|
|
324
|
-
req.setStatus(200);
|
|
325
|
-
req.response = new ArrayBuffer(8);
|
|
326
|
-
req.onload();
|
|
327
|
-
|
|
328
|
-
req = requests.find(req => req.url === 'http://example.com/sprite.json');
|
|
329
|
-
req.setStatus(200);
|
|
330
|
-
req.response = '{"image1": {"width": 1, "height": 1, "x": 0, "y": 0, "pixelRatio": 1.0}}';
|
|
331
|
-
req.onload();
|
|
332
|
-
};
|
|
301
|
+
server.respondWith('GET', 'http://example.com/sprite.png', new ArrayBuffer(8));
|
|
302
|
+
server.respondWith('GET', 'http://example.com/sprite.json', '{"image1": {"width": 1, "height": 1, "x": 0, "y": 0, "pixelRatio": 1.0}}');
|
|
333
303
|
|
|
334
304
|
const style = new Style(getStubMap());
|
|
335
305
|
|
|
@@ -357,7 +327,7 @@ describe('Style#loadJSON', () => {
|
|
|
357
327
|
});
|
|
358
328
|
});
|
|
359
329
|
|
|
360
|
-
respond();
|
|
330
|
+
server.respond();
|
|
361
331
|
});
|
|
362
332
|
});
|
|
363
333
|
|
|
@@ -751,7 +721,7 @@ describe('Style#setState', () => {
|
|
|
751
721
|
});
|
|
752
722
|
|
|
753
723
|
test('Issue #3893: compare new source options against originally provided options rather than normalized properties', done => {
|
|
754
|
-
|
|
724
|
+
server.respondWith('/tilejson.json', JSON.stringify({
|
|
755
725
|
tiles: ['http://tiles.server']
|
|
756
726
|
}));
|
|
757
727
|
const initial = createStyleJSON();
|
|
@@ -767,7 +737,7 @@ describe('Style#setState', () => {
|
|
|
767
737
|
style.setState(initial);
|
|
768
738
|
done();
|
|
769
739
|
});
|
|
770
|
-
|
|
740
|
+
server.respond();
|
|
771
741
|
});
|
|
772
742
|
|
|
773
743
|
test('return true if there is a change', done => {
|
package/src/style/style.ts
CHANGED
package/src/style/style_glyph.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type {AlphaImage} from '../util/image';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* The glyph's metrices
|
|
5
|
-
*/
|
|
6
3
|
export type GlyphMetrics = {
|
|
7
4
|
width: number;
|
|
8
5
|
height: number;
|
|
9
6
|
left: number;
|
|
10
7
|
top: number;
|
|
11
8
|
advance: number;
|
|
9
|
+
/**
|
|
10
|
+
* isDoubleResolution = true for 48px textures
|
|
11
|
+
*/
|
|
12
|
+
isDoubleResolution?: boolean;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {createStyleLayer} from '../create_style_layer';
|
|
2
|
+
import {extend} from '../../util/util';
|
|
3
|
+
import {LineStyleLayer} from './line_style_layer';
|
|
4
|
+
|
|
5
|
+
describe('LineStyleLayer', () => {
|
|
6
|
+
function createLineLayer(layer?) {
|
|
7
|
+
return extend({
|
|
8
|
+
type: 'line',
|
|
9
|
+
source: 'line',
|
|
10
|
+
id: 'line',
|
|
11
|
+
paint: {
|
|
12
|
+
'line-color': 'red',
|
|
13
|
+
'line-width': 14,
|
|
14
|
+
'line-gradient': [
|
|
15
|
+
'interpolate',
|
|
16
|
+
['linear'],
|
|
17
|
+
['line-progress'],
|
|
18
|
+
0,
|
|
19
|
+
'blue',
|
|
20
|
+
1,
|
|
21
|
+
'red'
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
}, layer);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
test('updating with valid line-gradient updates this.gradientVersion', () => {
|
|
28
|
+
const lineLayer = createStyleLayer(createLineLayer()) as LineStyleLayer;
|
|
29
|
+
const gradientVersion = lineLayer.gradientVersion;
|
|
30
|
+
|
|
31
|
+
lineLayer.setPaintProperty('line-gradient', [
|
|
32
|
+
'interpolate',
|
|
33
|
+
['linear'],
|
|
34
|
+
['line-progress'],
|
|
35
|
+
0,
|
|
36
|
+
'red',
|
|
37
|
+
1,
|
|
38
|
+
'blue'
|
|
39
|
+
]);
|
|
40
|
+
expect(lineLayer.gradientVersion).toBeGreaterThan(gradientVersion);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('updating with invalid line-gradient updates this.gradientVersion', () => {
|
|
44
|
+
const lineLayer = createStyleLayer(createLineLayer()) as LineStyleLayer;
|
|
45
|
+
const gradientVersion = lineLayer.gradientVersion;
|
|
46
|
+
|
|
47
|
+
lineLayer.setPaintProperty('line-gradient', null);
|
|
48
|
+
expect(lineLayer.gradientVersion).toBeGreaterThan(gradientVersion);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -9,8 +9,8 @@ import {extend} from '../../util/util';
|
|
|
9
9
|
import {EvaluationParameters} from '../evaluation_parameters';
|
|
10
10
|
import {Transitionable, Transitioning, Layout, PossiblyEvaluated, DataDrivenProperty} from '../properties';
|
|
11
11
|
|
|
12
|
-
import {Step} from '@maplibre/maplibre-gl-style-spec';
|
|
13
|
-
import type {FeatureState,
|
|
12
|
+
import {isZoomExpression, Step} from '@maplibre/maplibre-gl-style-spec';
|
|
13
|
+
import type {FeatureState, LayerSpecification} from '@maplibre/maplibre-gl-style-spec';
|
|
14
14
|
import type {Bucket, BucketParameters} from '../../data/bucket';
|
|
15
15
|
import type {LineLayoutProps, LinePaintProps} from './line_style_layer_properties.g';
|
|
16
16
|
import type {Transform} from '../../geo/transform';
|
|
@@ -60,8 +60,12 @@ export class LineStyleLayer extends StyleLayer {
|
|
|
60
60
|
|
|
61
61
|
_handleSpecialPaintPropertyUpdate(name: string) {
|
|
62
62
|
if (name === 'line-gradient') {
|
|
63
|
-
const expression
|
|
64
|
-
|
|
63
|
+
const expression = this.gradientExpression();
|
|
64
|
+
if (isZoomExpression(expression)) {
|
|
65
|
+
this.stepInterpolant = expression._styleExpression.expression instanceof Step;
|
|
66
|
+
} else {
|
|
67
|
+
this.stepInterpolant = false;
|
|
68
|
+
}
|
|
65
69
|
this.gradientVersion = (this.gradientVersion + 1) % Number.MAX_SAFE_INTEGER;
|
|
66
70
|
}
|
|
67
71
|
}
|
package/src/symbol/quads.ts
CHANGED
|
@@ -274,10 +274,12 @@ export function getGlyphQuads(
|
|
|
274
274
|
builtInOffset = [0, 0];
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
const textureScale = positionedGlyph.metrics.isDoubleResolution ? 2 : 1;
|
|
278
|
+
|
|
277
279
|
const x1 = (positionedGlyph.metrics.left - rectBuffer) * positionedGlyph.scale - halfAdvance + builtInOffset[0];
|
|
278
280
|
const y1 = (-positionedGlyph.metrics.top - rectBuffer) * positionedGlyph.scale + builtInOffset[1];
|
|
279
|
-
const x2 = x1 + textureRect.w * positionedGlyph.scale / pixelRatio;
|
|
280
|
-
const y2 = y1 + textureRect.h * positionedGlyph.scale / pixelRatio;
|
|
281
|
+
const x2 = x1 + textureRect.w / textureScale * positionedGlyph.scale / pixelRatio;
|
|
282
|
+
const y2 = y1 + textureRect.h / textureScale * positionedGlyph.scale / pixelRatio;
|
|
281
283
|
|
|
282
284
|
const tl = new Point(x1, y1);
|
|
283
285
|
const tr = new Point(x2, y1);
|
|
@@ -351,5 +351,11 @@ export class ScrollZoomHandler implements Handler {
|
|
|
351
351
|
|
|
352
352
|
reset() {
|
|
353
353
|
this._active = false;
|
|
354
|
+
this._zooming = false;
|
|
355
|
+
delete this._targetZoom;
|
|
356
|
+
if (this._finishTimeout) {
|
|
357
|
+
clearTimeout(this._finishTimeout);
|
|
358
|
+
delete this._finishTimeout;
|
|
359
|
+
}
|
|
354
360
|
}
|
|
355
361
|
}
|
|
@@ -17,6 +17,7 @@ import {DragPanHandler} from './handler/shim/drag_pan';
|
|
|
17
17
|
import {DragRotateHandler} from './handler/shim/drag_rotate';
|
|
18
18
|
import {TwoFingersTouchZoomRotateHandler} from './handler/shim/two_fingers_touch';
|
|
19
19
|
import {extend} from '../util/util';
|
|
20
|
+
import {browser} from '../util/browser';
|
|
20
21
|
import Point from '@mapbox/point-geometry';
|
|
21
22
|
|
|
22
23
|
export type InputEvent = MouseEvent | TouchEvent | KeyboardEvent | WheelEvent;
|
|
@@ -583,7 +584,7 @@ export class HandlerManager {
|
|
|
583
584
|
|
|
584
585
|
const shouldSnapToNorth = bearing => bearing !== 0 && -this._bearingSnap < bearing && bearing < this._bearingSnap;
|
|
585
586
|
|
|
586
|
-
if (inertialEase) {
|
|
587
|
+
if (inertialEase && (inertialEase.essential || !browser.prefersReducedMotion)) {
|
|
587
588
|
if (shouldSnapToNorth(inertialEase.bearing || this._map.getBearing())) {
|
|
588
589
|
inertialEase.bearing = 0;
|
|
589
590
|
}
|
package/src/ui/map.test.ts
CHANGED
|
@@ -288,6 +288,23 @@ describe('Map', () => {
|
|
|
288
288
|
|
|
289
289
|
});
|
|
290
290
|
|
|
291
|
+
test('setStyle back to the first style should work', done => {
|
|
292
|
+
const redStyle = {version: 8 as const, sources: {}, layers: [
|
|
293
|
+
{id: 'background', type: 'background' as const, paint: {'background-color': 'red'}},
|
|
294
|
+
]};
|
|
295
|
+
const blueStyle = {version: 8 as const, sources: {}, layers: [
|
|
296
|
+
{id: 'background', type: 'background' as const, paint: {'background-color': 'blue'}},
|
|
297
|
+
]};
|
|
298
|
+
const map = createMap({style: redStyle});
|
|
299
|
+
map.setStyle(blueStyle);
|
|
300
|
+
map.once('style.load', () => {
|
|
301
|
+
map.setStyle(redStyle);
|
|
302
|
+
const serializedStyle = map.style.serialize();
|
|
303
|
+
expect(serializedStyle.layers[0].paint['background-color']).toBe('red');
|
|
304
|
+
done();
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
291
308
|
test('style transform overrides unmodified map transform', done => {
|
|
292
309
|
const map = new Map({container: window.document.createElement('div')} as any as MapOptions);
|
|
293
310
|
map.transform.lngRange = [-120, 140];
|
package/src/ui/map.ts
CHANGED
|
@@ -2562,6 +2562,7 @@ export class Map extends Camera {
|
|
|
2562
2562
|
* @param name - The name of the paint property to set.
|
|
2563
2563
|
* @param value - The value of the paint property to set.
|
|
2564
2564
|
* Must be of a type appropriate for the property, as defined in the [MapLibre Style Specification](https://maplibre.org/maplibre-style-spec/).
|
|
2565
|
+
* Pass `null` to unset the existing value.
|
|
2565
2566
|
* @param options - Options object.
|
|
2566
2567
|
* @returns `this`
|
|
2567
2568
|
* @example
|
package/src/ui/marker.test.ts
CHANGED
|
@@ -811,4 +811,29 @@ describe('marker', () => {
|
|
|
811
811
|
|
|
812
812
|
map.remove();
|
|
813
813
|
});
|
|
814
|
+
|
|
815
|
+
test('Marker after the terrain event must listen to the render event till is fully loaded', async () => {
|
|
816
|
+
const map = createMap();
|
|
817
|
+
|
|
818
|
+
new Marker()
|
|
819
|
+
.setLngLat([1, 1])
|
|
820
|
+
.addTo(map);
|
|
821
|
+
|
|
822
|
+
expect(map._oneTimeListeners.render).toBeUndefined();
|
|
823
|
+
|
|
824
|
+
map.fire('terrain');
|
|
825
|
+
expect(map._oneTimeListeners.render).toHaveLength(1);
|
|
826
|
+
|
|
827
|
+
map.fire('render');
|
|
828
|
+
expect(map._oneTimeListeners.render).toHaveLength(1);
|
|
829
|
+
|
|
830
|
+
map.fire('render');
|
|
831
|
+
expect(map._oneTimeListeners.render).toHaveLength(1);
|
|
832
|
+
|
|
833
|
+
// await idle to be fully loaded
|
|
834
|
+
await map.once('idle');
|
|
835
|
+
map.fire('render');
|
|
836
|
+
expect(map._oneTimeListeners.render).toHaveLength(0);
|
|
837
|
+
map.remove();
|
|
838
|
+
});
|
|
814
839
|
});
|
package/src/ui/marker.ts
CHANGED
|
@@ -297,6 +297,8 @@ export class Marker extends Evented {
|
|
|
297
297
|
map.getCanvasContainer().appendChild(this._element);
|
|
298
298
|
map.on('move', this._update);
|
|
299
299
|
map.on('moveend', this._update);
|
|
300
|
+
map.on('terrain', this._update);
|
|
301
|
+
|
|
300
302
|
this.setDraggable(this._draggable);
|
|
301
303
|
this._update();
|
|
302
304
|
|
|
@@ -504,9 +506,14 @@ export class Marker extends Evented {
|
|
|
504
506
|
return this;
|
|
505
507
|
}
|
|
506
508
|
|
|
507
|
-
_update = (e?: { type: 'move' | 'moveend' }) => {
|
|
509
|
+
_update = (e?: { type: 'move' | 'moveend' | 'terrain' | 'render' }) => {
|
|
508
510
|
if (!this._map) return;
|
|
509
511
|
|
|
512
|
+
const isFullyLoaded = this._map.loaded() && !this._map.isMoving();
|
|
513
|
+
if (e?.type === 'terrain' || (e?.type === 'render' && !isFullyLoaded)) {
|
|
514
|
+
this._map.once('render', this._update);
|
|
515
|
+
}
|
|
516
|
+
|
|
510
517
|
if (this._map.transform.renderWorldCopies) {
|
|
511
518
|
this._lngLat = smartWrap(this._lngLat, this._pos, this._map.transform);
|
|
512
519
|
}
|
package/src/util/ajax.test.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
sameOrigin
|
|
7
7
|
} from './ajax';
|
|
8
8
|
|
|
9
|
-
import {fakeServer, FakeServer} from 'nise';
|
|
9
|
+
import {fakeServer, type FakeServer} from 'nise';
|
|
10
10
|
import {destroyFetchMock, FetchMock, RequestMock, setupFetchMock} from './test/mock_fetch';
|
|
11
11
|
|
|
12
12
|
function readAsText(blob) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {config} from './config';
|
|
2
2
|
import {webpSupported} from './webp_supported';
|
|
3
3
|
import {stubAjaxGetImage} from './test/util';
|
|
4
|
-
import {fakeServer, FakeServer} from 'nise';
|
|
4
|
+
import {fakeServer, type FakeServer} from 'nise';
|
|
5
5
|
import {ImageRequest, ImageRequestQueueItem} from './image_request';
|
|
6
6
|
import * as ajax from './ajax';
|
|
7
7
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {isOffscreenCanvasDistorted} from './offscreen_canvas_distorted';
|
|
2
|
+
import {Canvas} from 'canvas';
|
|
3
|
+
import {offscreenCanvasSupported} from './offscreen_canvas_supported';
|
|
4
|
+
|
|
5
|
+
test('normal operation does not mangle canvas', () => {
|
|
6
|
+
const OffscreenCanvas = (window as any).OffscreenCanvas = jest.fn((width:number, height: number) => {
|
|
7
|
+
return new Canvas(width, height);
|
|
8
|
+
});
|
|
9
|
+
expect(offscreenCanvasSupported()).toBeTruthy();
|
|
10
|
+
OffscreenCanvas.mockClear();
|
|
11
|
+
expect(isOffscreenCanvasDistorted()).toBeFalsy();
|
|
12
|
+
expect(OffscreenCanvas).toHaveBeenCalledTimes(1);
|
|
13
|
+
});
|