@mapwhit/tilerenderer 0.52.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +7 -0
  2. package/build/min/package.json +1 -1
  3. package/build/min/src/shaders/_prelude.fragment.glsl.js +2 -2
  4. package/build/min/src/shaders/_prelude.vertex.glsl.js +2 -2
  5. package/build/min/src/shaders/background.fragment.glsl.js +2 -2
  6. package/build/min/src/shaders/background.vertex.glsl.js +1 -1
  7. package/build/min/src/shaders/background_pattern.fragment.glsl.js +2 -2
  8. package/build/min/src/shaders/background_pattern.vertex.glsl.js +1 -1
  9. package/build/min/src/shaders/circle.fragment.glsl.js +2 -2
  10. package/build/min/src/shaders/circle.vertex.glsl.js +2 -2
  11. package/build/min/src/shaders/clipping_mask.fragment.glsl.js +1 -1
  12. package/build/min/src/shaders/clipping_mask.vertex.glsl.js +1 -1
  13. package/build/min/src/shaders/collision_box.fragment.glsl.js +1 -1
  14. package/build/min/src/shaders/collision_box.vertex.glsl.js +1 -1
  15. package/build/min/src/shaders/collision_circle.fragment.glsl.js +1 -1
  16. package/build/min/src/shaders/collision_circle.vertex.glsl.js +1 -1
  17. package/build/min/src/shaders/debug.fragment.glsl.js +1 -1
  18. package/build/min/src/shaders/debug.vertex.glsl.js +1 -1
  19. package/build/min/src/shaders/fill.fragment.glsl.js +2 -2
  20. package/build/min/src/shaders/fill.vertex.glsl.js +2 -2
  21. package/build/min/src/shaders/fill_extrusion.fragment.glsl.js +2 -2
  22. package/build/min/src/shaders/fill_extrusion.vertex.glsl.js +2 -2
  23. package/build/min/src/shaders/fill_extrusion_pattern.fragment.glsl.js +2 -2
  24. package/build/min/src/shaders/fill_extrusion_pattern.vertex.glsl.js +2 -2
  25. package/build/min/src/shaders/fill_outline.fragment.glsl.js +2 -2
  26. package/build/min/src/shaders/fill_outline.vertex.glsl.js +2 -2
  27. package/build/min/src/shaders/fill_outline_pattern.fragment.glsl.js +2 -2
  28. package/build/min/src/shaders/fill_outline_pattern.vertex.glsl.js +2 -2
  29. package/build/min/src/shaders/fill_pattern.fragment.glsl.js +2 -2
  30. package/build/min/src/shaders/fill_pattern.vertex.glsl.js +2 -2
  31. package/build/min/src/shaders/heatmap.fragment.glsl.js +2 -2
  32. package/build/min/src/shaders/heatmap.vertex.glsl.js +2 -2
  33. package/build/min/src/shaders/heatmap_texture.fragment.glsl.js +2 -2
  34. package/build/min/src/shaders/heatmap_texture.vertex.glsl.js +1 -1
  35. package/build/min/src/shaders/hillshade.fragment.glsl.js +2 -2
  36. package/build/min/src/shaders/hillshade.vertex.glsl.js +1 -1
  37. package/build/min/src/shaders/hillshade_prepare.fragment.glsl.js +2 -2
  38. package/build/min/src/shaders/hillshade_prepare.vertex.glsl.js +1 -1
  39. package/build/min/src/shaders/line.fragment.glsl.js +2 -2
  40. package/build/min/src/shaders/line.vertex.glsl.js +2 -2
  41. package/build/min/src/shaders/line_gradient.fragment.glsl.js +2 -2
  42. package/build/min/src/shaders/line_gradient.vertex.glsl.js +2 -2
  43. package/build/min/src/shaders/line_pattern.fragment.glsl.js +2 -2
  44. package/build/min/src/shaders/line_pattern.vertex.glsl.js +2 -2
  45. package/build/min/src/shaders/line_sdf.fragment.glsl.js +2 -2
  46. package/build/min/src/shaders/line_sdf.vertex.glsl.js +2 -2
  47. package/build/min/src/shaders/raster.fragment.glsl.js +2 -2
  48. package/build/min/src/shaders/raster.vertex.glsl.js +1 -1
  49. package/build/min/src/shaders/symbol_icon.fragment.glsl.js +2 -2
  50. package/build/min/src/shaders/symbol_icon.vertex.glsl.js +2 -2
  51. package/build/min/src/shaders/symbol_sdf.fragment.glsl.js +2 -2
  52. package/build/min/src/shaders/symbol_sdf.vertex.glsl.js +2 -2
  53. package/package.json +3 -3
  54. package/src/data/array_types.js +1 -36
  55. package/src/data/bucket/circle_bucket.js +8 -5
  56. package/src/data/bucket/fill_bucket.js +8 -5
  57. package/src/data/bucket/fill_extrusion_bucket.js +8 -5
  58. package/src/data/bucket/heatmap_bucket.js +0 -4
  59. package/src/data/bucket/line_bucket.js +9 -6
  60. package/src/data/bucket/pattern_bucket_features.js +2 -2
  61. package/src/data/bucket/symbol_bucket.js +99 -129
  62. package/src/data/bucket.js +26 -21
  63. package/src/data/dem_data.js +0 -3
  64. package/src/data/feature_index.js +3 -8
  65. package/src/data/program_configuration.js +24 -33
  66. package/src/data/segment.js +0 -4
  67. package/src/render/draw_background.js +3 -3
  68. package/src/render/draw_circle.js +4 -4
  69. package/src/render/draw_fill.js +8 -8
  70. package/src/render/draw_fill_extrusion.js +8 -8
  71. package/src/render/draw_heatmap.js +4 -4
  72. package/src/render/draw_line.js +6 -6
  73. package/src/render/draw_raster.js +6 -6
  74. package/src/render/draw_symbol.js +16 -16
  75. package/src/render/glyph_atlas.js +0 -3
  76. package/src/render/glyph_manager.js +1 -2
  77. package/src/render/image_atlas.js +0 -4
  78. package/src/render/image_manager.js +33 -19
  79. package/src/render/painter.js +13 -14
  80. package/src/render/program/circle_program.js +4 -4
  81. package/src/render/program/fill_extrusion_program.js +1 -1
  82. package/src/render/program/heatmap_program.js +1 -1
  83. package/src/render/program/hillshade_program.js +6 -6
  84. package/src/render/program/line_program.js +3 -3
  85. package/src/render/program/raster_program.js +6 -6
  86. package/src/source/geojson_source.js +15 -24
  87. package/src/source/geojson_worker_source.js +40 -68
  88. package/src/source/geojson_wrapper.js +9 -1
  89. package/src/source/image_source.js +6 -16
  90. package/src/source/query_features.js +4 -5
  91. package/src/source/raster_dem_tile_source.js +45 -64
  92. package/src/source/raster_tile_source.js +1 -6
  93. package/src/source/resources/glyphs.js +2 -2
  94. package/src/source/resources/index.js +3 -9
  95. package/src/source/rtl_text_plugin.js +58 -31
  96. package/src/source/source.js +11 -13
  97. package/src/source/source_cache.js +135 -151
  98. package/src/source/source_state.js +101 -12
  99. package/src/source/tile.js +32 -46
  100. package/src/source/tile_bounds.js +26 -26
  101. package/src/source/tile_id.js +2 -5
  102. package/src/source/vector_tile_source.js +14 -14
  103. package/src/source/vector_tile_worker_source.js +19 -23
  104. package/src/source/worker_tile.js +122 -119
  105. package/src/style/create_style_layer.js +1 -1
  106. package/src/style/pauseable_placement.js +4 -5
  107. package/src/style/properties.js +1 -8
  108. package/src/style/query_utils.js +3 -3
  109. package/src/style/style.js +286 -216
  110. package/src/style/style_layer/circle_style_layer.js +13 -11
  111. package/src/style/style_layer/fill_extrusion_style_layer.js +42 -27
  112. package/src/style/style_layer/fill_style_layer.js +5 -5
  113. package/src/style/style_layer/heatmap_style_layer.js +1 -1
  114. package/src/style/style_layer/hillshade_style_layer.js +1 -1
  115. package/src/style/style_layer/line_style_layer.js +23 -19
  116. package/src/style/style_layer/symbol_style_layer.js +13 -13
  117. package/src/style/style_layer.js +71 -30
  118. package/src/style/style_layer_index.js +16 -41
  119. package/src/symbol/anchor.js +0 -4
  120. package/src/symbol/cross_tile_symbol_index.js +2 -5
  121. package/src/symbol/opacity_state.js +0 -4
  122. package/src/symbol/placement.js +3 -3
  123. package/src/symbol/quads.js +4 -4
  124. package/src/symbol/symbol_layout.js +7 -7
  125. package/src/symbol/transform_text.js +1 -1
  126. package/src/ui/map.js +52 -15
  127. package/src/util/group_layers.js +41 -0
  128. package/src/util/image.js +0 -5
  129. package/src/util/key.js +21 -0
  130. package/src/util/object.js +8 -53
  131. package/src/worker.js +1 -4
  132. package/src/source/resources/images.js +0 -68
  133. package/src/source/worker.js +0 -110
  134. package/src/source/worker_source.js +0 -14
  135. package/src/style-spec/deref.js +0 -51
  136. package/src/style-spec/group_by_layout.js +0 -46
  137. package/src/util/actor.js +0 -108
  138. package/src/util/dispatcher.js +0 -65
  139. package/src/util/global_worker_pool.js +0 -15
  140. package/src/util/transfer_registry.js +0 -168
  141. package/src/util/web_worker_transfer.js +0 -43
  142. package/src/util/worker_pool.js +0 -41
