@mapwhit/tilerenderer 0.47.1 → 0.47.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.
Files changed (56) hide show
  1. package/build/min/package.json +1 -1
  2. package/package.json +1 -2
  3. package/src/data/array_types.js +1 -1
  4. package/src/data/bucket/circle_bucket.js +1 -1
  5. package/src/data/bucket/fill_bucket.js +1 -1
  6. package/src/data/bucket/fill_extrusion_bucket.js +1 -1
  7. package/src/data/bucket/heatmap_bucket.js +1 -1
  8. package/src/data/bucket/line_bucket.js +1 -1
  9. package/src/data/bucket/symbol_bucket.js +1 -1
  10. package/src/data/dem_data.js +1 -1
  11. package/src/data/feature_index.js +43 -82
  12. package/src/data/program_configuration.js +1 -1
  13. package/src/data/segment.js +2 -2
  14. package/src/gl/color_mode.js +6 -6
  15. package/src/index.js +2 -0
  16. package/src/render/glyph_atlas.js +1 -1
  17. package/src/render/glyph_manager.js +43 -48
  18. package/src/render/image_atlas.js +1 -1
  19. package/src/render/image_manager.js +9 -37
  20. package/src/source/geojson_source.js +49 -93
  21. package/src/source/geojson_worker_source.js +33 -134
  22. package/src/source/image_source.js +9 -14
  23. package/src/source/load_tilejson.js +27 -34
  24. package/src/source/raster_dem_tile_source.js +27 -40
  25. package/src/source/raster_tile_source.js +53 -62
  26. package/src/source/rtl_text_plugin.js +2 -1
  27. package/src/source/source_cache.js +22 -20
  28. package/src/source/source_state.js +17 -26
  29. package/src/source/tile_id.js +1 -1
  30. package/src/source/vector_tile_source.js +56 -73
  31. package/src/source/vector_tile_worker_source.js +20 -85
  32. package/src/source/worker.js +38 -95
  33. package/src/source/worker_tile.js +39 -84
  34. package/src/style/load_sprite.js +14 -17
  35. package/src/style/properties.js +1 -1
  36. package/src/style/style.js +22 -22
  37. package/src/style/style_layer_index.js +17 -23
  38. package/src/style-spec/reference/v8.json +2 -2
  39. package/src/symbol/anchor.js +1 -1
  40. package/src/symbol/collision_index.js +23 -16
  41. package/src/symbol/grid_index.js +176 -182
  42. package/src/symbol/mergelines.js +48 -48
  43. package/src/symbol/opacity_state.js +1 -1
  44. package/src/ui/camera.js +82 -85
  45. package/src/ui/map.js +5 -32
  46. package/src/util/actor.js +46 -42
  47. package/src/util/browser.js +6 -0
  48. package/src/util/dictionary_coder.js +13 -21
  49. package/src/util/dispatcher.js +14 -17
  50. package/src/util/image.js +1 -1
  51. package/src/util/loader/image.js +11 -11
  52. package/src/util/polyfill.js +16 -0
  53. package/src/util/task_queue.js +39 -43
  54. package/src/util/transfer_registry.js +167 -0
  55. package/src/util/web_worker_transfer.js +5 -190
  56. package/src/source/raster_dem_tile_worker_source.js +0 -26
package/src/ui/camera.js CHANGED
@@ -1,4 +1,4 @@
1
- const { bindAll, deepEqual } = require('../util/object');
1
+ const { deepEqual } = require('../util/object');
2
2
  const { clamp, wrap, ease: defaultEasing } = require('../util/util');
3
3
  const warn = require('../util/warn');
4
4
  const interpolate = require('../util/interpolate');
@@ -53,8 +53,6 @@ class Camera extends Evented {
53
53
  this._zooming = false;
54
54
  this.transform = transform;
55
55
  this._bearingSnap = options.bearingSnap;
56
-
57
- bindAll(['_renderFrameCallback'], this);
58
56
  }
59
57
 
