@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
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.46.2"
2
+ "version": "0.47.1"
3
3
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mapwhit/tilerenderer",
3
3
  "description": "A WebGL interactive maps library",
4
- "version": "0.47.1",
4
+ "version": "0.47.2",
5
5
  "main": "src/index.js",
6
6
  "license": "BSD-3-Clause",
7
7
  "repository": {
@@ -26,7 +26,6 @@
26
26
  "grid-index": "^1.1.0",
27
27
  "quickselect": "^2.0.0",
28
28
  "supercluster": "^2.0.1",
29
- "tile-cache": "^1.0.2",
30
29
  "tinyqueue": "^1.1.0"
31
30
  },
32
31
  "browser": {
@@ -2,7 +2,7 @@
2
2
 
3
3
  const assert = require('assert');
4
4
  const { Struct, StructArray } = require('../util/struct_array');
5
- const { register } = require('../util/web_worker_transfer');
5
+ const { register } = require('../util/transfer_registry');
6
6
  const Point = require('@mapbox/point-geometry');
7
7
 
8
8
  /**
@@ -6,7 +6,7 @@ const { ProgramConfigurationSet } = require('../program_configuration');
6
6
  const { TriangleIndexArray } = require('../index_array_type');
7
7
  const loadGeometry = require('../load_geometry');
8
8
  const EXTENT = require('../extent');
9
- const { register } = require('../../util/web_worker_transfer');
9
+ const { register } = require('../../util/transfer_registry');
10
10
  const EvaluationParameters = require('../../style/evaluation_parameters');
11
11
 
12
12
  function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) {
@@ -8,7 +8,7 @@ const earcut = require('earcut');
8
8
  const classifyRings = require('../../util/classify_rings');
9
9
  const assert = require('assert');
10
10
  const EARCUT_MAX_RINGS = 500;
11
- const { register } = require('../../util/web_worker_transfer');
11
+ const { register } = require('../../util/transfer_registry');
12
12
  const { hasPattern, addPatternDependencies } = require('./pattern_bucket_features');
13
13
  const loadGeometry = require('../load_geometry');
14
14
  const EvaluationParameters = require('../../style/evaluation_parameters');
@@ -12,7 +12,7 @@ const {
12
12
  const classifyRings = require('../../util/classify_rings');
13
13
  const assert = require('assert');
14
14
  const EARCUT_MAX_RINGS = 500;
15
- const { register } = require('../../util/web_worker_transfer');
15
+ const { register } = require('../../util/transfer_registry');
16
16
  const { hasPattern, addPatternDependencies } = require('./pattern_bucket_features');
17
17
  const loadGeometry = require('../load_geometry');
18
18
  const EvaluationParameters = require('../../style/evaluation_parameters');
@@ -1,6 +1,6 @@
1
1
  const CircleBucket = require('./circle_bucket');
2
2
 
3
- const { register } = require('../../util/web_worker_transfer');
3
+ const { register } = require('../../util/transfer_registry');
4
4
 
5
5
  class HeatmapBucket extends CircleBucket {
6
6
  // Needed for flow to accept omit: ['layers'] below, due to
@@ -7,7 +7,7 @@ const { TriangleIndexArray } = require('../index_array_type');
7
7
  const EXTENT = require('../extent');
8
8
  const mvt = require('@mapbox/vector-tile');
9
9
  const vectorTileFeatureTypes = mvt.VectorTileFeature.types;
10
- const { register } = require('../../util/web_worker_transfer');
10
+ const { register } = require('../../util/transfer_registry');
11
11
  const { hasPattern, addPatternDependencies } = require('./pattern_bucket_features');
12
12
  const loadGeometry = require('../load_geometry');
13
13
  const EvaluationParameters = require('../../style/evaluation_parameters');
@@ -29,7 +29,7 @@ const mvt = require('@mapbox/vector-tile');
29
29
  const vectorTileFeatureTypes = mvt.VectorTileFeature.types;
30
30
  const { verticalizedCharacterMap } = require('../../util/verticalize_punctuation');
31
31
  const { getSizeData } = require('../../symbol/symbol_size');
32
- const { register } = require('../../util/web_worker_transfer');
32
+ const { register } = require('../../util/transfer_registry');
33
33
  const EvaluationParameters = require('../../style/evaluation_parameters');
34
34
 
35
35
  // Opacity arrays are frequently updated but don't contain a lot of information, so we pack them
@@ -1,7 +1,7 @@
1
1
  const { RGBAImage } = require('../util/image');
2
2
 
3
3
  const warn = require('../util/warn');
4
- const { register } = require('../util/web_worker_transfer');
4
+ const { register } = require('../util/transfer_registry');
5
5
 
6
6
  // DEMData is a data structure for decoding, backfilling, and storing elevation data for processing in the hillshade shaders
7
7
  // data can be populated either from a pngraw image tile or from serliazed data sent back from a worker. When data is initially
@@ -2,26 +2,23 @@ const loadGeometry = require('./load_geometry');
2
2
  const EXTENT = require('./extent');
3
3
  const featureFilter = require('../style-spec/feature_filter');
4
4
  const Grid = require('grid-index');
5
- const DictionaryCoder = require('../util/dictionary_coder');
5
+ const dictionaryCoder = require('../util/dictionary_coder');
6
6
  const vt = require('@mapbox/vector-tile');
7
7
  const Protobuf = require('@mapwhit/pbf');
8
8
  const GeoJSONFeature = require('../util/vectortile_to_geojson');
9
9
  const { arraysIntersect } = require('../util/object');
10
- const { register } = require('../util/web_worker_transfer');
10
+ const { register } = require('../util/transfer_registry');
11
11
  const EvaluationParameters = require('../style/evaluation_parameters');
12
12
  const { polygonIntersectsBox } = require('../util/intersection_tests');
13
13
 
14
14
  const { FeatureIndexArray } = require('./array_types');
15
15
 
16
16
  class FeatureIndex {
17
- constructor(tileID, grid, featureIndexArray) {
17
+ constructor(tileID, grid = new Grid(EXTENT, 16, 0), featureIndexArray = new FeatureIndexArray()) {
18
18
  this.tileID = tileID;
19
- this.x = tileID.canonical.x;
20
- this.y = tileID.canonical.y;
21
- this.z = tileID.canonical.z;
22
- this.grid = grid || new Grid(EXTENT, 16, 0);
19
+ this.grid = grid;
23
20
  this.grid3D = new Grid(EXTENT, 16, 0);
24
- this.featureIndexArray = featureIndexArray || new FeatureIndexArray();
21
+ this.featureIndexArray = featureIndexArray;
25
22
  }
26
23
 
27
24
  insert(feature, geometry, featureIndex, sourceLayerIndex, bucketIndex, is3D) {
@@ -30,25 +27,10 @@ class FeatureIndex {
30
27
 
31
28
  const grid = is3D ? this.grid3D : this.grid;
32
29
 
33
- for (let r = 0; r < geometry.length; r++) {
34
- const ring = geometry[r];
35
-
36
- const bbox = [
37
- Number.POSITIVE_INFINITY,
38
- Number.POSITIVE_INFINITY,
39
- Number.NEGATIVE_INFINITY,
40
- Number.NEGATIVE_INFINITY
41
- ];
42
- for (let i = 0; i < ring.length; i++) {
43
- const p = ring[i];
44
- bbox[0] = Math.min(bbox[0], p.x);
45
- bbox[1] = Math.min(bbox[1], p.y);
46
- bbox[2] = Math.max(bbox[2], p.x);
47
- bbox[3] = Math.max(bbox[3], p.y);
48
- }
49
-
50
- if (bbox[0] < EXTENT && bbox[1] < EXTENT && bbox[2] >= 0 && bbox[3] >= 0) {
51
- grid.insert(key, bbox[0], bbox[1], bbox[2], bbox[3]);
30
+ for (const ring of geometry) {
31
+ const { minX, minY, maxX, maxY } = getBounds(ring);
32
+ if (minX < EXTENT && minY < EXTENT && maxX >= 0 && maxY >= 0) {
33
+ grid.insert(key, minX, minY, maxX, maxY);
52
34
  }
53
35
  }
54
36
  }
@@ -56,9 +38,7 @@ class FeatureIndex {
56
38
  loadVTLayers() {
57
39
  if (!this.vtLayers) {
58
40
  this.vtLayers = new vt.VectorTile(new Protobuf(this.rawTileData)).layers;
59
- this.sourceLayerCoder = new DictionaryCoder(
60
- this.vtLayers ? Object.keys(this.vtLayers).sort() : ['_geojsonTileLayer']
61
- );
41
+ this.sourceLayerCoder = dictionaryCoder(this.vtLayers ? Object.keys(this.vtLayers) : ['_geojsonTileLayer']);
62
42
  }
63
43
  return this.vtLayers;
64
44
  }
@@ -99,10 +79,7 @@ class FeatureIndex {
99
79
  }
100
80
  );
101
81
 
102
- for (const key of matching3D) {
103
- matching.push(key);
104
- }
105
-
82
+ matching.push(...matching3D);
106
83
  matching.sort(topDownFeatureComparator);
107
84
 
108
85
  const result = {};
@@ -116,6 +93,26 @@ class FeatureIndex {
116
93
 
117
94
  const match = this.featureIndexArray.get(index);
118
95
  let featureGeometry = null;
96
+ const intersectionTest = (feature, styleLayer) => {
97
+ if (!featureGeometry) {
98
+ featureGeometry = loadGeometry(feature);
99
+ }
100
+ let featureState = {};
101
+ if (feature.id) {
102
+ // `feature-state` expression evaluation requires feature state to be available
103
+ featureState = sourceFeatureState.getState(styleLayer.sourceLayer || '_geojsonTileLayer', String(feature.id));
104
+ }
105
+ return styleLayer.queryIntersectsFeature(
106
+ queryGeometry,
107
+ feature,
108
+ featureState,
109
+ featureGeometry,
110
+ this.tileID.canonical.z,
111
+ args.transform,
112
+ pixelsToTileUnits,
113
+ args.pixelPosMatrix
114
+ );
115
+ };
119
116
  this.loadMatchingFeature(
120
117
  result,
121
118
  match.bucketIndex,
@@ -124,29 +121,7 @@ class FeatureIndex {
124
121
  filter,
125
122
  params.layers,
126
123
  styleLayers,
127
- (feature, styleLayer) => {
128
- if (!featureGeometry) {
129
- featureGeometry = loadGeometry(feature);
130
- }
131
- let featureState = {};
132
- if (feature.id) {
133
- // `feature-state` expression evaluation requires feature state to be available
134
- featureState = sourceFeatureState.getState(
135
- styleLayer.sourceLayer || '_geojsonTileLayer',
136
- String(feature.id)
137
- );
138
- }
139
- return styleLayer.queryIntersectsFeature(
140
- queryGeometry,
141
- feature,
142
- featureState,
143
- featureGeometry,
144
- this.z,
145
- args.transform,
146
- pixelsToTileUnits,
147
- args.pixelPosMatrix
148
- );
149
- }
124
+ intersectionTest
150
125
  );
151
126
  }
152
127
 
@@ -172,10 +147,9 @@ class FeatureIndex {
172
147
 
173
148
  if (!filter(new EvaluationParameters(this.tileID.overscaledZ), feature)) return;
174
149
 
175
- for (let l = 0; l < layerIDs.length; l++) {
176
- const layerID = layerIDs[l];
177
-
178
- if (filterLayerIDs && filterLayerIDs.indexOf(layerID) < 0) {
150
+ const { x, y, z } = this.tileID.canonical;
151
+ for (const layerID of layerIDs) {
152
+ if (filterLayerIDs && !filterLayerIDs.includes(layerID)) {
179
153
  continue;
180
154
  }
181
155
 
@@ -188,13 +162,10 @@ class FeatureIndex {
188
162
  continue;
189
163
  }
190
164
 
191
- const geojsonFeature = new GeoJSONFeature(feature, this.z, this.x, this.y);
165
+ const geojsonFeature = new GeoJSONFeature(feature, z, x, y);
192
166
  geojsonFeature.layer = styleLayer.serialize();
193
- let layerResult = result[layerID];
194
- if (layerResult === undefined) {
195
- layerResult = result[layerID] = [];
196
- }
197
- layerResult.push({ featureIndex: featureIndex, feature: geojsonFeature, intersectionZ });
167
+ const layerResult = (result[layerID] ??= []);
168
+ layerResult.push({ featureIndex, feature: geojsonFeature, intersectionZ });
198
169
  }
199
170
  }
200
171
 
@@ -219,16 +190,6 @@ class FeatureIndex {
219
190
  }
220
191
  return result;
221
192
  }
222
-
223
- hasLayer(id) {
224
- for (const layerIDs of this.bucketLayerIDs) {
225
- for (const layerID of layerIDs) {
226
- if (id === layerID) return true;
227
- }
228
- }
229
-
230
- return false;
231
- }
232
193
  }
233
194
 
234
195
  register('FeatureIndex', FeatureIndex, { omit: ['rawTileData', 'sourceLayerCoder'] });
@@ -240,11 +201,11 @@ function getBounds(geometry) {
240
201
  let minY = Number.POSITIVE_INFINITY;
241
202
  let maxX = Number.NEGATIVE_INFINITY;
242
203
  let maxY = Number.NEGATIVE_INFINITY;
243
- for (const p of geometry) {
244
- minX = Math.min(minX, p.x);
245
- minY = Math.min(minY, p.y);
246
- maxX = Math.max(maxX, p.x);
247
- maxY = Math.max(maxY, p.y);
204
+ for (const { x, y } of geometry) {
205
+ if (x < minX) minX = x;
206
+ if (x > maxX) maxX = x;
207
+ if (y < minY) minY = y;
208
+ if (y > maxY) maxY = y;
248
209
  }
249
210
  return { minX, minY, maxX, maxY };
250
211
  }
@@ -1,6 +1,6 @@
1
1
  const { packUint8ToFloat } = require('../shaders/encode_attribute');
2
2
  const { supportsPropertyExpression } = require('../style-spec/util/properties');
3
- const { register } = require('../util/web_worker_transfer');
3
+ const { register } = require('../util/transfer_registry');
4
4
  const { PossiblyEvaluatedPropertyValue } = require('../style/properties');
5
5
  const {
6
6
  StructArrayLayout1f4,
@@ -1,6 +1,6 @@
1
1
  const warn = require('../util/warn');
2
2
 
3
- const { register } = require('../util/web_worker_transfer');
3
+ const { register } = require('../util/transfer_registry');
4
4
 
5
5
  class SegmentVector {
6
6
  constructor(segments = []) {
@@ -8,11 +8,11 @@ class SegmentVector {
8
8
  }
9
9
 
10
10
  prepareSegment(numVertices, layoutVertexArray, indexArray) {
11
- let segment = this.segments[this.segments.length - 1];
12
11
  if (numVertices > SegmentVector.MAX_VERTEX_ARRAY_LENGTH)
13
12
  warn.once(
14
13
  `Max vertices per segment is ${SegmentVector.MAX_VERTEX_ARRAY_LENGTH}: bucket requested ${numVertices}`
15
14
  );
15
+ let segment = this.segments.at(-1);
16
16
  if (!segment || segment.vertexLength + numVertices > SegmentVector.MAX_VERTEX_ARRAY_LENGTH) {
17
17
  segment = {
18
18
  vertexOffset: layoutVertexArray.length,
@@ -5,6 +5,12 @@ const ONE = 0x0001;
5
5
  const ONE_MINUS_SRC_ALPHA = 0x0303;
6
6
 
7
7
  class ColorMode {
8
+ static Replace = [ONE, ZERO];
9
+
10
+ static disabled = new ColorMode(ColorMode.Replace, Color.transparent, [false, false, false, false]);
11
+ static unblended = new ColorMode(ColorMode.Replace, Color.transparent, [true, true, true, true]);
12
+ static alphaBlended = new ColorMode([ONE, ONE_MINUS_SRC_ALPHA], Color.transparent, [true, true, true, true]);
13
+
8
14
  constructor(blendFunction, blendColor, mask) {
9
15
  this.blendFunction = blendFunction;
10
16
  this.blendColor = blendColor;
@@ -12,10 +18,4 @@ class ColorMode {
12
18
  }
13
19
  }
14
20
 
15
- ColorMode.Replace = [ONE, ZERO];
16
-
17
- ColorMode.disabled = new ColorMode(ColorMode.Replace, Color.transparent, [false, false, false, false]);
18
- ColorMode.unblended = new ColorMode(ColorMode.Replace, Color.transparent, [true, true, true, true]);
19
- ColorMode.alphaBlended = new ColorMode([ONE, ONE_MINUS_SRC_ALPHA], Color.transparent, [true, true, true, true]);
20
-
21
21
  module.exports = ColorMode;
package/src/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ require('./util/polyfill');
2
+
1
3
  module.exports = {
2
4
  version: require('../package.json').version,
3
5
  setRTLTextPlugin: require('./source/rtl_text_plugin').setRTLTextPlugin,
@@ -1,7 +1,7 @@
1
1
  const ShelfPack = require('@mapbox/shelf-pack');
2
2
 
3
3
  const { AlphaImage } = require('../util/image');
4
- const { register } = require('../util/web_worker_transfer');
4
+ const { register } = require('../util/transfer_registry');
5
5
 
6
6
  const padding = 1;
7
7
 
@@ -3,7 +3,6 @@ const loadGlyphRange = require('../style/load_glyph_range');
3
3
  const TinySDF = require('@mapbox/tiny-sdf');
4
4
  const isChar = require('../util/is_char_in_unicode_block');
5
5
  const { AlphaImage } = require('../util/image');
6
- const { callback } = require('../util/callback');
7
6
 
8
7
  class GlyphManager {
9
8
  // exposed as statics to enable stubbing in unit tests
@@ -19,62 +18,58 @@ class GlyphManager {
19
18
  this.loader = loader;
20
19
  }
21
20
 
22
- getGlyphs(glyphs, fn) {
23
- return callback(fn, perform.call(this, glyphs));
24
-
25
- async function perform(glyphs) {
26
- const all = [];
27
- for (const stack in glyphs) {
28
- for (const id of glyphs[stack]) {
29
- all.push(retrieveGlyph(this, { stack, id }));
30
- }
21
+ async getGlyphs(glyphs) {
22
+ const all = [];
23
+ for (const stack in glyphs) {
24
+ for (const id of glyphs[stack]) {
25
+ all.push(retrieveGlyph(this, { stack, id }));
31
26
  }
32
- const fetchedGlyphs = await Promise.all(all);
33
- const result = {};
34
- for (const { stack, id, glyph } of fetchedGlyphs) {
35
- // Clone the glyph so that our own copy of its ArrayBuffer doesn't get transferred.
36
- (result[stack] ??= {})[id] = cloneGlyph(glyph);
37
- }
38
- return result;
39
-
40
- function cloneGlyph(glyph) {
41
- if (glyph) {
42
- return {
43
- id: glyph.id,
44
- bitmap: glyph.bitmap.clone(),
45
- metrics: glyph.metrics
46
- };
47
- }
27
+ }
28
+ const fetchedGlyphs = await Promise.all(all);
29
+ const result = {};
30
+ for (const { stack, id, glyph } of fetchedGlyphs) {
31
+ // Clone the glyph so that our own copy of its ArrayBuffer doesn't get transferred.
32
+ (result[stack] ??= {})[id] = cloneGlyph(glyph);
33
+ }
34
+ return result;
35
+
36
+ function cloneGlyph(glyph) {
37
+ if (glyph) {
38
+ return {
39
+ id: glyph.id,
40
+ bitmap: glyph.bitmap.clone(),
41
+ metrics: glyph.metrics
42
+ };
48
43
  }
44
+ }
49
45
 
50
- async function retrieveGlyph({ entries, loader, localIdeographFontFamily }, { stack, id }) {
51
- const entry = (entries[stack] ??= { glyphs: {}, requests: {} });
46
+ async function retrieveGlyph({ entries, loader, localIdeographFontFamily }, { stack, id }) {
47
+ const entry = (entries[stack] ??= { glyphs: {}, requests: {} });
52
48
 
53
- let glyph = entry.glyphs[id];
54
- if (glyph) {
55
- return { stack, id, glyph };
56
- }
49
+ let glyph = entry.glyphs[id];
50
+ if (glyph) {
51
+ return { stack, id, glyph };
52
+ }
57
53
 
58
- glyph = tinySDF(localIdeographFontFamily, entry, stack, id);
59
- if (glyph) {
60
- return { stack, id, glyph };
61
- }
54
+ glyph = tinySDF(localIdeographFontFamily, entry, stack, id);
55
+ if (glyph) {
56
+ return { stack, id, glyph };
57
+ }
62
58
 
63
- const range = Math.floor(id / 256);
64
- if (range * 256 > 65535) {
65
- throw new Error('glyphs > 65535 not supported');
66
- }
59
+ const range = Math.floor(id / 256);
60
+ if (range * 256 > 65535) {
61
+ throw new Error('glyphs > 65535 not supported');
62
+ }
67
63
 
68
- const promise = (entry.requests[range] ??= GlyphManager.loadGlyphRange(stack, range, loader));
69
- const response = await promise;
70
- if (response) {
71
- for (const id in response) {
72
- entry.glyphs[+id] = response[+id];
73
- }
64
+ const promise = (entry.requests[range] ??= GlyphManager.loadGlyphRange(stack, range, loader));
65
+ const response = await promise;
66
+ if (response) {
67
+ for (const id in response) {
68
+ entry.glyphs[+id] = response[+id];
74
69
  }
75
- delete entry.requests[range];
76
- return { stack, id, glyph: response?.[id] || null };
77
70
  }
71
+ delete entry.requests[range];
72
+ return { stack, id, glyph: response?.[id] || null };
78
73
  }
79
74
  }
80
75
  }
@@ -1,7 +1,7 @@
1
1
  const ShelfPack = require('@mapbox/shelf-pack');
2
2
 
3
3
  const { RGBAImage } = require('../util/image');
4
- const { register } = require('../util/web_worker_transfer');
4
+ const { register } = require('../util/transfer_registry');
5
5
 
6
6
  const padding = 1;
7
7
 
@@ -22,10 +22,9 @@ const padding = 1;
22
22
  to refactor this.
23
23
  */
24
24
  class ImageManager {
25
+ #loadedState = Promise.withResolvers();
25
26
  constructor() {
26
27
  this.images = {};
27
- this.loaded = false;
28
- this.requestors = [];
29
28
 
30
29
  this.shelfPack = new ShelfPack(64, 64, { autoResize: true });
31
30
  this.patterns = {};
@@ -34,22 +33,15 @@ class ImageManager {
34
33
  }
35
34
 
36
35
  isLoaded() {
37
- return this.loaded;
36
+ return !!this.#loadedState.loaded;
38
37
  }
39
38
 
40
- setLoaded(loaded) {
41
- if (this.loaded === loaded) {
39
+ setLoaded() {
40
+ if (this.#loadedState.loaded) {
42
41
  return;
43
42
  }
44
-
45
- this.loaded = loaded;
46
-
47
- if (loaded) {
48
- for (const { ids, callback } of this.requestors) {
49
- this._notify(ids, callback);
50
- }
51
- this.requestors = [];
52
- }
43
+ this.#loadedState.loaded = true;
44
+ this.#loadedState.resolve();
53
45
  }
54
46
 
55
47
  getImage(id) {
@@ -76,29 +68,10 @@ class ImageManager {
76
68
  return Object.keys(this.images);
77
69
  }
78
70
 
79
- getImages(ids, callback) {
80
- // If the sprite has been loaded, or if all the icon dependencies are already present
81
- // (i.e. if they've been addeded via runtime styling), then notify the requestor immediately.
82
- // Otherwise, delay notification until the sprite is loaded. At that point, if any of the
83
- // dependencies are still unavailable, we'll just assume they are permanently missing.
84
- let hasAllDependencies = true;
85
- if (!this.isLoaded()) {
86
- for (const id of ids) {
87
- if (!this.images[id]) {
88
- hasAllDependencies = false;
89
- }
90
- }
91
- }
92
- if (this.isLoaded() || hasAllDependencies) {
93
- this._notify(ids, callback);
94
- } else {
95
- this.requestors.push({ ids, callback });
96
- }
97
- }
71
+ async getImages(ids) {
72
+ await this.#loadedState.promise;
98
73
 
99
- _notify(ids, callback) {
100
74
  const response = {};
101
-
102
75
  for (const id of ids) {
103
76
  const image = this.images[id];
104
77
  if (image) {
@@ -110,8 +83,7 @@ class ImageManager {
110
83
  };
111
84
  }
112
85
  }
113
-
114
- callback(null, response);
86
+ return response;
115
87
  }
116
88
 
117
89
  // Pattern stuff