@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
@@ -22,7 +22,7 @@ const { GLYPH_PBF_BORDER } = require('../style/parse_glyph_pbf');
22
22
  */
23
23
  function getIconQuads(anchor, shapedIcon, layer, alongLine, shapedText, feature) {
24
24
  const image = shapedIcon.image;
25
- const layout = layer.layout;
25
+ const layout = layer._layout;
26
26
 
27
27
  // If you have a 10px icon that isn't perfectly aligned to the pixel grid it will cover 11 actual
28
28
  // pixels. The quad needs to be padded to account for this, otherwise they'll look slightly clipped
@@ -71,7 +71,7 @@ function getIconQuads(anchor, shapedIcon, layer, alongLine, shapedText, feature)
71
71
  bl = new Point(left, bottom);
72
72
  }
73
73
 
74
- const angle = (layer.layout.get('icon-rotate').evaluate(feature, {}) * Math.PI) / 180;
74
+ const angle = (layer._layout.get('icon-rotate').evaluate(feature, {}) * Math.PI) / 180;
75
75
 
76
76
  if (angle) {
77
77
  const sin = Math.sin(angle);
@@ -94,8 +94,8 @@ function getIconQuads(anchor, shapedIcon, layer, alongLine, shapedText, feature)
94
94
  */
95
95
  function getGlyphQuads(anchor, shaping, layer, alongLine, feature, positions) {
96
96
  const oneEm = 24;
97
- const textRotate = (layer.layout.get('text-rotate').evaluate(feature, {}) * Math.PI) / 180;
98
- const textOffset = layer.layout
97
+ const textRotate = (layer._layout.get('text-rotate').evaluate(feature, {}) * Math.PI) / 180;
98
+ const textOffset = layer._layout
99
99
  .get('text-offset')
100
100
  .evaluate(feature, {})
101
101
  .map(t => t * oneEm);
@@ -26,7 +26,7 @@ const murmur3 = require('murmurhash-js');
26
26
  // 5. For composite `*-size` expressions: two zoom levels of curve stops that "cover" the zoom level of the
27
27
  // bucket. These go into a vertex buffer and are used by the shader to interpolate the size at render time.
28
28
  //
29
- // (1) and (2) are stored in `bucket.layers[0].layout`. The remainder are below.
29
+ // (1) and (2) are stored in `bucket.layers[0]._layout`. The remainder are below.
30
30
  //
31
31
 
32
32
  function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap, imagePositions, showCollisionBoxes) {
@@ -37,7 +37,7 @@ function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap, imagePo
37
37
  bucket.compareText = {};
38
38
  bucket.iconsNeedLinear = false;
39
39
 
40
- const layout = bucket.layers[0].layout;
40
+ const layout = bucket.layers[0]._layout;
41
41
  const unevaluatedLayoutValues = bucket.layers[0]._unevaluatedLayout._values;
42
42
 
43
43
  const sizes = {};
@@ -172,7 +172,7 @@ function addFeature(bucket, feature, shapedTextOrientations, shapedIcon, glyphPo
172
172
  textMaxSize = layoutTextSize;
173
173
  }
174
174
 
175
- const layout = bucket.layers[0].layout;
175
+ const layout = bucket.layers[0]._layout;
176
176
  const textOffset = layout.get('text-offset').evaluate(feature, {});
177
177
  const iconOffset = layout.get('icon-offset').evaluate(feature, {});
178
178
 
@@ -301,7 +301,7 @@ function addTextVertices(
301
301
  let textSizeData = null;
302
302
 
303
303
  if (sizeData.functionType === 'source') {
304
- textSizeData = [10 * layer.layout.get('text-size').evaluate(feature, {})];
304
+ textSizeData = [10 * layer._layout.get('text-size').evaluate(feature, {})];
305
305
  } else if (sizeData.functionType === 'composite') {
306
306
  textSizeData = [
307
307
  10 * sizes.compositeTextSizes[0].evaluate(feature, {}),
@@ -370,7 +370,7 @@ function addSymbol(
370
370
  if (shapedTextOrientations.horizontal) {
371
371
  // As a collision approximation, we can use either the vertical or the horizontal version of the feature
372
372
  // We're counting on the two versions having similar dimensions
373
- const textRotate = layer.layout.get('text-rotate').evaluate(feature, {});
373
+ const textRotate = layer._layout.get('text-rotate').evaluate(feature, {});
374
374
  textCollisionFeature = new CollisionFeature(
375
375
  collisionBoxArray,
376
376
  line,
@@ -430,7 +430,7 @@ function addSymbol(
430
430
  shapedTextOrientations.horizontal,
431
431
  feature
432
432
  );
433
- const iconRotate = layer.layout.get('icon-rotate').evaluate(feature, {});
433
+ const iconRotate = layer._layout.get('icon-rotate').evaluate(feature, {});
434
434
  iconCollisionFeature = new CollisionFeature(
435
435
  collisionBoxArray,
436
436
  line,
@@ -452,7 +452,7 @@ function addSymbol(
452
452
  let iconSizeData = null;
453
453
 
454
454
  if (sizeData.functionType === 'source') {
455
- iconSizeData = [10 * layer.layout.get('icon-size').evaluate(feature, {})];
455
+ iconSizeData = [10 * layer._layout.get('icon-size').evaluate(feature, {})];
456
456
  } else if (sizeData.functionType === 'composite') {
457
457
  iconSizeData = [
458
458
  10 * sizes.compositeIconSizes[0].evaluate(feature, {}),
@@ -1,7 +1,7 @@
1
1
  const { plugin: rtlTextPlugin } = require('../source/rtl_text_plugin');
2
2
 
3
3
  function transformText(text, layer, feature) {
4
- const transform = layer.layout.get('text-transform').evaluate(feature, {});
4
+ const transform = layer._layout.get('text-transform').evaluate(feature, {});
5
5
  if (transform === 'uppercase') {
6
6
  text = text.toLocaleUpperCase();
7
7
  } else if (transform === 'lowercase') {
package/src/ui/map.js CHANGED
@@ -41,10 +41,6 @@ const defaultOptions = {
41
41
 
42
42
  renderWorldCopies: true,
43
43
 
44
- refreshExpiredTiles: true,
45
-
46
- maxTileCacheSize: null,
47
-
48
44
  transformRequest: null,
49
45
  fadeDuration: 300,
50
46
  crossSourceCollisions: true
@@ -98,7 +94,6 @@ const defaultOptions = {
98
94
  * @param {number} [options.bearing=0] The initial bearing (rotation) of the map, measured in degrees counter-clockwise from north. If `bearing` is not specified in the constructor options, Mapbox GL JS will look for it in the map's style object. If it is not specified in the style, either, it will default to `0`.
99
95
  * @param {number} [options.pitch=0] The initial pitch (tilt) of the map, measured in degrees away from the plane of the screen (0-60). If `pitch` is not specified in the constructor options, Mapbox GL JS will look for it in the map's style object. If it is not specified in the style, either, it will default to `0`.
100
96
  * @param {boolean} [options.renderWorldCopies=true] If `true`, multiple copies of the world will be rendered, when zoomed out.
101
- * @param {number} [options.maxTileCacheSize=null] The maximum number of tiles stored in the tile cache for a given source. If omitted, the cache will be dynamically sized based on the current viewport.
102
97
  * @param {number} [options.fadeDuration=300] Controls the duration of the fade-in/fade-out animation for label collisions, in milliseconds. This setting affects all symbol layers. This setting does not affect the duration of runtime styling transitions or raster tile cross-fading.
103
98
  * @param {boolean} [options.crossSourceCollisions=true] If `true`, symbols from multiple sources can collide with each other during collision detection. If `false`, collision detection is run separately for the symbols in each source.
104
99
  * @example
@@ -125,7 +120,6 @@ class Map extends Camera {
125
120
  this.loadImage = loadImage;
126
121
 
127
122
  this._interactive = options.interactive;
128
- this._maxTileCacheSize = options.maxTileCacheSize;
129
123
  this._failIfMajorPerformanceCaveat = options.failIfMajorPerformanceCaveat;
130
124
  this._preserveDrawingBuffer = options.preserveDrawingBuffer;
131
125
  this._trackResize = options.trackResize;
@@ -205,14 +199,13 @@ class Map extends Camera {
205
199
  * Sets a global state property that can be retrieved with the [`global-state` expression](https://maplibre.org/maplibre-style-spec/expressions/#global-state).
206
200
  * If the value is null, it resets the property to its default value defined in the [`state` style property](https://maplibre.org/maplibre-style-spec/root/#state).
207
201
  *
208
- * Note that changing `global-state` values defined in layout properties is not supported, and will be ignored.
209
- *
210
202
  * @param propertyName - The name of the state property to set.
211
203
  * @param value - The value of the state property to set.
212
204
  */
213
205
  setGlobalStateProperty(propertyName, value) {
214
- this.style.setGlobalStateProperty(propertyName, value);
215
- return this._update(true);
206
+ if (!this.style.setGlobalStateProperty(propertyName, value)) {
207
+ return this._update(true);
208
+ }
216
209
  }
217
210
 
218
211
  /**
@@ -688,7 +681,7 @@ class Map extends Camera {
688
681
  */
689
682
  getStyle() {
690
683
  if (this.style) {
691
- return this.style.serialize();
684
+ return this.style.serialize?.() ?? this.style;
692
685
  }
693
686
  }
694
687
 
@@ -728,7 +721,7 @@ class Map extends Camera {
728
721
  * @returns {boolean} A Boolean indicating whether the source is loaded.
729
722
  */
730
723
  isSourceLoaded(id) {
731
- const source = this.style?.sourceCaches[id];
724
+ const source = this.style?._sources[id];
732
725
  if (source === undefined) {
733
726
  this.fire(new ErrorEvent(new Error(`There is no source with ID '${id}'`)));
734
727
  return;
@@ -744,12 +737,11 @@ class Map extends Camera {
744
737
  */
745
738
 
746
739
  areTilesLoaded() {
747
- const sources = this.style?.sourceCaches;
740
+ const sources = this.style?._sources;
748
741
  for (const id in sources) {
749
742
  const source = sources[id];
750
743
  const tiles = source._tiles;
751
- for (const t in tiles) {
752
- const tile = tiles[t];
744
+ for (const tile of tiles.values()) {
753
745
  if (!(tile.state === 'loaded' || tile.state === 'errored')) return false;
754
746
  }
755
747
  }
@@ -799,6 +791,16 @@ class Map extends Camera {
799
791
  */
800
792
  addImage(id, image, { pixelRatio = 1, sdf = false } = {}) {
801
793
  if (image instanceof HTMLImageElement) {
794
+ if (!image.complete) {
795
+ const promise = new Promise(resolve => {
796
+ image.decode().then(() => {
797
+ const { width, height, data } = browser.getImageData(image);
798
+ resolve({ data: new RGBAImage({ width, height }, data), pixelRatio, sdf });
799
+ });
800
+ });
801
+ this.style.addImage(id, { promise });
802
+ return;
803
+ }
802
804
  const { width, height, data } = browser.getImageData(image);
803
805
  this.style.addImage(id, { data: new RGBAImage({ width, height }, data), pixelRatio, sdf });
804
806
  } else if (image.width === undefined || image.height === undefined) {
@@ -820,6 +822,23 @@ class Map extends Camera {
820
822
  }
821
823
  }
822
824
 
825
+ /**
826
+ * Returns an image, specified by ID, currently available in the map.
827
+ * This includes both images from the style's original sprite
828
+ * and any images that have been added at runtime using {@link Map.addImage}.
829
+ *
830
+ * @param id - The ID of the image.
831
+ * @returns An image in the map with the specified ID.
832
+ *
833
+ * @example
834
+ * ```js
835
+ * let coffeeShopIcon = map.getImage("coffee_cup");
836
+ * ```
837
+ */
838
+ getImage(id) {
839
+ return this.style.getImage(id);
840
+ }
841
+
823
842
  /**
824
843
  * Define wether the image has been added or not
825
844
  *
@@ -1055,6 +1074,24 @@ class Map extends Camera {
1055
1074
  this._update();
1056
1075
  }
1057
1076
 
1077
+ /**
1078
+ * Removes feature state, setting it back to the default behavior. If only
1079
+ * source is specified, removes all states of that source. If
1080
+ * target.id is also specified, removes all keys for that feature's state.
1081
+ * If key is also specified, removes that key from that feature's state.
1082
+ *
1083
+ * @param {Object} target Identifier of where to set state: can be a source, a feature, or a specific key of feature.
1084
+ * Feature objects returned from {@link Map#queryRenderedFeatures} or event handlers can be used as feature identifiers.
1085
+ * @param {string | number} target.id (optional) Unique id of the feature. Optional if key is not specified.
1086
+ * @param {string} target.source The Id of the vector source or GeoJSON source for the feature.
1087
+ * @param {string} [target.sourceLayer] (optional) *For vector tile sources, the sourceLayer is
1088
+ * required.*
1089
+ * @param {string} key (optional) The key in the feature state to reset.
1090
+ */
1091
+ removeFeatureState(target, key) {
1092
+ this.style.removeFeatureState(target, key);
1093
+ return this._update();
1094
+ }
1058
1095
  /**
1059
1096
  * Gets the state of a feature.
1060
1097
  *
@@ -0,0 +1,41 @@
1
+ module.exports = groupBySource;
2
+
3
+ /**
4
+ * Given an collection of layers, divide them by property 'source', then by 'source-layer',
5
+ * and then by layout-affecting properties: 'type', , 'minzoom', 'maxzoom', 'filter', and 'layout'.
6
+ *
7
+ * The input is not modified. The output layers are references to the
8
+ * input layers.
9
+ *
10
+ * @param layers iterable collection of layers
11
+ * @returns Map source to {Map source-layer to {Map layout key to Array of layers}}
12
+ */
13
+ function groupBySource(layers) {
14
+ const groups = new Map();
15
+
16
+ // Iterate through each layer and group them by source, source-layer, and layout properties
17
+ for (const layer of layers) {
18
+ if (layer.visibility === 'none') {
19
+ continue;
20
+ }
21
+
22
+ const { source = '', sourceLayer = '_geojsonTileLayer' } = layer;
23
+ let sourceGroup = groups.get(source);
24
+ if (!sourceGroup) {
25
+ sourceGroup = new Map();
26
+ groups.set(source, sourceGroup);
27
+ }
28
+ let sourceLayerGroup = sourceGroup.get(sourceLayer);
29
+ if (!sourceLayerGroup) {
30
+ sourceLayerGroup = new Map();
31
+ sourceGroup.set(sourceLayer, sourceLayerGroup);
32
+ }
33
+ let layoutGroup = sourceLayerGroup.get(layer.key);
34
+ if (!layoutGroup) {
35
+ layoutGroup = [];
36
+ sourceLayerGroup.set(layer.key, layoutGroup);
37
+ }
38
+ layoutGroup.push(layer);
39
+ }
40
+ return groups;
41
+ }
package/src/util/image.js CHANGED
@@ -1,7 +1,5 @@
1
1
  const assert = require('assert');
2
2
 
3
- const { register } = require('./transfer_registry');
4
-
5
3
  function createImage(image, { width, height }, channels, data) {
6
4
  if (!data) {
7
5
  data = new Uint8Array(width * height * channels);
@@ -115,9 +113,6 @@ class RGBAImage {
115
113
  }
116
114
  }
117
115
 
118
- register('AlphaImage', AlphaImage);
119
- register('RGBAImage', RGBAImage);
120
-
121
116
  module.exports = {
122
117
  AlphaImage,
123
118
  RGBAImage
@@ -0,0 +1,21 @@
1
+ module.exports = createKey;
2
+
3
+ function stringify(obj) {
4
+ if (obj == null) return 'null';
5
+ const type = typeof obj;
6
+ if (type === 'number' || type === 'boolean' || type === 'string') return obj;
7
+
8
+ if (Array.isArray(obj)) {
9
+ return '[' + obj.map(val => stringify(val)).join(',') + ']';
10
+ }
11
+
12
+ const keys = Object.keys(obj).sort();
13
+ return '{' + keys.map(key => `${key}:${stringify(obj[key])}`).join(',') + '}';
14
+ }
15
+
16
+ /**
17
+ * Create a unique key for an based on its properties.
18
+ */
19
+ function createKey(properties, object) {
20
+ return properties.map(k => stringify(object[k])).join('/');
21
+ }
@@ -1,34 +1,3 @@
1
- /*
2
- * Polyfill for Object.values. Not fully spec compliant, but we don't
3
- * need it to be.
4
- *
5
- * @private
6
- */
7
- function values(obj) {
8
- const result = [];
9
- for (const k in obj) {
10
- result.push(obj[k]);
11
- }
12
- return result;
13
- }
14
-
15
- /*
16
- * Compute the difference between the keys in one object and the keys
17
- * in another object.
18
- *
19
- * @returns keys difference
20
- * @private
21
- */
22
- function keysDifference(obj, other) {
23
- const difference = [];
24
- for (const i in obj) {
25
- if (!(i in other)) {
26
- difference.push(i);
27
- }
28
- }
29
- return difference;
30
- }
31
-
32
1
  /**
33
2
  * Given an object and a number of properties as strings, return version
34
3
  * of that object with only those properties.
@@ -44,14 +13,8 @@ function keysDifference(obj, other) {
44
13
  * @private
45
14
  */
46
15
  function pick(src, properties) {
47
- const result = {};
48
- for (let i = 0; i < properties.length; i++) {
49
- const k = properties[i];
50
- if (k in src) {
51
- result[k] = src[k];
52
- }
53
- }
54
- return result;
16
+ const entries = properties.filter(p => p in src).map(p => [p, src[p]]);
17
+ return Object.fromEntries(entries);
55
18
  }
56
19
 
57
20
  /**
@@ -91,11 +54,9 @@ function bindAll(fns, context) {
91
54
  * @private
92
55
  */
93
56
  function mapObject(input, iterator, context) {
94
- const output = {};
95
- for (const key in input) {
96
- output[key] = iterator.call(context || this, input[key], key, input);
97
- }
98
- return output;
57
+ context ??= this;
58
+ const entries = Object.entries(input).map(([k, v]) => [k, iterator.call(context, v, k, input)]);
59
+ return Object.fromEntries(entries);
99
60
  }
100
61
 
101
62
  /**
@@ -104,13 +65,9 @@ function mapObject(input, iterator, context) {
104
65
  * @private
105
66
  */
106
67
  function filterObject(input, iterator, context) {
107
- const output = {};
108
- for (const key in input) {
109
- if (iterator.call(context || this, input[key], key, input)) {
110
- output[key] = input[key];
111
- }
112
- }
113
- return output;
68
+ context ??= this;
69
+ const entries = Object.entries(input).filter(([k, v]) => iterator.call(context, v, k, input));
70
+ return Object.fromEntries(entries);
114
71
  }
115
72
 
116
73
  /**
@@ -166,8 +123,6 @@ function arraysIntersect(a, b) {
166
123
  }
167
124
 
168
125
  module.exports = {
169
- values,
170
- keysDifference,
171
126
  pick,
172
127
  bindAll,
173
128
  mapObject,
package/src/worker.js CHANGED
@@ -1,4 +1 @@
1
- const worker = require('./source/worker');
2
-
3
- /* global self */
4
- worker(self);
1
+ /* intentionaly empty for now */
@@ -1,68 +0,0 @@
1
- module.exports = images;
2
-
3
- function images({ actor, mapId }) {
4
- const cache = new Map(); // id -> image
5
- const inProgress = new Map(); // id -> promise
6
-
7
- return {
8
- getImages
9
- };
10
-
11
- async function getImages({ icons }) {
12
- const missing = new Set();
13
- const result = {};
14
- for (const id of icons) {
15
- if (cache.has(id)) {
16
- const image = cache.get(id);
17
- if (image) {
18
- result[id] = image;
19
- }
20
- } else {
21
- missing.add(id);
22
- }
23
- }
24
- if (missing.size === 0) {
25
- // All images are already in the cache
26
- return result;
27
- }
28
- const active = new Set();
29
- const needed = [...missing];
30
- // Check if any of the missing images are already being fetched
31
- for (const id of missing) {
32
- if (inProgress.has(id)) {
33
- active.add(inProgress.get(id));
34
- missing.delete(id);
35
- }
36
- }
37
- if (missing.size > 0) {
38
- // Fetch the remaining images
39
- await fetchMissing([...missing]);
40
- }
41
- if (active.size > 0) {
42
- await Promise.all(active);
43
- }
44
- for (const id of needed) {
45
- const image = cache.get(id);
46
- if (image) {
47
- result[id] = image;
48
- }
49
- }
50
- return result;
51
- }
52
-
53
- async function fetchMissing(icons) {
54
- const promise = actor.send('getImages', { icons }, mapId);
55
- for (const id of icons) {
56
- inProgress.set(id, promise);
57
- }
58
- const result = await promise;
59
- // Add the fetched images to the cache
60
- for (const id of icons) {
61
- cache.set(id, result[id]);
62
- }
63
- // Remove the fetched images from the inProgress set
64
- for (const id of icons) {
65
- inProgress.delete(id);
66
- }
67
- }
68
- }
@@ -1,110 +0,0 @@
1
- require('../util/polyfill');
2
-
3
- const Actor = require('../util/actor');
4
-
5
- const StyleLayerIndex = require('../style/style_layer_index');
6
- const VectorTileWorkerSource = require('./vector_tile_worker_source');
7
- const GeoJSONWorkerSource = require('./geojson_worker_source');
8
- const assert = require('assert');
9
- const { plugin: globalRTLTextPlugin } = require('./rtl_text_plugin');
10
- const DEMData = require('../data/dem_data');
11
- const { resources } = require('./resources');
12
-
13
- class Worker {
14
- #resources = {};
15
-
16
- constructor(self) {
17
- this.self = self;
18
- this.actor = new Actor(self, this);
19
-
20
- this.actors = {};
21
- this.layerIndexes = {};
22
-
23
- this.workerSourceTypes = {
24
- vector: VectorTileWorkerSource,
25
- geojson: GeoJSONWorkerSource
26
- };
27
-
28
- // [mapId][sourceType][sourceName] => worker source instance
29
- this.workerSources = {};
30
-
31
- this.self.registerWorkerSource = (name, WorkerSource) => {
32
- if (this.workerSourceTypes[name]) {
33
- throw new Error(`Worker source with name "${name}" already registered.`);
34
- }
35
- this.workerSourceTypes[name] = WorkerSource;
36
- };
37
-
38
- this.self.registerRTLTextPlugin = rtlTextPlugin => {
39
- if (globalRTLTextPlugin.isLoaded()) {
40
- throw new Error('RTL text plugin already registered.');
41
- }
42
- globalRTLTextPlugin['applyArabicShaping'] = rtlTextPlugin.applyArabicShaping;
43
- globalRTLTextPlugin['processBidirectionalText'] = rtlTextPlugin.processBidirectionalText;
44
- globalRTLTextPlugin['processStyledBidirectionalText'] = rtlTextPlugin.processStyledBidirectionalText;
45
- };
46
- }
47
-
48
- setLayers(mapId, layers) {
49
- this.getLayerIndex(mapId).replace(layers);
50
- }
51
-
52
- updateLayers(mapId, params) {
53
- this.getLayerIndex(mapId).update(params.layers, params.removedIds);
54
- }
55
-
56
- loadTile(mapId, params) {
57
- assert(params.type);
58
- return this.getWorkerSource(mapId, params.type, params.source).loadTile(params);
59
- }
60
-
61
- loadDEMTile(mapId, params) {
62
- const { uid, rawImageData, encoding } = params;
63
- return new DEMData(uid, rawImageData, encoding);
64
- }
65
-
66
- removeSource(mapId, params) {
67
- const { type, source } = params;
68
- assert(type);
69
- assert(source);
70
-
71
- const worker = this.workerSources?.[mapId]?.[type]?.[source];
72
- if (worker) {
73
- delete this.workerSources[mapId][type][source];
74
- worker.removeSource?.(params);
75
- }
76
- }
77
-
78
- loadRTLTextPlugin(map, pluginURL) {
79
- if (!globalRTLTextPlugin.isLoaded()) {
80
- this.self.importScripts(pluginURL);
81
- if (!globalRTLTextPlugin.isLoaded()) {
82
- throw new Error(`RTL Text Plugin failed to import scripts from ${pluginURL}`);
83
- }
84
- }
85
- }
86
-
87
- getLayerIndex(mapId) {
88
- return (this.layerIndexes[mapId] ??= new StyleLayerIndex());
89
- }
90
-
91
- getResources(mapId) {
92
- return (this.#resources[mapId] ??= resources(this.actor, mapId));
93
- }
94
-
95
- getWorkerSource(mapId, type, source) {
96
- this.workerSources[mapId] ??= {};
97
- this.workerSources[mapId][type] ??= {};
98
-
99
- return (this.workerSources[mapId][type][source] ??= this.createWorkerSource(type, mapId));
100
- }
101
-
102
- createWorkerSource(type, mapId) {
103
- const WorkerSource = this.workerSourceTypes[type];
104
- return new WorkerSource(this.getResources(mapId), this.getLayerIndex(mapId));
105
- }
106
- }
107
-
108
- module.exports = function createWorker(self) {
109
- return new Worker(self);
110
- };
@@ -1,14 +0,0 @@
1
- /**
2
- * May be implemented by custom source types to provide code that can be run on
3
- * the WebWorkers. In addition to providing a custom
4
- * {@link WorkerSource#loadTile}, any other methods attached to a `WorkerSource`
5
- * implementation may also be targeted by the {@link Source} via
6
- * `dispatcher.send('source-type.methodname', params, callback)`.
7
- *
8
- * @see {@link Map#addSourceType}
9
- * @private
10
- *
11
- * @class WorkerSource
12
- * @param actor
13
- * @param layerIndex
14
- */
@@ -1,51 +0,0 @@
1
- const refProperties = require('./util/ref_properties');
2
-
3
- function deref(layer, parent) {
4
- const result = {};
5
-
6
- for (const k in layer) {
7
- if (k !== 'ref') {
8
- result[k] = layer[k];
9
- }
10
- }
11
-
12
- refProperties.forEach(k => {
13
- if (k in parent) {
14
- result[k] = parent[k];
15
- }
16
- });
17
-
18
- return result;
19
- }
20
-
21
- module.exports = derefLayers;
22
-
23
- /**
24
- * Given an array of layers, some of which may contain `ref` properties
25
- * whose value is the `id` of another property, return a new array where
26
- * such layers have been augmented with the 'type', 'source', etc. properties
27
- * from the parent layer, and the `ref` property has been removed.
28
- *
29
- * The input is not modified. The output may contain references to portions
30
- * of the input.
31
- *
32
- * @private
33
- * @param {Array<Layer>} layers
34
- * @returns {Array<Layer>}
35
- */
36
- function derefLayers(layers) {
37
- layers = layers.slice();
38
-
39
- const map = Object.create(null);
40
- for (let i = 0; i < layers.length; i++) {
41
- map[layers[i].id] = layers[i];
42
- }
43
-
44
- for (let i = 0; i < layers.length; i++) {
45
- if ('ref' in layers[i]) {
46
- layers[i] = deref(layers[i], map[layers[i].ref]);
47
- }
48
- }
49
-
50
- return layers;
51
- }