maplibre-gl 3.5.1 → 3.5.2
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.ts +9 -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 +77 -71
- package/dist/maplibre-gl-dev.js.map +1 -1
- package/dist/maplibre-gl.d.ts +139 -63
- package/dist/maplibre-gl.js +4 -4
- package/dist/maplibre-gl.js.map +1 -1
- package/package.json +26 -25
- package/src/data/bucket/symbol_bucket.ts +1 -1
- package/src/data/bucket.ts +1 -1
- package/src/data/evaluation_feature.ts +2 -14
- package/src/gl/webgl2.ts +1 -1
- package/src/source/geojson_worker_source.ts +39 -45
- package/src/source/geojson_wrapper.ts +5 -15
- package/src/source/worker.test.ts +2 -1
- package/src/source/worker.ts +9 -9
- package/src/style/style.test.ts +27 -0
- package/src/style/style.ts +3 -1
- package/src/util/actor.test.ts +11 -9
- package/src/util/actor.ts +81 -42
- package/src/util/dispatcher.test.ts +7 -8
- package/src/util/dispatcher.ts +5 -12
- package/src/util/web_worker.ts +0 -15
- package/src/util/web_worker_transfer.ts +4 -5
- package/src/util/worker_pool.ts +3 -3
package/src/util/actor.ts
CHANGED
|
@@ -1,9 +1,57 @@
|
|
|
1
|
-
import {isWorker
|
|
2
|
-
import {serialize, deserialize} from './web_worker_transfer';
|
|
1
|
+
import {isWorker} from './util';
|
|
2
|
+
import {serialize, deserialize, Serialized} from './web_worker_transfer';
|
|
3
3
|
import {ThrottledInvoker} from './throttled_invoker';
|
|
4
4
|
|
|
5
5
|
import type {Transferable} from '../types/transferable';
|
|
6
6
|
import type {Cancelable} from '../types/cancelable';
|
|
7
|
+
import type {WorkerSource} from '../source/worker_source';
|
|
8
|
+
import type {OverscaledTileID} from '../source/tile_id';
|
|
9
|
+
import type {Callback} from '../types/callback';
|
|
10
|
+
import type {StyleGlyph} from '../style/style_glyph';
|
|
11
|
+
|
|
12
|
+
export interface ActorTarget {
|
|
13
|
+
addEventListener: typeof window.addEventListener;
|
|
14
|
+
removeEventListener: typeof window.removeEventListener;
|
|
15
|
+
postMessage: typeof window.postMessage;
|
|
16
|
+
terminate?: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface WorkerSourceProvider {
|
|
20
|
+
getWorkerSource(mapId: string | number, sourceType: string, sourceName: string): WorkerSource;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface GlyphsProvider {
|
|
24
|
+
getGlyphs(mapId: string, params: {
|
|
25
|
+
stacks: {[_: string]: Array<number>};
|
|
26
|
+
source: string;
|
|
27
|
+
tileID: OverscaledTileID;
|
|
28
|
+
type: string;
|
|
29
|
+
},
|
|
30
|
+
callback: Callback<{[_: string]: {[_: number]: StyleGlyph}}>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type MessageType = '<response>' | '<cancel>' |
|
|
35
|
+
'geojson.getClusterExpansionZoom' | 'geojson.getClusterChildren' | 'geojson.getClusterLeaves' | 'geojson.loadData' |
|
|
36
|
+
'removeSource' | 'loadWorkerSource' | 'loadDEMTile' | 'removeDEMTile' |
|
|
37
|
+
'removeTile' | 'reloadTile' | 'abortTile' | 'loadTile' | 'getTile' |
|
|
38
|
+
'getGlyphs' | 'getImages' | 'setImages' |
|
|
39
|
+
'syncRTLPluginState' | 'setReferrer' | 'setLayers' | 'updateLayers';
|
|
40
|
+
|
|
41
|
+
export type MessageData = {
|
|
42
|
+
id: string;
|
|
43
|
+
type: MessageType;
|
|
44
|
+
data?: Serialized;
|
|
45
|
+
targetMapId?: string | number | null;
|
|
46
|
+
mustQueue?: boolean;
|
|
47
|
+
error?: Serialized | null;
|
|
48
|
+
hasCallback?: boolean;
|
|
49
|
+
sourceMapId: string | number | null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type Message = {
|
|
53
|
+
data: MessageData;
|
|
54
|
+
}
|
|
7
55
|
|
|
8
56
|
/**
|
|
9
57
|
* An implementation of the [Actor design pattern](http://en.wikipedia.org/wiki/Actor_model)
|
|
@@ -12,36 +60,30 @@ import type {Cancelable} from '../types/cancelable';
|
|
|
12
60
|
* owned by the styles
|
|
13
61
|
*/
|
|
14
62
|
export class Actor {
|
|
15
|
-
target:
|
|
16
|
-
parent:
|
|
17
|
-
mapId: string | null;
|
|
18
|
-
callbacks: {
|
|
19
|
-
number: any;
|
|
20
|
-
};
|
|
63
|
+
target: ActorTarget;
|
|
64
|
+
parent: WorkerSourceProvider | GlyphsProvider;
|
|
65
|
+
mapId: string | number | null;
|
|
66
|
+
callbacks: { [x: number]: Function};
|
|
21
67
|
name: string;
|
|
22
|
-
tasks: {
|
|
23
|
-
|
|
24
|
-
};
|
|
25
|
-
taskQueue: Array<number>;
|
|
26
|
-
cancelCallbacks: {
|
|
27
|
-
number: Cancelable;
|
|
28
|
-
};
|
|
68
|
+
tasks: { [x: number]: MessageData };
|
|
69
|
+
taskQueue: Array<string>;
|
|
70
|
+
cancelCallbacks: { [x: number]: () => void };
|
|
29
71
|
invoker: ThrottledInvoker;
|
|
30
|
-
globalScope:
|
|
72
|
+
globalScope: ActorTarget;
|
|
31
73
|
|
|
32
74
|
/**
|
|
33
75
|
* @param target - The target
|
|
34
76
|
* @param parent - The parent
|
|
35
77
|
* @param mapId - A unique identifier for the Map instance using this Actor.
|
|
36
78
|
*/
|
|
37
|
-
constructor(target:
|
|
79
|
+
constructor(target: ActorTarget, parent: WorkerSourceProvider | GlyphsProvider, mapId?: string | number) {
|
|
38
80
|
this.target = target;
|
|
39
81
|
this.parent = parent;
|
|
40
82
|
this.mapId = mapId;
|
|
41
|
-
this.callbacks = {}
|
|
42
|
-
this.tasks = {}
|
|
83
|
+
this.callbacks = {};
|
|
84
|
+
this.tasks = {};
|
|
43
85
|
this.taskQueue = [];
|
|
44
|
-
this.cancelCallbacks = {}
|
|
86
|
+
this.cancelCallbacks = {};
|
|
45
87
|
this.invoker = new ThrottledInvoker(this.process);
|
|
46
88
|
this.target.addEventListener('message', this.receive, false);
|
|
47
89
|
this.globalScope = isWorker() ? target : window;
|
|
@@ -55,7 +97,7 @@ export class Actor {
|
|
|
55
97
|
* @param targetMapId - A particular mapId to which to send this message.
|
|
56
98
|
*/
|
|
57
99
|
send(
|
|
58
|
-
type:
|
|
100
|
+
type: MessageType,
|
|
59
101
|
data: unknown,
|
|
60
102
|
callback?: Function | null,
|
|
61
103
|
targetMapId?: string | null,
|
|
@@ -69,8 +111,8 @@ export class Actor {
|
|
|
69
111
|
if (callback) {
|
|
70
112
|
this.callbacks[id] = callback;
|
|
71
113
|
}
|
|
72
|
-
const buffers: Array<Transferable> =
|
|
73
|
-
|
|
114
|
+
const buffers: Array<Transferable> = [];
|
|
115
|
+
const message: MessageData = {
|
|
74
116
|
id,
|
|
75
117
|
type,
|
|
76
118
|
hasCallback: !!callback,
|
|
@@ -78,31 +120,27 @@ export class Actor {
|
|
|
78
120
|
mustQueue,
|
|
79
121
|
sourceMapId: this.mapId,
|
|
80
122
|
data: serialize(data, buffers)
|
|
81
|
-
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
this.target.postMessage(message, {transfer: buffers});
|
|
82
126
|
return {
|
|
83
127
|
cancel: () => {
|
|
84
128
|
if (callback) {
|
|
85
129
|
// Set the callback to null so that it never fires after the request is aborted.
|
|
86
130
|
delete this.callbacks[id];
|
|
87
131
|
}
|
|
88
|
-
|
|
132
|
+
const cancelMessage: MessageData = {
|
|
89
133
|
id,
|
|
90
134
|
type: '<cancel>',
|
|
91
135
|
targetMapId,
|
|
92
136
|
sourceMapId: this.mapId
|
|
93
|
-
}
|
|
137
|
+
};
|
|
138
|
+
this.target.postMessage(cancelMessage);
|
|
94
139
|
}
|
|
95
140
|
};
|
|
96
141
|
}
|
|
97
142
|
|
|
98
|
-
receive = (message: {
|
|
99
|
-
data: {
|
|
100
|
-
id: number;
|
|
101
|
-
type: string;
|
|
102
|
-
data: unknown;
|
|
103
|
-
targetMapId?: string | null;
|
|
104
|
-
mustQueue: boolean;
|
|
105
|
-
};}) => {
|
|
143
|
+
receive = (message: Message) => {
|
|
106
144
|
const data = message.data;
|
|
107
145
|
const id = data.id;
|
|
108
146
|
|
|
@@ -164,7 +202,7 @@ export class Actor {
|
|
|
164
202
|
this.processTask(id, task);
|
|
165
203
|
};
|
|
166
204
|
|
|
167
|
-
processTask(id:
|
|
205
|
+
processTask(id: string, task: MessageData) {
|
|
168
206
|
if (task.type === '<response>') {
|
|
169
207
|
// The done() function in the counterpart has been called, and we are now
|
|
170
208
|
// firing the callback in the originating actor, if there is one.
|
|
@@ -180,30 +218,31 @@ export class Actor {
|
|
|
180
218
|
}
|
|
181
219
|
} else {
|
|
182
220
|
let completed = false;
|
|
183
|
-
const buffers: Array<Transferable> =
|
|
221
|
+
const buffers: Array<Transferable> = [];
|
|
184
222
|
const done = task.hasCallback ? (err: Error, data?: any) => {
|
|
185
223
|
completed = true;
|
|
186
224
|
delete this.cancelCallbacks[id];
|
|
187
|
-
|
|
225
|
+
const responseMessage: MessageData = {
|
|
188
226
|
id,
|
|
189
227
|
type: '<response>',
|
|
190
228
|
sourceMapId: this.mapId,
|
|
191
229
|
error: err ? serialize(err) : null,
|
|
192
230
|
data: serialize(data, buffers)
|
|
193
|
-
}
|
|
231
|
+
};
|
|
232
|
+
this.target.postMessage(responseMessage, {transfer: buffers});
|
|
194
233
|
} : (_) => {
|
|
195
234
|
completed = true;
|
|
196
235
|
};
|
|
197
236
|
|
|
198
|
-
let callback = null;
|
|
199
|
-
const params =
|
|
237
|
+
let callback: Cancelable = null;
|
|
238
|
+
const params = deserialize(task.data);
|
|
200
239
|
if (this.parent[task.type]) {
|
|
201
240
|
// task.type == 'loadTile', 'removeTile', etc.
|
|
202
241
|
callback = this.parent[task.type](task.sourceMapId, params, done);
|
|
203
|
-
} else if (this.parent
|
|
242
|
+
} else if ('getWorkerSource' in this.parent) {
|
|
204
243
|
// task.type == sourcetype.method
|
|
205
244
|
const keys = task.type.split('.');
|
|
206
|
-
const scope =
|
|
245
|
+
const scope = this.parent.getWorkerSource(task.sourceMapId, keys[0], (params as any).source);
|
|
207
246
|
callback = scope[keys[1]](params, done);
|
|
208
247
|
} else {
|
|
209
248
|
// No function was found.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {Actor} from './actor';
|
|
1
2
|
import {Dispatcher} from './dispatcher';
|
|
2
3
|
import {workerFactory} from './web_worker';
|
|
3
4
|
import {WorkerPool} from './worker_pool';
|
|
@@ -16,7 +17,7 @@ describe('Dispatcher', () => {
|
|
|
16
17
|
}
|
|
17
18
|
} as any as WorkerPool;
|
|
18
19
|
|
|
19
|
-
const dispatcher = new Dispatcher(workerPool, {}, mapId);
|
|
20
|
+
const dispatcher = new Dispatcher(workerPool, {} as any, mapId);
|
|
20
21
|
expect(dispatcher.actors.map((actor) => { return actor.target; })).toEqual(workers);
|
|
21
22
|
dispatcher.remove();
|
|
22
23
|
expect(dispatcher.actors).toHaveLength(0);
|
|
@@ -41,7 +42,7 @@ describe('Dispatcher', () => {
|
|
|
41
42
|
}
|
|
42
43
|
} as any as WorkerPool;
|
|
43
44
|
|
|
44
|
-
let dispatcher = new Dispatcher(workerPool, {}, mapId);
|
|
45
|
+
let dispatcher = new Dispatcher(workerPool, {} as any, mapId);
|
|
45
46
|
expect(dispatcher.actors.map((actor) => { return actor.target; })).toEqual(workers);
|
|
46
47
|
|
|
47
48
|
// Remove dispatcher, but map is not disposed (During style change)
|
|
@@ -50,7 +51,7 @@ describe('Dispatcher', () => {
|
|
|
50
51
|
expect(releaseCalled).toHaveLength(0);
|
|
51
52
|
|
|
52
53
|
// Create new instance of dispatcher
|
|
53
|
-
dispatcher = new Dispatcher(workerPool, {}, mapId);
|
|
54
|
+
dispatcher = new Dispatcher(workerPool, {} as any, mapId);
|
|
54
55
|
expect(dispatcher.actors.map((actor) => { return actor.target; })).toEqual(workers);
|
|
55
56
|
dispatcher.remove(true); // mapRemoved = true
|
|
56
57
|
expect(dispatcher.actors).toHaveLength(0);
|
|
@@ -61,14 +62,12 @@ describe('Dispatcher', () => {
|
|
|
61
62
|
test('#remove destroys actors', () => {
|
|
62
63
|
const actorsRemoved = [];
|
|
63
64
|
const mapId = 1;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
jest.spyOn(Dispatcher, 'Actor').mockImplementation(Actor as any);
|
|
65
|
+
const spy = jest.fn().mockImplementation(() => { actorsRemoved.push(this); });
|
|
66
|
+
Actor.prototype.remove = spy;
|
|
68
67
|
WorkerPool.workerCount = 4;
|
|
69
68
|
|
|
70
69
|
const workerPool = new WorkerPool();
|
|
71
|
-
const dispatcher = new Dispatcher(workerPool, {}, mapId);
|
|
70
|
+
const dispatcher = new Dispatcher(workerPool, {} as any, mapId);
|
|
72
71
|
dispatcher.remove();
|
|
73
72
|
expect(actorsRemoved).toHaveLength(4);
|
|
74
73
|
});
|
package/src/util/dispatcher.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {asyncAll} from './util';
|
|
2
|
-
import {Actor} from './actor';
|
|
2
|
+
import {Actor, GlyphsProvider, MessageType} from './actor';
|
|
3
3
|
|
|
4
4
|
import type {WorkerPool} from './worker_pool';
|
|
5
5
|
import type {WorkerSource} from '../source/worker_source'; /* eslint-disable-line */ // this is used for the docs' import
|
|
@@ -11,14 +11,9 @@ export class Dispatcher {
|
|
|
11
11
|
workerPool: WorkerPool;
|
|
12
12
|
actors: Array<Actor>;
|
|
13
13
|
currentActor: number;
|
|
14
|
-
id: number;
|
|
14
|
+
id: string | number;
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
static Actor: {
|
|
18
|
-
new (...args: any): Actor;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
constructor(workerPool: WorkerPool, parent: any, mapId: number) {
|
|
16
|
+
constructor(workerPool: WorkerPool, parent: GlyphsProvider, mapId: string | number) {
|
|
22
17
|
this.workerPool = workerPool;
|
|
23
18
|
this.actors = [];
|
|
24
19
|
this.currentActor = 0;
|
|
@@ -26,7 +21,7 @@ export class Dispatcher {
|
|
|
26
21
|
const workers = this.workerPool.acquire(mapId);
|
|
27
22
|
for (let i = 0; i < workers.length; i++) {
|
|
28
23
|
const worker = workers[i];
|
|
29
|
-
const actor = new
|
|
24
|
+
const actor = new Actor(worker, parent, mapId);
|
|
30
25
|
actor.name = `Worker ${i}`;
|
|
31
26
|
this.actors.push(actor);
|
|
32
27
|
}
|
|
@@ -36,7 +31,7 @@ export class Dispatcher {
|
|
|
36
31
|
/**
|
|
37
32
|
* Broadcast a message to all Workers.
|
|
38
33
|
*/
|
|
39
|
-
broadcast(type:
|
|
34
|
+
broadcast(type: MessageType, data: unknown, cb?: (...args: any[]) => any) {
|
|
40
35
|
cb = cb || function () {};
|
|
41
36
|
asyncAll(this.actors, (actor, done) => {
|
|
42
37
|
actor.send(type, data, done);
|
|
@@ -58,5 +53,3 @@ export class Dispatcher {
|
|
|
58
53
|
if (mapRemoved) this.workerPool.release(this.id);
|
|
59
54
|
}
|
|
60
55
|
}
|
|
61
|
-
|
|
62
|
-
Dispatcher.Actor = Actor;
|
package/src/util/web_worker.ts
CHANGED
|
@@ -2,21 +2,6 @@ import {config} from './config';
|
|
|
2
2
|
|
|
3
3
|
import type {WorkerSource} from '../source/worker_source';
|
|
4
4
|
|
|
5
|
-
export type MessageListener = (
|
|
6
|
-
a: {
|
|
7
|
-
data: any;
|
|
8
|
-
target: any;
|
|
9
|
-
}
|
|
10
|
-
) => unknown;
|
|
11
|
-
|
|
12
|
-
// The main thread interface. Provided by Worker in a browser environment,
|
|
13
|
-
export interface WorkerInterface {
|
|
14
|
-
addEventListener(type: 'message', listener: MessageListener): void;
|
|
15
|
-
removeEventListener(type: 'message', listener: MessageListener): void;
|
|
16
|
-
postMessage(message: any): void;
|
|
17
|
-
terminate(): void;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
5
|
export interface WorkerGlobalScopeInterface {
|
|
21
6
|
importScripts(...urls: Array<string>): void;
|
|
22
7
|
registerWorkerSource: (
|
|
@@ -172,10 +172,9 @@ export function serialize(input: unknown, transferables?: Array<Transferable> |
|
|
|
172
172
|
|
|
173
173
|
if (!klass.serialize) {
|
|
174
174
|
for (const key in input) {
|
|
175
|
-
|
|
176
|
-
if (!(input as any).hasOwnProperty(key)) continue; // eslint-disable-line no-prototype-builtins
|
|
175
|
+
if (!input.hasOwnProperty(key)) continue; // eslint-disable-line no-prototype-builtins
|
|
177
176
|
if (registry[name].omit.indexOf(key) >= 0) continue;
|
|
178
|
-
const property =
|
|
177
|
+
const property = input[key];
|
|
179
178
|
properties[key] = registry[name].shallow.indexOf(key) >= 0 ?
|
|
180
179
|
property :
|
|
181
180
|
serialize(property, transferables);
|
|
@@ -184,7 +183,7 @@ export function serialize(input: unknown, transferables?: Array<Transferable> |
|
|
|
184
183
|
properties.message = input.message;
|
|
185
184
|
}
|
|
186
185
|
} else {
|
|
187
|
-
if (transferables && properties
|
|
186
|
+
if (transferables && properties === transferables[transferables.length - 1]) {
|
|
188
187
|
throw new Error('statically serialized object won\'t survive transfer of $name property');
|
|
189
188
|
}
|
|
190
189
|
}
|
|
@@ -226,7 +225,7 @@ export function deserialize(input: Serialized): unknown {
|
|
|
226
225
|
}
|
|
227
226
|
|
|
228
227
|
if (typeof input === 'object') {
|
|
229
|
-
const name =
|
|
228
|
+
const name = input.$name || 'Object';
|
|
230
229
|
if (!registry[name]) {
|
|
231
230
|
throw new Error(`can't deserialize unregistered class ${name}`);
|
|
232
231
|
}
|
package/src/util/worker_pool.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {workerFactory} from './web_worker';
|
|
2
|
-
import type {WorkerInterface} from './web_worker';
|
|
3
2
|
import {browser} from './browser';
|
|
4
3
|
import {isSafari} from './util';
|
|
4
|
+
import {ActorTarget} from './actor';
|
|
5
5
|
|
|
6
6
|
export const PRELOAD_POOL_ID = 'mapboxgl_preloaded_worker_pool';
|
|
7
7
|
|
|
@@ -14,13 +14,13 @@ export class WorkerPool {
|
|
|
14
14
|
active: {
|
|
15
15
|
[_ in number | string]: boolean;
|
|
16
16
|
};
|
|
17
|
-
workers: Array<
|
|
17
|
+
workers: Array<ActorTarget>;
|
|
18
18
|
|
|
19
19
|
constructor() {
|
|
20
20
|
this.active = {};
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
acquire(mapId: number | string): Array<
|
|
23
|
+
acquire(mapId: number | string): Array<ActorTarget> {
|
|
24
24
|
if (!this.workers) {
|
|
25
25
|
// Lazily look up the value of mapboxgl.workerCount so that
|
|
26
26
|
// client code has had a chance to set it.
|