@@ -2,6 +2,7 @@ const { Event, ErrorEvent, Evented } = require('@mapwhit/events');
2
2
 
3
3
  const EXTENT = require('../data/extent');
4
4
  const browser = require('../util/browser');
5
+ const GeoJSONWorkerSource = require('./geojson_worker_source');
5
6
 
6
7
  /**
7
8
  * A source containing GeoJSON.
@@ -52,8 +53,9 @@ class GeoJSONSource extends Evented {
52
53
  #pendingDataEvents = new Set();
53
54
  #newData = false;
54
55
  #updateInProgress = false;
56
+ #worker;
55
57
 
56
- constructor(id, options, dispatcher, eventedParent) {
58
+ constructor(id, options, eventedParent, { resources, layerIndex }) {
57
59
  super();
58
60
 
59
61
  this.id = id;
@@ -69,10 +71,9 @@ class GeoJSONSource extends Evented {
69
71
  this.reparseOverscaled = true;
70
72
  this._removed = false;
71
73
 
72
- this.dispatcher = dispatcher;
73
74
  this.setEventedParent(eventedParent);
74
75
 
75
- this._data = options.data;
76
+ this.data = options.data;
76
77
  this._options = Object.assign({}, options);
77
78
 
78
79
  if (options.maxzoom !== undefined) this.maxzoom = options.maxzoom;
@@ -107,6 +108,7 @@ class GeoJSONSource extends Evented {
107
108
  },
108
109
  options.workerOptions
109
110
  );
111
+ this.#worker = new GeoJSONWorkerSource(resources, layerIndex);
110
112
  }
111
113
 
112
114
  load() {
@@ -125,7 +127,7 @@ class GeoJSONSource extends Evented {
125
127
  * @returns {GeoJSONSource} this
126
128
  */