60
58
  /**
@@ -96,9 +94,9 @@ class Camera extends Evented {
96
94
  * @returns {Map} `this`
97
95
  * @see [Navigate the map with game-like controls](https://www.mapbox.com/mapbox-gl-js/example/game-controls/)
98
96
  */
99
- panBy(offset, options, eventData) {
97
+ panBy(offset, options = {}, eventData) {
100
98
  offset = Point.convert(offset).mult(-1);
101
- return this.panTo(this.transform.center, Object.assign({ offset }, options), eventData);
99
+ return this.panTo(this.transform.center, { offset, ...options }, eventData);
102
100
  }
103
101
 
104
102
  /**
@@ -112,16 +110,8 @@ class Camera extends Evented {
112
110
  * @fires moveend
113
111
  * @returns {Map} `this`
114
112
  */
115
- panTo(lnglat, options, eventData) {
116
- return this.easeTo(
117
- Object.assign(
118
- {
119
- center: lnglat
120
- },
121
- options
122
- ),
123
- eventData
124
- );
113
+ panTo(lnglat, options = {}, eventData) {
114
+ return this.easeTo({ center: lnglat, ...options }, eventData);
125
115
  }
126
116
 
127
117
  /**
@@ -171,16 +161,8 @@ class Camera extends Evented {
171
161
  * @fires zoomend
172
162
  * @returns {Map} `this`
173
163
  */
174
- zoomTo(zoom, options, eventData) {
175
- return this.easeTo(
176
- Object.assign(
177
- {
178
- zoom: zoom
179
- },
180
- options
181
- ),
182
- eventData
183
- );
164
+ zoomTo(zoom, options = {}, eventData) {
165
+ return this.easeTo({ zoom, ...options }, eventData);
184
166
  }
185
167
 
186
168
  /**
@@ -266,16 +248,8 @@ class Camera extends Evented {
266
248
  * @fires moveend
267
249
  * @returns {Map} `this`
268
250
  */
269
- rotateTo(bearing, options, eventData) {
270
- return this.easeTo(
271
- Object.assign(
272
- {
273
- bearing: bearing
274
- },
275
- options
276
- ),
277
- eventData
278
- );
251
+ rotateTo(bearing, options = {}, eventData) {
252
+ return this.easeTo({ bearing, ...options }, eventData);
279
253
  }
280
254
 
281
255
  /**
@@ -288,8 +262,8 @@ class Camera extends Evented {
288
262
  * @fires moveend
289
263
  * @returns {Map} `this`
290
264
  */
291
- resetNorth(options, eventData) {
292
- this.rotateTo(0, Object.assign({ duration: 1000 }, options), eventData);
265
+ resetNorth(options = {}, eventData) {
266
+ this.rotateTo(0, { duration: 1000, ...options }, eventData);
293
267
  return this;
294
268
  }
295
269
 
@@ -338,45 +312,35 @@ class Camera extends Evented {
338
312
  }
339
313
 
340
314
  /**
341
- * Pans and zooms the map to contain its visible area within the specified geographical bounds.
342
- * This function will also reset the map's bearing to 0 if bearing is nonzero.
343
- *
344
315
  * @memberof Map#
345
- * @param bounds Center these bounds in the viewport and use the highest
346
- * zoom level up to and including `Map#getMaxZoom()` that fits them in the viewport.
316
+ * @param bounds Calculate the center for these bounds in the viewport and use
317
+ * the highest zoom level up to and including `Map#getMaxZoom()` that fits
318
+ * in the viewport.
347
319
  * @param options
348
320
  * @param {number | PaddingOptions} [options.padding] The amount of padding in pixels to add to the given bounds.
349
- * @param {boolean} [options.linear=false] If `true`, the map transitions using
350
- * {@link Map#easeTo}. If `false`, the map transitions using {@link Map#flyTo}. See
351
- * those functions and {@link AnimationOptions} for information about options available.
352
- * @param {Function} [options.easing] An easing function for the animated transition. See {@link AnimationOptions}.
353
321
  * @param {PointLike} [options.offset=[0, 0]] The center of the given bounds relative to the map's center, measured in pixels.
354
- * @param {number} [options.maxZoom] The maximum zoom level to allow when the map view transitions to the specified bounds.
355
- * @param eventData Additional properties to be added to event objects of events triggered by this method.
356
- * @fires movestart
357
- * @fires moveend
358
- * @returns {Map} `this`
322
+ * @param {number} [options.maxZoom] The maximum zoom level to allow when the camera would transition to the specified bounds.
323
+ * @returns {CameraOptions | void} If map is able to fit to provided bounds, returns `CameraOptions` with
324
+ * at least `center`, `zoom`, `bearing`, `offset`, `padding`, and `maxZoom`, as well as any other
325
+ * `options` provided in arguments. If map is unable to fit, method will warn and return undefined.
359
326
  * @example
360
327
  * var bbox = [[-79, 43], [-73, 45]];
361
- * map.fitBounds(bbox, {
328
+ * var newCameraTransform = map.cameraForBounds(bbox, {
362
329
  * padding: {top: 10, bottom:25, left: 15, right: 5}
363
330
  * });
364
- * @see [Fit a map to a bounding box](https://www.mapbox.com/mapbox-gl-js/example/fitbounds/)
365
331
  */
366
- fitBounds(bounds, options, eventData) {
367
- options = Object.assign(
368
- {
369
- padding: {
370
- top: 0,
371
- bottom: 0,
372
- right: 0,
373
- left: 0
374
- },
375
- offset: [0, 0],
376
- maxZoom: this.transform.maxZoom
332
+ cameraForBounds(bounds, options) {
333
+ options = {
334
+ padding: {
335
+ top: 0,
336
+ bottom: 0,
337
+ right: 0,
338
+ left: 0
377
339
  },
378
- options
379
- );
340
+ offset: [0, 0],
341
+ maxZoom: this.transform.maxZoom,
342
+ ...options
343
+ };
380
344
 
381
345
  if (typeof options.padding === 'number') {
382
346
  const p = options.padding;
@@ -398,7 +362,7 @@ class Camera extends Evented {
398
362
  )
399
363
  ) {
400
364
  warn.once("options.padding must be a positive number, or an Object with keys 'bottom', 'left', 'right', 'top'");
401
- return this;
365
+ return;
402
366
  }
403
367
 
404
368
  bounds = LngLatBounds.convert(bounds);
@@ -425,13 +389,50 @@ class Camera extends Evented {
425
389
 
426
390
  if (scaleY < 0 || scaleX < 0) {
427
391
  warn.once('Map cannot fit within canvas with the given bounds, padding, and/or offset.');
428
- return this;
392
+ return;
429
393
  }
430
394
 
431
395
  options.center = tr.unproject(nw.add(se).div(2));
432
396
  options.zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), options.maxZoom);
433
397
  options.bearing = 0;
434
398
 
399
+ return options;
400
+ }
401
+
402
+ /**
403
+ * Pans and zooms the map to contain its visible area within the specified geographical bounds.
404
+ * This function will also reset the map's bearing to 0 if bearing is nonzero.
405
+ *
406
+ * @memberof Map#
407
+ * @param bounds Center these bounds in the viewport and use the highest
408
+ * zoom level up to and including `Map#getMaxZoom()` that fits them in the viewport.
409
+ * @param options
410
+ * @param {number | PaddingOptions} [options.padding] The amount of padding in pixels to add to the given bounds.
411
+ * @param {boolean} [options.linear=false] If `true`, the map transitions using
412
+ * {@link Map#easeTo}. If `false`, the map transitions using {@link Map#flyTo}. See
413
+ * those functions and {@link AnimationOptions} for information about options available.
414
+ * @param {Function} [options.easing] An easing function for the animated transition. See {@link AnimationOptions}.
415
+ * @param {PointLike} [options.offset=[0, 0]] The center of the given bounds relative to the map's center, measured in pixels.
416
+ * @param {number} [options.maxZoom] The maximum zoom level to allow when the map view transitions to the specified bounds.
417
+ * @param eventData Additional properties to be added to event objects of events triggered by this method.
418
+ * @fires movestart
419
+ * @fires moveend
420
+ * @returns {Map} `this`
421
+ * @example
422
+ * var bbox = [[-79, 43], [-73, 45]];
423
+ * map.fitBounds(bbox, {
424
+ * padding: {top: 10, bottom:25, left: 15, right: 5}
425
+ * });
426
+ * @see [Fit a map to a bounding box](https://www.mapbox.com/mapbox-gl-js/example/fitbounds/)
427
+ */
428
+ fitBounds(bounds, options, eventData) {
429
+ const calculatedOptions = this.cameraForBounds(bounds, options);
430
+
431
+ // cameraForBounds warns + returns undefined if unable to fit:
432
+ if (!calculatedOptions) return this;
433
+
434
+ options = Object.assign(calculatedOptions, options);
435
+
435
436
  return options.linear
436
437
  ? this.easeTo(options, eventData)
437
438
  : options.animate === false
@@ -534,14 +535,12 @@ class Camera extends Evented {
534
535
  easeTo(options, eventData) {
535
536
  this.stop();
536
537
 
537
- options = Object.assign(
538
- {
539
- offset: [0, 0],
540
- duration: 500,
541
- easing: defaultEasing
542
- },
543
- options
544
- );
538
+ options = {
539
+ offset: [0, 0],
540
+ duration: 500,
541
+ easing: defaultEasing,
542
+ ...options
543
+ };
545
544
 
546
545
  if (options.animate === false) options.duration = 0;
547
546
 
@@ -732,15 +731,13 @@ class Camera extends Evented {
732
731
 
733
732
  this.stop();
734
733
 
735
- options = Object.assign(
736
- {
737
- offset: [0, 0],
738
- speed: 1.2,
739
- curve: 1.42,
740
- easing: defaultEasing
741
- },
742
- options
743
- );
734
+ options = {
735
+ offset: [0, 0],
736
+ speed: 1.2,
737
+ curve: 1.42,
738
+ easing: defaultEasing,
739
+ ...options
740
+ };
744
741
 
745
742
  const tr = this.transform;
746
743
  const startZoom = this.getZoom();
package/src/ui/map.js CHANGED
@@ -16,7 +16,7 @@ const LngLatBounds = require('../geo/lng_lat_bounds');
16
16
  const Point = require('@mapbox/point-geometry');
17
17
  const { RGBAImage } = require('../util/image');
18
18
  const { Event, ErrorEvent } = require('../util/evented');
19
- const TaskQueue = require('../util/task_queue');
19
+ const taskQueue = require('../util/task_queue');
20
20
 
21
21
  const defaultMinZoom = 0;
22
22
  const defaultMaxZoom = 22;
@@ -134,36 +134,6 @@ const defaultOptions = {
134
134
  * @see [Display a map](https://www.mapbox.com/mapbox-gl-js/examples/)
135
135
  */
136
136
  class Map extends Camera {
137
- /**
138
- * The map's {@link ScrollZoomHandler}, which implements zooming in and out with a scroll wheel or trackpad.
139
- */
140
-
141
- /**
142
- * The map's {@link BoxZoomHandler}, which implements zooming using a drag gesture with the Shift key pressed.
143
- */
144
-
145
- /**
146
- * The map's {@link DragRotateHandler}, which implements rotating the map while dragging with the right
147
- * mouse button or with the Control key pressed.
148
- */
149
-
150
- /**
151
- * The map's {@link DragPanHandler}, which implements dragging the map with a mouse or touch gesture.
152
- */
153
-
154
- /**
155
- * The map's {@link KeyboardHandler}, which allows the user to zoom, rotate, and pan the map using keyboard
156
- * shortcuts.
157
- */
158
-
159
- /**
160
- * The map's {@link DoubleClickZoomHandler}, which allows the user to zoom by double clicking.
161
- */
162
-
163
- /**
164
- * The map's {@link TouchZoomRotateHandler}, which allows the user to zoom or rotate the map with touch gestures.
165
- */
166
-
167
137
  constructor(options) {
168
138
  options = Object.assign({}, defaultOptions, options);
169
139
 
@@ -186,7 +156,7 @@ class Map extends Camera {
186
156
  this._fadeDuration = options.fadeDuration;
187
157
  this._crossSourceCollisions = options.crossSourceCollisions;
188
158
  this._crossFadingFactor = 1;
189
- this._renderTaskQueue = new TaskQueue();
159
+ this._renderTaskQueue = taskQueue(this);
190
160
 
191
161
  if (typeof options.container === 'string') {
192
162
  const container = window.document.getElementById(options.container);
@@ -220,6 +190,9 @@ class Map extends Camera {
220
190
 
221
191
  this._setupContainer();
222
192
  this._setupPainter();
193
+ if (this.painter === undefined) {
194
+ throw new Error('Failed to initialize WebGL.');
195
+ }
223
196
 
224
197
  this.on('move', this._update.bind(this, false));
225
198
  this.on('moveend', this._update.bind(this, false));
package/src/util/actor.js CHANGED
@@ -15,24 +15,16 @@ module.exports = actor;
15
15
  */
16
16
 
17
17
  function actor(target, parent, mapId, name) {
18
- const callbacks = {};
19
- let callbackID = 0;
18
+ const promises = new Map();
19
+ let callbackID = Number.MIN_SAFE_INTEGER;
20
20
  target.addEventListener('message', receive, false);
21
21
 
22
- function postMessage(targetMapId, id, type, data, err) {
23
- const buffers = [];
24
- const payload = {
25
- targetMapId,
26
- sourceMapId: mapId,
27
- type,
28
- id,
29
- data: serialize(data, buffers)
30
- };
31
- if (err) {
32
- payload.error = serialize(err);
33
- }
34
- target.postMessage(payload, buffers);
35
- }
22
+ return {
23
+ send,
24
+ receive,
25
+ remove,
26
+ name
27
+ };
36
28
 
37
29
  /**
38
30
  * Sends a message from a main-thread map to a Worker or from a Worker back to
@@ -42,50 +34,54 @@ function actor(target, parent, mapId, name) {
42
34
  * @param targetMapId A particular mapId to which to send this message.
43
35
  * @private
44
36
  */
45
- function send(type, data, callback, targetMapId) {
46
- let id = 'null';
47
- if (callback) {
48
- id = `${mapId}:${callbackID++}`;
49
- callbacks[id] = callback;
50
- }
37
+ function send(type, data, targetMapId) {
38
+ const id = `${mapId}:${callbackID++}`;
39
+ const p = Promise.withResolvers();
40
+ promises.set(id, p);
51
41
  postMessage(targetMapId, id, type, data);
42
+ return p.promise;
52
43
  }
53
44
 
54
- function receive(message) {
45
+ async function receive(message) {
55
46
  const { data } = message;
56
47
  const { id, type, targetMapId } = data;
57
48
 
58
49
  if (targetMapId && mapId !== targetMapId) return;
59
50
 
60
- const done = (err, data) => postMessage(undefined, id, '<response>', data, err);
61
-
62
51
  if (type === '<response>') {
63
- const callback = callbacks[id];
64
- delete callbacks[id];
65
- if (callback) {
52
+ const p = promises.get(id);
53
+ if (p) {
54
+ promises.delete(id);
66
55
  if (data.error) {
67
- callback(deserialize(data.error));
56
+ p.reject(deserialize(data.error));
68
57
  } else {
69
- callback(null, deserialize(data.data));
58
+ p.resolve(deserialize(data.data));
70
59
  }
71
60
  }
72
61
  return;
73
62
  }
74
63
 
75
64
  if (typeof id !== 'undefined') {
65
+ let perform;
76
66
  if (parent[type]) {
77
- // data.type == 'loadTile', 'removeTile', etc.
78
- parent[type](data.sourceMapId, deserialize(data.data), done);
79
- return;
80
- }
81
- if (parent.getWorkerSource) {
67
+ // data.type == 'loadTile' etc.
68
+ perform = () => parent[type](data.sourceMapId, deserialize(data.data));
69
+ } else if (parent.getWorkerSource) {
82
70
  // data.type == sourcetype.method
83
71
  const [sourcetype, method] = type.split('.');
84
72
  const params = deserialize(data.data);
85
73
  const workerSource = parent.getWorkerSource(data.sourceMapId, sourcetype, params.source);
86
- workerSource[method](params, done);
74
+ perform = () => workerSource[method](params);
75
+ } else {
87
76
  return;
88
77
  }
78
+ try {
79
+ const result = await perform();
80
+ postMessage(data.sourceMapId, id, '<response>', result);
81
+ } catch (err) {
82
+ postMessage(data.sourceMapId, id, '<response>', undefined, err);
83
+ }
84
+ return;
89
85
  }
90
86
 
91
87
  parent[type](deserialize(data.data));
@@ -95,10 +91,18 @@ function actor(target, parent, mapId, name) {
95
91
  target.removeEventListener('message', receive, false);
96
92
  }
97
93
 
98
- return {
99
- send,
100
- receive,
101
- remove,
102
- name
103
- };
94
+ function postMessage(targetMapId, id, type, data, err) {
95
+ const buffers = [];
96
+ const payload = {
97
+ targetMapId,
98
+ sourceMapId: mapId,
99
+ type,
100
+ id,
101
+ data: serialize(data, buffers)
102
+ };
103
+ if (err) {
104
+ payload.error = serialize(err);
105
+ }
106
+ target.postMessage(payload, buffers);
107
+ }
104
108
  }
@@ -51,6 +51,12 @@ const exported = {
51
51
  return context.getImageData(0, 0, img.width, img.height);
52
52
  },
53
53
 
54
+ resolveURL(path) {
55
+ const a = window.document.createElement('a');
56
+ a.href = path;
57
+ return a.href;
58
+ },
59
+
54
60
  hardwareConcurrency: typeof window === 'object' ? window.navigator.hardwareConcurrency : 4,
55
61
 
56
62
  get devicePixelRatio() {
@@ -1,25 +1,17 @@
1
1
  const assert = require('assert');
2
2
 
3
- class DictionaryCoder {
4
- constructor(strings) {
5
- this._stringToNumber = {};
6
- this._numberToString = [];
7
- for (let i = 0; i < strings.length; i++) {
8
- const string = strings[i];
9
- this._stringToNumber[string] = i;
10
- this._numberToString[i] = string;
11
- }
12
- }
13
-
14
- encode(string) {
15
- assert(string in this._stringToNumber);
16
- return this._stringToNumber[string];
17
- }
3
+ module.exports = dictionaryCoder;
18
4
 
19
- decode(n) {
20
- assert(n < this._numberToString.length);
21
- return this._numberToString[n];
22
- }
5
+ function dictionaryCoder(strings) {
6
+ const numberToString = strings.sort();
7
+ const stringToNumber = new Map(numberToString.map((s, i) => [s, i]));
8
+ return {
9
+ encode(string) {
10
+ return stringToNumber.get(string);
11
+ },
12
+ decode(n) {
13
+ assert(n < numberToString.length);
14
+ return numberToString[n];
15
+ }
16
+ };
23
17
  }
24
-
25
- module.exports = DictionaryCoder;
@@ -1,11 +1,8 @@
1
- const async = require('./async');
2
1
  const uniqueId = require('./unique_id');
3
2
  const actor = require('./actor');
4
3
 
5
4
  module.exports = dispatcher;
6
5
 
7
- const noop = () => {};
8
-
9
6
  /**
10
7
  * Responsible for sending messages from a {@link Source} to an associated
11
8
  * {@link WorkerSource}.
@@ -15,7 +12,7 @@ const noop = () => {};
15
12
  function dispatcher(workerPool, parent, makeActor = actor) {
16
13
  // exposed to allow stubbing in unit tests
17
14
 
18
- let currentActor = 0;
15
+ let currentActor = -1;
19
16
  const id = uniqueId();
20
17
  const workers = workerPool.acquire(id);
21
18
  const actors = workers.map((worker, i) => makeActor(worker, parent, id, `Worker ${i}`));
@@ -23,8 +20,9 @@ function dispatcher(workerPool, parent, makeActor = actor) {
23
20
  /**
24
21
  * Broadcast a message to all Workers.
25
22
  */
26
- function broadcast(type, data, cb = noop) {
27
- async.all(actors, (actor, done) => actor.send(type, data, done), cb);
23
+ function broadcast(type, data) {
24
+ const tasks = actors.map(actor => actor.send(type, data));
25
+ return Promise.all(tasks);
28
26
  }
29
27
 
30
28
  // Use round robin to send requests to web workers.
@@ -41,16 +39,8 @@ function dispatcher(workerPool, parent, makeActor = actor) {
41
39
  * @param targetID The ID of the Worker to which to send this message. Omit to allow the dispatcher to choose.
42
40
  * @returns The ID of the worker to which the message was sent.
43
41
  */
44
- function send(type, data, callback, targetID) {
45
- if (typeof targetID !== 'number' || isNaN(targetID)) {
46
- targetID = nextActorId();
47
- }
48
-
49
- const actor = actors[targetID];
50
- if (actor) {
51
- actor.send(type, data, callback);
52
- }
53
- return targetID;
42
+ function send(type, data, targetID = nextActorId()) {
43
+ return actors[targetID]?.send(type, data) ?? Promise.resolve();
54
44
  }
55
45
 
56
46
  function remove() {
@@ -59,10 +49,17 @@ function dispatcher(workerPool, parent, makeActor = actor) {
59
49
  workerPool.release(id);
60
50
  }
61
51
 
52
+ function nextWorkerId(workerId = nextActorId()) {
53
+ return workerId;
54
+ }
55
+
62
56
  return {
63
- id,
57
+ get id() {
58
+ return id;
59
+ },
64
60
  broadcast,
65
61
  send,
62
+ nextWorkerId,
66
63
  remove
67
64
  };
68
65
  }
package/src/util/image.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const assert = require('assert');
2
2
 
3
- const { register } = require('./web_worker_transfer');
3
+ const { register } = require('./transfer_registry');
4
4
 
5
5
  function createImage(image, { width, height }, channels, data) {
6
6
  if (!data) {
@@ -1,32 +1,32 @@
1
1
  module.exports = image;
2
2
 
3
- function image(data, fn) {
3
+ function image(data) {
4
4
  if (!data) {
5
- return fn(new Error('image data not loaded'));
6
- }
7
- if (data.byteLength === 0) {
8
- transparentImage(fn);
9
- } else {
10
- imageFromData({ data }, fn);
5
+ throw new Error('image data not loaded');
11
6
  }
7
+ return data.byteLength === 0 ? transparentImage() : imageFromData({ data });
12
8
  }
13
9
 
14
- async function imageFromData(imgData, fn) {
10
+ async function imageFromData(imgData) {
11
+ const { promise, resolve } = Promise.withResolvers();
15
12
  const blob = new window.Blob([imgData.data], { type: imgData.type || 'image/png' });
16
13
  const img = new window.Image();
17
14
 
18
15
  img.onload = () => {
19
- fn(null, img);
16
+ resolve(img);
20
17
  window.URL.revokeObjectURL(img.src);
21
18
  };
22
19
  img.src = await window.URL.createObjectURL(blob);
20
+ return promise;
23
21
  }
24
22
 
25
23
  const transparentPngUrl =
26
24
  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAUAAarVyFEAAAAASUVORK5CYII=';
27
25
 
28
- function transparentImage(fn) {
26
+ function transparentImage() {
27
+ const { promise, resolve } = Promise.withResolvers();
29
28
  const img = new window.Image();
30
- img.onload = () => fn(null, img);
29
+ img.onload = () => resolve(img);
31
30
  img.src = transparentPngUrl;
31
+ return promise;
32
32
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Adds a static method `withResolvers` to the Promise object if it does not already exist.
3
+ *
4
+ * @see https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
5
+ */
6
+ if (typeof Promise.withResolvers !== 'function') {
7
+ Promise.withResolvers = function () {
8
+ let resolve;
9
+ let reject;
10
+ const promise = new Promise((res, rej) => {
11
+ resolve = res;
12
+ reject = rej;
13
+ });
14
+ return { promise, resolve, reject };
15
+ };
16
+ }