127
129
  setData(data) {
128
- this._data = data;
130
+ this.data = data;
129
131
  this.#updateData();
130
132
  return this;
131
133
  }
@@ -142,7 +144,7 @@ class GeoJSONSource extends Evented {
142
144
  this.fire(new Event('dataloading', { dataType: 'source' }));
143
145
  while (this.#newData) {
144
146
  this.#newData = false;
145
- await this._updateWorkerData(this._data);
147
+ await this._updateWorkerData(this.data);
146
148
  }
147
149
  this.#pendingDataEvents.forEach(sourceDataType =>
148
150
  this.fire(new Event('data', { dataType: 'source', sourceDataType }))
@@ -165,13 +167,9 @@ class GeoJSONSource extends Evented {
165
167
  if (!json) {
166
168
  throw new Error('no GeoJSON data');
167
169
  }
168
- const options = { ...this.workerOptions, data: JSON.stringify(json) };
169
- this.workerID ??= this.dispatcher.nextWorkerId();
170
+ const options = { ...this.workerOptions, data: json };
170
171
 
171
- // target {this.type}.loadData rather than literally geojson.loadData,
172
- // so that other geojson-like source types can easily reuse this
173
- // implementation
174
- await this.dispatcher.send(`${this.type}.loadData`, options, this.workerID);
172
+ return await this.#worker.loadData(options);
175
173
  }
176
174
 
177
175
  async loadTile(tile) {
@@ -185,14 +183,15 @@ class GeoJSONSource extends Evented {
185
183
  source: this.id,
186
184
  pixelRatio: browser.devicePixelRatio,
187
185
  showCollisionBoxes: this.map.showCollisionBoxes,
188
- globalState: this.map.getGlobalState()
186
+ globalState: this.map.getGlobalState(),
187
+ justReloaded: tile.workerID != null,
188
+ painter: this.map.painter
189
189
  };
190
190
 
191
- const justReloaded = tile.workerID != null;
192
- tile.workerID ??= this.dispatcher.nextWorkerId(this.workerID);
193
- const data = await this.dispatcher.send('loadTile', params, tile.workerID).finally(() => tile.unloadVectorData());
191
+ tile.workerID ??= true;
192
+ const data = await this.#worker.loadTile(params).finally(() => tile.unloadVectorData());
194
193
  if (!tile.aborted) {
195
- tile.loadVectorData(data, this.map.painter, justReloaded);
194
+ tile.loadVectorData(data, this.map.painter);
196
195
  }
197
196
  }
198
197
 
@@ -206,14 +205,6 @@ class GeoJSONSource extends Evented {
206
205
 
207
206
  onRemove() {
208
207
  this._removed = true;
209
- return this.dispatcher.send('removeSource', { type: this.type, source: this.id }, this.workerID);
210
- }
211
-
212
- serialize() {
213
- return Object.assign({}, this._options, {
214
- type: this.type,
215
- data: this._data
216
- });
217
208
  }
218
209
 
219
210
  hasTransition() {
@@ -1,68 +1,14 @@
1
1
  const rewind = require('@mapwhit/geojson-rewind');
2
2
  const GeoJSONWrapper = require('./geojson_wrapper');
3
- const { fromVectorTileJs } = require('@mapwhit/vt-pbf');
4
3
  const { default: Supercluster } = require('supercluster');
5
4
  const { default: geojsonvt } = require('geojson-vt');
6
5
  const VectorTileWorkerSource = require('./vector_tile_worker_source');
7
6
 
8
- function loadGeoJSONTile(params) {
9
- if (!this._geoJSONIndex) {
10
- if (!this._createGeoJSONIndex) {
11
- return; // we couldn't load the file
12
- }
13
-
14
- try {
15
- this._geoJSONIndex = this._createGeoJSONIndex();
16
- } finally {
17
- this._createGeoJSONIndex = null;
18
- }
19
- }
20
-
21
- const { z, x, y } = params.tileID.canonical;
22
- const geoJSONTile = this._geoJSONIndex.getTile(z, x, y);
23
- if (!geoJSONTile) {
24
- return; // nothing in the given tile
25
- }
26
-
27
- const geojsonWrapper = new GeoJSONWrapper(geoJSONTile.features);
28
-
29
- // Encode the geojson-vt tile into binary vector tile form. This
30
- // is a convenience that allows `FeatureIndex` to operate the same way
31
- // across `VectorTileSource` and `GeoJSONSource` data.
32
- let pbf = fromVectorTileJs(geojsonWrapper);
33
- if (pbf.byteOffset !== 0 || pbf.byteLength !== pbf.buffer.byteLength) {
34
- // Compatibility with node Buffer (https://github.com/mapbox/pbf/issues/35)
35
- pbf = new Uint8Array(pbf);
36
- }
37
-
38
- return {
39
- vectorTile: geojsonWrapper,
40
- rawData: pbf.buffer
41
- };
42
- }
43
-
44
7
  /**
45
8
  * The {@link WorkerSource} implementation that supports {@link GeoJSONSource}.
46
- * This class is designed to be easily reused to support custom source types
47
- * for data formats that can be parsed/converted into an in-memory GeoJSON
48
- * representation. To do so, create it with
49
- * `new GeoJSONWorkerSource(resources, layerIndex, customLoadGeoJSONFunction)`.
50
- * For a full example, see [mapbox-gl-topojson](https://github.com/developmentseed/mapbox-gl-topojson).
51
9
  *
52
10
  */
53
11
  class GeoJSONWorkerSource extends VectorTileWorkerSource {
54
- /**
55
- * @param [loadGeoJSON] Optional method for custom loading/parsing of
56
- * GeoJSON based on parameters passed from the main-thread Source.
57
- * See {@link GeoJSONWorkerSource#loadGeoJSON}.
58
- */
59
- constructor(resources, layerIndex, loadGeoJSON) {
60
- super(resources, layerIndex, loadGeoJSONTile);
61
- if (loadGeoJSON) {
62
- this.loadGeoJSON = loadGeoJSON;
63
- }
64
- }
65
-
66
12
  /**
67
13
  * Fetches (if appropriate), parses, and index geojson data into tiles. This
68
14
  * preparatory method must be called before {@link GeoJSONWorkerSource#loadTile}
@@ -76,7 +22,7 @@ class GeoJSONWorkerSource extends VectorTileWorkerSource {
76
22
  * @param callback
77
23
  */
78
24
  loadData(params) {
79
- const data = this.loadGeoJSON(params);
25
+ const data = loadJSON(params.data);
80
26
  this._geoJSONIndex = null;
81
27
  this._createGeoJSONIndex = params.cluster
82
28
  ? () => {
@@ -89,20 +35,46 @@ class GeoJSONWorkerSource extends VectorTileWorkerSource {
89
35
  };
90
36
  }
91
37
 
92
- /**
93
- * Fetch and parse GeoJSON according to the given params.
94
- *
95
- * GeoJSON is expected as a literal (string or object) `params.data`.
96
- *
97
- * @param params
98
- * @param [params.data] Literal GeoJSON data. Must be provided.
99
- */
100
- loadGeoJSON(params) {
101
- try {
102
- return JSON.parse(params.data);
103
- } catch (e) {
104
- throw new Error('Input data is not a valid GeoJSON object.');
38
+ getTile(tileID) {
39
+ if (!this._geoJSONIndex) {
40
+ if (!this._createGeoJSONIndex) {
41
+ return; // we couldn't load the file
42
+ }
43
+
44
+ try {
45
+ this._geoJSONIndex = this._createGeoJSONIndex();
46
+ } finally {
47
+ this._createGeoJSONIndex = null;
48
+ }
49
+ }
50
+ const { z, x, y } = tileID.canonical;
51
+ return this._geoJSONIndex.getTile(z, x, y);
52
+ }
53
+
54
+ loadVectorData({ tileID }) {
55
+ const geoJSONTile = this.getTile(tileID);
56
+ if (!geoJSONTile) {
57
+ return; // nothing in the given tile
105
58
  }
59
+
60
+ const vectorTile = new GeoJSONWrapper(geoJSONTile.features);
61
+
62
+ return {
63
+ vectorTile
64
+ };
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Fetch and parse GeoJSON according to the given params.
70
+ *
71
+ * @param data Literal GeoJSON data. Must be provided.
72
+ */
73
+ function loadJSON(data) {
74
+ try {
75
+ return typeof data === 'string' ? JSON.parse(data) : data;
76
+ } catch (e) {
77
+ throw new Error('Input data is not a valid GeoJSON object.');
106
78
  }
107
79
  }
108
80
 
@@ -20,6 +20,14 @@ class FeatureWrapper {
20
20
  if ('id' in feature && !isNaN(feature.id)) {
21
21
  this.id = Number.parseInt(feature.id, 10);
22
22
  }
23
+
24
+ // fix geometry - it has to be at least array of 2 points
25
+ if (typeof this._feature.geometry[0] === 'number') {
26
+ this._feature.geometry = [this._feature.geometry];
27
+ if (this._feature.geometry.length === 1) {
28
+ this._feature.geometry.push(this._feature.geometry[0]);
29
+ }
30
+ }
23
31
  }
24
32
 
25
33
  get type() {
@@ -27,7 +35,7 @@ class FeatureWrapper {
27
35
  }
28
36
 
29
37
  get properties() {
30
- return this._feature.tags;
38
+ return this._feature.tags ?? {};
31
39
  }
32
40
 
33
41
  get extent() {
@@ -2,7 +2,6 @@ const { getCoordinatesCenter } = require('../util/util');
2
2
 
3
3
  const { CanonicalTileID } = require('./tile_id');
4
4
  const LngLat = require('../geo/lng_lat');
5
- const { default: Point } = require('@mapbox/point-geometry');
6
5
  const { Event, ErrorEvent, Evented } = require('@mapwhit/events');
7
6
  const loadImage = require('../util/loader/image');
8
7
  const EXTENT = require('../data/extent');
@@ -44,10 +43,9 @@ class ImageSource extends Evented {
44
43
  /**
45
44
  * @private
46
45
  */
47
- constructor(id, options, dispatcher, eventedParent) {
46
+ constructor(id, options, eventedParent) {
48
47
  super();
49
48
  this.id = id;
50
- this.dispatcher = dispatcher;
51
49
  this.coordinates = options.coordinates;
52
50
 
53
51
  this.type = 'image';
@@ -125,10 +123,10 @@ class ImageSource extends Evented {
125
123
  // tile.
126
124
  const tileCoords = cornerZ0Coords.map(coord => {
127
125
  const zoomedCoord = coord.zoomTo(centerCoord.zoom);
128
- return new Point(
129
- Math.round((zoomedCoord.column - centerCoord.column) * EXTENT),
130
- Math.round((zoomedCoord.row - centerCoord.row) * EXTENT)
131
- );
126
+ return {
127
+ x: Math.round((zoomedCoord.column - centerCoord.column) * EXTENT),
128
+ y: Math.round((zoomedCoord.row - centerCoord.row) * EXTENT)
129
+ };
132
130
  });
133
131
 
134
132
  this._boundsArray = new RasterBoundsArray();
@@ -185,21 +183,13 @@ class ImageSource extends Evented {
185
183
  // single tile.
186
184
  if (this.tileID?.equals(tile.tileID.canonical)) {
187
185
  this.tiles[String(tile.tileID.wrap)] = tile;
188
- tile.buckets = {};
186
+ tile.buckets = new Map();
189
187
  } else {
190
188
  tile.state = 'errored';
191
189
  }
192
190
  return Promise.resolve();
193
191
  }
194
192
 
195
- serialize() {
196
- return {
197
- type: 'image',
198
- url: this.options.url,
199
- coordinates: this.coordinates
200
- };
201
- }
202
-
203
193
  hasTransition() {
204
194
  return false;
205
195
  }
@@ -20,14 +20,13 @@ function getPixelPosMatrix(transform, tileID) {
20
20
  function queryIncludes3DLayer(layers, styleLayers, sourceID) {
21
21
  if (layers) {
22
22
  for (const layerID of layers) {
23
- const layer = styleLayers[layerID];
23
+ const layer = styleLayers.get(layerID);
24
24
  if (layer && layer.source === sourceID && layer.type === 'fill-extrusion') {
25
25
  return true;
26
26
  }
27
27
  }
28
- } else {
29
- for (const key in styleLayers) {
30
- const layer = styleLayers[key];
28
+ } else if (styleLayers) {
29
+ for (const layer of styleLayers.values()) {
31
30
  if (layer.source === sourceID && layer.type === 'fill-extrusion') {
32
31
  return true;
33
32
  }
@@ -129,7 +128,7 @@ function queryRenderedSymbols(styleLayers, sourceCaches, queryGeometry, params,
129
128
  for (const layerName in result) {
130
129
  result[layerName].forEach(featureWrapper => {
131
130
  const feature = featureWrapper.feature;
132
- const layer = styleLayers[layerName];
131
+ const layer = styleLayers.get(layerName);
133
132
  const sourceCache = sourceCaches[layer.source];
134
133
  const state = sourceCache.getFeatureState(feature.layer['source-layer'], feature.id);
135
134
  feature.source = feature.layer.source;
@@ -1,35 +1,23 @@
1
1
  const browser = require('../util/browser');
2
2
  const loadImage = require('../util/loader/image');
3
- const { OverscaledTileID } = require('./tile_id');
3
+ const { calculateKey } = require('./tile_id');
4
4
  const RasterTileSource = require('./raster_tile_source');
5
- // ensure DEMData is registered for worker transfer on main thread:
6
- require('../data/dem_data');
5
+ const DEMData = require('../data/dem_data');
7
6
 
8
7
  class RasterDEMTileSource extends RasterTileSource {
9
- constructor(id, options, dispatcher, eventedParent) {
10
- super(id, options, dispatcher, eventedParent);
8
+ constructor(id, options, eventedParent) {
9
+ super(id, options, eventedParent);
11
10
  this.type = 'raster-dem';
12
11
  this.maxzoom = 22;
13
12
  this._options = Object.assign({}, options);
14
13
  this.encoding = options.encoding || 'mapbox';
15
14
  }
16
15
 
17
- serialize() {
18
- return {
19
- type: 'raster-dem',
20
- url: this.url,
21
- tileSize: this.tileSize,
22
- tiles: this.tiles,
23
- bounds: this.bounds,
24
- encoding: this.encoding
25
- };
26
- }
27
-
28
16
  async loadTile(tile) {
29
17
  try {
30
18
  tile.abortController = new window.AbortController();
31
19
  const data = await this.tiles(tile.tileID.canonical, tile.abortController).catch(() => {});
32
- tile.neighboringTiles = this._getNeighboringTiles(tile.tileID);
20
+ tile.neighboringTiles = getNeighboringTiles(tile.tileID);
33
21
  if (!data) {
34
22
  const err = new Error('Tile could not be loaded');
35
23
  err.status = 404; // will try to use the parent/child tile
@@ -48,7 +36,7 @@ class RasterDEMTileSource extends RasterTileSource {
48
36
  rawImageData,
49
37
  encoding: this.encoding
50
38
  };
51
- const dem = await this.dispatcher.send('loadDEMTile', params);
39
+ const dem = await loadDEMTile(params);
52
40
  if (dem) {
53
41
  tile.dem = dem;
54
42
  tile.needsHillshadePrepare = true;
@@ -65,52 +53,6 @@ class RasterDEMTileSource extends RasterTileSource {
65
53
  }
66
54
  }
67
55
 
68
- _getNeighboringTiles(tileID) {
69
- const canonical = tileID.canonical;
70
- const dim = 2 ** canonical.z;
71
-
72
- const px = (canonical.x - 1 + dim) % dim;
73
- const pxw = canonical.x === 0 ? tileID.wrap - 1 : tileID.wrap;
74
- const nx = (canonical.x + 1 + dim) % dim;
75
- const nxw = canonical.x + 1 === dim ? tileID.wrap + 1 : tileID.wrap;
76
-
77
- const neighboringTiles = {};
78
- // add adjacent tiles
79
- neighboringTiles[new OverscaledTileID(tileID.overscaledZ, pxw, canonical.z, px, canonical.y).key] = {
80
- backfilled: false
81
- };
82
- neighboringTiles[new OverscaledTileID(tileID.overscaledZ, nxw, canonical.z, nx, canonical.y).key] = {
83
- backfilled: false
84
- };
85
-
86
- // Add upper neighboringTiles
87
- if (canonical.y > 0) {
88
- neighboringTiles[new OverscaledTileID(tileID.overscaledZ, pxw, canonical.z, px, canonical.y - 1).key] = {
89
- backfilled: false
90
- };
91
- neighboringTiles[
92
- new OverscaledTileID(tileID.overscaledZ, tileID.wrap, canonical.z, canonical.x, canonical.y - 1).key
93
- ] = { backfilled: false };
94
- neighboringTiles[new OverscaledTileID(tileID.overscaledZ, nxw, canonical.z, nx, canonical.y - 1).key] = {
95
- backfilled: false
96
- };
97
- }
98
- // Add lower neighboringTiles
99
- if (canonical.y + 1 < dim) {
100
- neighboringTiles[new OverscaledTileID(tileID.overscaledZ, pxw, canonical.z, px, canonical.y + 1).key] = {
101
- backfilled: false
102
- };
103
- neighboringTiles[
104
- new OverscaledTileID(tileID.overscaledZ, tileID.wrap, canonical.z, canonical.x, canonical.y + 1).key
105
- ] = { backfilled: false };
106
- neighboringTiles[new OverscaledTileID(tileID.overscaledZ, nxw, canonical.z, nx, canonical.y + 1).key] = {
107
- backfilled: false
108
- };
109
- }
110
-
111
- return neighboringTiles;
112
- }
113
-
114
56
  unloadTile(tile) {
115
57
  if (tile.demTexture) this.map.painter.saveTileTexture(tile.demTexture);
116
58
  if (tile.fbo) {
@@ -124,4 +66,43 @@ class RasterDEMTileSource extends RasterTileSource {
124
66
  }
125
67
  }
126
68
 
69
+ // biome-ignore lint/suspicious/useAwait: thread
70
+ async function loadDEMTile({ uid, rawImageData, encoding }) {
71
+ return new DEMData(uid, rawImageData, encoding);
72
+ }
73
+
127
74
  module.exports = RasterDEMTileSource;
75
+
76
+ function getNeighboringTiles(tileID) {
77
+ const {
78
+ canonical: { x, y, z },
79
+ wrap,
80
+ overscaledZ
81
+ } = tileID;
82
+ const dim = 2 ** z;
83
+ const px = (x - 1 + dim) % dim;
84
+ const pxw = x === 0 ? wrap - 1 : wrap;
85
+ const nx = (x + 1 + dim) % dim;
86
+ const nxw = x + 1 === dim ? wrap + 1 : wrap;
87
+
88
+ const neighboringTiles = {
89
+ // add adjacent tiles
90
+ [calculateKey(pxw, overscaledZ, px, y)]: { backfilled: false },
91
+ [calculateKey(nxw, overscaledZ, nx, y)]: { backfilled: false }
92
+ };
93
+
94
+ // Add upper neighboringTiles
95
+ if (y > 0) {
96
+ neighboringTiles[calculateKey(pxw, overscaledZ, px, y - 1)] = { backfilled: false };
97
+ neighboringTiles[calculateKey(wrap, overscaledZ, x, y - 1)] = { backfilled: false };
98
+ neighboringTiles[calculateKey(nxw, overscaledZ, nx, y - 1)] = { backfilled: false };
99
+ }
100
+ // Add lower neighboringTiles
101
+ if (y + 1 < dim) {
102
+ neighboringTiles[calculateKey(pxw, overscaledZ, px, y + 1)] = { backfilled: false };
103
+ neighboringTiles[calculateKey(wrap, overscaledZ, x, y + 1)] = { backfilled: false };
104
+ neighboringTiles[calculateKey(nxw, overscaledZ, nx, y + 1)] = { backfilled: false };
105
+ }
106
+
107
+ return neighboringTiles;
108
+ }
@@ -6,10 +6,9 @@ const TileBounds = require('./tile_bounds');
6
6
  const Texture = require('../render/texture');
7
7
 
8
8
  class RasterTileSource extends Evented {
9
- constructor(id, options, dispatcher, eventedParent) {
9
+ constructor(id, options, eventedParent) {
10
10
  super();
11
11
  this.id = id;
12
- this.dispatcher = dispatcher;
13
12
  this.setEventedParent(eventedParent);
14
13
 
15
14
  this.type = 'raster';
@@ -46,10 +45,6 @@ class RasterTileSource extends Evented {
46
45
  this.load();
47
46
  }
48
47
 
49
- serialize() {
50
- return Object.assign({}, this._options);
51
- }
52
-
53
48
  hasTile(tileID) {
54
49
  return !this.tileBounds || this.tileBounds.contains(tileID.canonical);
55
50
  }
@@ -4,7 +4,7 @@ module.exports = glyphCache;
4
4
 
5
5
  const MAX_GLYPH_ID = 65535;
6
6
 
7
- function glyphCache({ actor, mapId, parseGlyphs = parseGlyphPBF }) {
7
+ function glyphCache({ loadGlyphRange: loadGlyphRangeFromStyle, parseGlyphs = parseGlyphPBF }) {
8
8
  const entries = {};
9
9
 
10
10
  return {
@@ -56,7 +56,7 @@ function glyphCache({ actor, mapId, parseGlyphs = parseGlyphPBF }) {
56
56
  }
57
57
 
58
58
  async function loadGlyphRange(entry, stack, range) {
59
- const promise = (entry.requests[range] ??= actor.send('loadGlyphRange', { stack, range }, mapId));
59
+ const promise = (entry.requests[range] ??= loadGlyphRangeFromStyle({ stack, range }));
60
60
  const data = await promise;
61
61
  delete entry.requests[range];
62
62
  entry.ranges[range] = true;
@@ -1,22 +1,16 @@
1
1
  const makeGlyphs = require('./glyphs');
2
- const makeImages = require('./images');
3
2
 
4
3
  module.exports = { resources };
5
4
 
6
- function resources(actor, mapId) {
7
- const glyphs = makeGlyphs({ actor, mapId });
8
- const images = makeImages({ actor, mapId });
5
+ function resources(opts) {
6
+ const glyphs = makeGlyphs(opts);
9
7
 
10
8
  return {
11
9
  getGlyphs,
12
- getImages
10
+ getImages: opts.getImages
13
11
  };
14
12
 
15
13
  function getGlyphs(params) {
16
14
  return glyphs.getGlyphs(params);
17
15
  }
18
-
19
- function getImages(params) {
20
- return images.getImages(params);
21
- }
22
16
  }
@@ -1,26 +1,34 @@
1
- const { Event, Evented } = require('@mapwhit/events');
1
+ const dynload = require('dynload');
2
2
  const browser = require('../util/browser');
3
3
 
4
4
  let pluginRequested = false;
5
- let pluginURL = null;
6
- let foregroundLoadComplete = false;
7
-
8
- const evented = new Evented();
5
+ let pluginURL;
6
+ let loading = false;
9
7
 
10
8
  let _completionCallback;
9
+ const _loadedCallbacks = [];
10
+
11
+ const rtlPlugin = {
12
+ clearRTLTextPlugin, // exported for testing
13
+ loadScript, // exported for testing
14
+ registerForPluginAvailability,
15
+ setRTLTextPlugin
16
+ };
11
17
 
12
18
  function registerForPluginAvailability(callback) {
13
- if (pluginURL) {
14
- callback({ pluginURL: pluginURL, completionCallback: _completionCallback });
15
- } else {
16
- evented.once('pluginAvailable', callback);
19
+ if (plugin.isLoaded()) {
20
+ callback();
21
+ return;
17
22
  }
18
- return callback;
23
+ _loadedCallbacks.push(callback);
24
+ loadRTLTextPlugin();
25
+ return () => _loadedCallbacks.splice(_loadedCallbacks.indexOf(callback), 1);
19
26
  }
20
27
 
21
28
  function clearRTLTextPlugin() {
29
+ _loadedCallbacks.length = 0;
22
30
  pluginRequested = false;
23
- pluginURL = null;
31
+ pluginURL = undefined;
24
32
  }
25
33
 
26
34
  function setRTLTextPlugin(url, callback) {
@@ -31,35 +39,54 @@ function setRTLTextPlugin(url, callback) {
31
39
  pluginURL = browser.resolveURL(url);
32
40
  _completionCallback = error => {
33
41
  if (error) {
42
+ const msg = `RTL Text Plugin failed to load scripts from ${pluginURL}`;
34
43
  // Clear loaded state to allow retries
35
44
  clearRTLTextPlugin();
36
45
  if (callback) {
37
- callback(error);
46
+ callback(new Error(msg));
38
47
  }
39
- } else {
40
- // Called once for each worker
41
- foregroundLoadComplete = true;
42
48
  }
49
+ loading = false;
50
+ _completionCallback = undefined;
43
51
  };
44
- evented.fire(new Event('pluginAvailable', { pluginURL: pluginURL, completionCallback: _completionCallback }));
52
+ loadRTLTextPlugin();
53
+ }
54
+
55
+ function loadRTLTextPlugin() {
56
+ if (pluginURL && !plugin.isLoaded() && _loadedCallbacks.length > 0 && !loading) {
57
+ // needs to be called as exported method for mock testing
58
+ loading = rtlPlugin.loadScript(pluginURL).catch(_completionCallback);
59
+ }
60
+ }
61
+
62
+ function registerRTLTextPlugin(loadedPlugin) {
63
+ if (plugin.isLoaded()) {
64
+ throw new Error('RTL text plugin already registered.');
65
+ }
66
+ plugin['applyArabicShaping'] = loadedPlugin.applyArabicShaping;
67
+ plugin['processBidirectionalText'] = loadedPlugin.processBidirectionalText;
68
+ plugin['processStyledBidirectionalText'] = loadedPlugin.processStyledBidirectionalText;
69
+
70
+ _completionCallback();
71
+ _loadedCallbacks.forEach(callback => callback());
72
+ _loadedCallbacks.length = 0;
73
+ }
74
+
75
+ globalThis.registerRTLTextPlugin ??= registerRTLTextPlugin;
76
+
77
+ async function loadScript(url) {
78
+ const { promise, resolve, reject } = Promise.withResolvers();
79
+ const s = dynload(url);
80
+ s.onload = () => resolve();
81
+ s.onerror = () => reject(true);
82
+ return promise;
45
83
  }
46
84
 
47
- const plugin = {
85
+ const plugin = (rtlPlugin.plugin = {
48
86
  applyArabicShaping: null,
49
87
  processBidirectionalText: null,
50
88
  processStyledBidirectionalText: null,
51
- isLoaded: function () {
52
- return (
53
- foregroundLoadComplete || // Foreground: loaded if the completion callback returned successfully
54
- plugin.applyArabicShaping != null
55
- ); // Background: loaded if the plugin functions have been compiled
56
- }
57
- };
89
+ isLoaded: () => plugin.applyArabicShaping != null
90
+ });
58
91
 
59
- module.exports = {
60
- registerForPluginAvailability,
61
- clearRTLTextPlugin,
62
- setRTLTextPlugin,
63
- plugin,
64
- evented
65
- };
92
+ module.exports = rtlPlugin;