@mapwhit/tilerenderer 0.52.1 → 1.1.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 (249) hide show
  1. package/README.md +7 -0
  2. package/build/min/package.json +2 -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 +5 -4
  54. package/src/data/array_types.js +55 -117
  55. package/src/data/bucket/circle_attributes.js +2 -4
  56. package/src/data/bucket/circle_bucket.js +19 -16
  57. package/src/data/bucket/fill_attributes.js +2 -4
  58. package/src/data/bucket/fill_bucket.js +38 -27
  59. package/src/data/bucket/fill_extrusion_attributes.js +2 -4
  60. package/src/data/bucket/fill_extrusion_bucket.js +56 -37
  61. package/src/data/bucket/heatmap_bucket.js +2 -11
  62. package/src/data/bucket/line_attributes.js +2 -4
  63. package/src/data/bucket/line_bucket.js +208 -163
  64. package/src/data/bucket/pattern_attributes.js +2 -4
  65. package/src/data/bucket/pattern_bucket_features.js +7 -9
  66. package/src/data/bucket/symbol_attributes.js +12 -26
  67. package/src/data/bucket/symbol_bucket.js +174 -323
  68. package/src/data/bucket/symbol_buffers.js +62 -0
  69. package/src/data/bucket/symbol_collision_buffers.js +33 -0
  70. package/src/data/bucket.js +26 -25
  71. package/src/data/dem_data.js +11 -10
  72. package/src/data/extent.js +1 -1
  73. package/src/data/feature_index.js +38 -28
  74. package/src/data/index_array_type.js +1 -6
  75. package/src/data/load_geometry.js +6 -9
  76. package/src/data/pos_attributes.js +2 -3
  77. package/src/data/program_configuration.js +47 -38
  78. package/src/data/raster_bounds_attributes.js +2 -2
  79. package/src/data/segment.js +4 -7
  80. package/src/geo/coordinate.js +1 -1
  81. package/src/geo/lng_lat.js +3 -3
  82. package/src/geo/lng_lat_bounds.js +8 -4
  83. package/src/geo/transform.js +69 -30
  84. package/src/gl/color_mode.js +2 -2
  85. package/src/gl/context.js +28 -29
  86. package/src/gl/cull_face_mode.js +1 -1
  87. package/src/gl/depth_mode.js +1 -1
  88. package/src/gl/framebuffer.js +8 -4
  89. package/src/gl/index_buffer.js +2 -2
  90. package/src/gl/stencil_mode.js +1 -1
  91. package/src/gl/value.js +33 -68
  92. package/src/gl/vertex_buffer.js +2 -2
  93. package/src/index.js +49 -25
  94. package/src/render/draw_background.js +17 -12
  95. package/src/render/draw_circle.js +15 -12
  96. package/src/render/draw_collision_debug.js +11 -8
  97. package/src/render/draw_debug.js +16 -14
  98. package/src/render/draw_fill.js +27 -20
  99. package/src/render/draw_fill_extrusion.js +20 -17
  100. package/src/render/draw_heatmap.js +21 -16
  101. package/src/render/draw_hillshade.js +12 -9
  102. package/src/render/draw_line.js +36 -22
  103. package/src/render/draw_raster.js +22 -18
  104. package/src/render/draw_symbol.js +38 -33
  105. package/src/render/glyph_atlas.js +9 -8
  106. package/src/render/glyph_manager.js +2 -3
  107. package/src/render/image_atlas.js +4 -11
  108. package/src/render/image_manager.js +39 -28
  109. package/src/render/line_atlas.js +2 -2
  110. package/src/render/painter.js +78 -61
  111. package/src/render/program/background_program.js +6 -13
  112. package/src/render/program/circle_program.js +8 -10
  113. package/src/render/program/clipping_mask_program.js +3 -5
  114. package/src/render/program/collision_program.js +4 -6
  115. package/src/render/program/debug_program.js +3 -5
  116. package/src/render/program/fill_extrusion_program.js +9 -15
  117. package/src/render/program/fill_program.js +10 -21
  118. package/src/render/program/heatmap_program.js +9 -15
  119. package/src/render/program/hillshade_program.js +16 -22
  120. package/src/render/program/line_program.js +14 -25
  121. package/src/render/program/pattern.js +5 -7
  122. package/src/render/program/program_uniforms.js +13 -20
  123. package/src/render/program/raster_program.js +9 -11
  124. package/src/render/program/symbol_program.js +5 -7
  125. package/src/render/program.js +5 -6
  126. package/src/render/texture.js +1 -1
  127. package/src/render/tile_mask.js +6 -4
  128. package/src/render/uniform_binding.js +9 -20
  129. package/src/render/vertex_array_object.js +5 -3
  130. package/src/shaders/encode_attribute.js +2 -6
  131. package/src/shaders/index.js +103 -51
  132. package/src/source/geojson_source.js +25 -30
  133. package/src/source/geojson_worker_source.js +46 -74
  134. package/src/source/geojson_wrapper.js +13 -5
  135. package/src/source/image_source.js +17 -28
  136. package/src/source/load_tilejson.js +3 -3
  137. package/src/source/pixels_to_tile_units.js +3 -3
  138. package/src/source/query_features.js +17 -15
  139. package/src/source/raster_dem_tile_source.js +54 -71
  140. package/src/source/raster_tile_source.js +14 -15
  141. package/src/source/resources/glyphs.js +4 -5
  142. package/src/source/resources/index.js +4 -12
  143. package/src/source/rtl_text_plugin.js +62 -35
  144. package/src/source/source.js +14 -22
  145. package/src/source/source_cache.js +221 -179
  146. package/src/source/source_state.js +125 -13
  147. package/src/source/tile.js +67 -66
  148. package/src/source/tile_bounds.js +36 -29
  149. package/src/source/tile_cache.js +2 -2
  150. package/src/source/tile_id.js +30 -26
  151. package/src/source/vector_tile_source.js +23 -21
  152. package/src/source/vector_tile_worker_source.js +22 -26
  153. package/src/source/worker_tile.js +139 -134
  154. package/src/style/create_style_layer.js +11 -11
  155. package/src/style/evaluation_parameters.js +4 -6
  156. package/src/style/light.js +5 -5
  157. package/src/style/load_sprite.js +6 -6
  158. package/src/style/parse_glyph_pbf.js +21 -17
  159. package/src/style/pauseable_placement.js +7 -9
  160. package/src/style/properties.js +21 -51
  161. package/src/style/query_utils.js +7 -13
  162. package/src/style/style.js +314 -221
  163. package/src/style/style_layer/background_style_layer.js +3 -4
  164. package/src/style/style_layer/background_style_layer_properties.js +2 -2
  165. package/src/style/style_layer/circle_style_layer.js +25 -20
  166. package/src/style/style_layer/circle_style_layer_properties.js +2 -2
  167. package/src/style/style_layer/fill_extrusion_style_layer.js +55 -37
  168. package/src/style/style_layer/fill_extrusion_style_layer_properties.js +2 -2
  169. package/src/style/style_layer/fill_style_layer.js +11 -12
  170. package/src/style/style_layer/fill_style_layer_properties.js +2 -2
  171. package/src/style/style_layer/heatmap_style_layer.js +6 -7
  172. package/src/style/style_layer/heatmap_style_layer_properties.js +2 -2
  173. package/src/style/style_layer/hillshade_style_layer.js +4 -5
  174. package/src/style/style_layer/hillshade_style_layer_properties.js +2 -2
  175. package/src/style/style_layer/line_style_layer.js +33 -30
  176. package/src/style/style_layer/line_style_layer_properties.js +5 -5
  177. package/src/style/style_layer/raster_style_layer.js +3 -4
  178. package/src/style/style_layer/raster_style_layer_properties.js +2 -2
  179. package/src/style/style_layer/symbol_style_layer.js +20 -21
  180. package/src/style/style_layer/symbol_style_layer_properties.js +2 -2
  181. package/src/style/style_layer.js +66 -47
  182. package/src/style/style_layer_index.js +17 -42
  183. package/src/style/zoom_history.js +1 -1
  184. package/src/style-spec/error/parsing_error.js +1 -1
  185. package/src/style-spec/error/validation_error.js +5 -3
  186. package/src/style-spec/feature_filter/convert.js +17 -9
  187. package/src/style-spec/feature_filter/index.js +13 -9
  188. package/src/style-spec/util/eval_support.js +2 -2
  189. package/src/style-spec/util/ref_properties.js +1 -1
  190. package/src/symbol/anchor.js +2 -6
  191. package/src/symbol/check_max_angle.js +13 -5
  192. package/src/symbol/clip_line.js +2 -3
  193. package/src/symbol/collision_feature.js +8 -4
  194. package/src/symbol/collision_index.js +5 -7
  195. package/src/symbol/cross_tile_symbol_index.js +7 -10
  196. package/src/symbol/get_anchors.js +15 -8
  197. package/src/symbol/grid_index.js +5 -3
  198. package/src/symbol/mergelines.js +2 -2
  199. package/src/symbol/opacity_state.js +1 -5
  200. package/src/symbol/placement.js +28 -23
  201. package/src/symbol/projection.js +29 -28
  202. package/src/symbol/quads.js +14 -16
  203. package/src/symbol/shaping.js +27 -19
  204. package/src/symbol/symbol_layout.js +24 -28
  205. package/src/symbol/symbol_size.js +13 -12
  206. package/src/symbol/transform_text.js +4 -4
  207. package/src/ui/camera.js +34 -18
  208. package/src/ui/map.js +102 -44
  209. package/src/util/async.js +11 -5
  210. package/src/util/browser.js +1 -1
  211. package/src/util/callback.js +3 -9
  212. package/src/util/classify_rings.js +13 -8
  213. package/src/util/color_ramp.js +3 -3
  214. package/src/util/config.js +4 -4
  215. package/src/util/dictionary_coder.js +2 -3
  216. package/src/util/dom.js +7 -3
  217. package/src/util/find_pole_of_inaccessibility.js +29 -14
  218. package/src/util/group_layers.js +41 -0
  219. package/src/util/image.js +3 -13
  220. package/src/util/interpolate.js +1 -1
  221. package/src/util/intersection_tests.js +80 -42
  222. package/src/util/is_char_in_unicode_block.js +1 -1
  223. package/src/util/key.js +25 -0
  224. package/src/util/loader/image.js +1 -1
  225. package/src/util/object.js +33 -76
  226. package/src/util/script_detection.js +212 -91
  227. package/src/util/struct_array.js +8 -40
  228. package/src/util/task_queue.js +11 -7
  229. package/src/util/throttle.js +2 -2
  230. package/src/util/tile_cover.js +8 -5
  231. package/src/util/token.js +1 -1
  232. package/src/util/unique_id.js +2 -2
  233. package/src/util/util.js +21 -29
  234. package/src/util/vectortile_to_geojson.js +4 -2
  235. package/src/util/verticalize_punctuation.js +3 -7
  236. package/src/util/warn.js +4 -4
  237. package/src/util/web_worker.js +3 -3
  238. package/src/worker.js +1 -4
  239. package/src/source/resources/images.js +0 -68
  240. package/src/source/worker.js +0 -110
  241. package/src/source/worker_source.js +0 -14
  242. package/src/style-spec/deref.js +0 -51
  243. package/src/style-spec/group_by_layout.js +0 -46
  244. package/src/util/actor.js +0 -108
  245. package/src/util/dispatcher.js +0 -65
  246. package/src/util/global_worker_pool.js +0 -15
  247. package/src/util/transfer_registry.js +0 -168
  248. package/src/util/web_worker_transfer.js +0 -43
  249. package/src/util/worker_pool.js +0 -41
@@ -1,15 +1,13 @@
1
- const { create: createSource } = require('./source');
2
- const Tile = require('./tile');
3
- const { Event, ErrorEvent, Evented } = require('@mapwhit/events');
4
- const TileCache = require('./tile_cache');
5
- const Coordinate = require('../geo/coordinate');
6
- const { keysDifference } = require('../util/object');
7
- const EXTENT = require('../data/extent');
8
- const { default: Point } = require('@mapbox/point-geometry');
9
- const browser = require('../util/browser');
10
- const { OverscaledTileID } = require('./tile_id');
11
- const assert = require('assert');
12
- const SourceFeatureState = require('./source_state');
1
+ import Point from '@mapbox/point-geometry';
2
+ import { ErrorEvent, Event, Evented } from '@mapwhit/events';
3
+ import EXTENT from '../data/extent.js';
4
+ import Coordinate from '../geo/coordinate.js';
5
+ import browser from '../util/browser.js';
6
+ import { create as createSource } from './source.js';
7
+ import SourceFeatureState from './source_state.js';
8
+ import Tile from './tile.js';
9
+ import TileCache from './tile_cache.js';
10
+ import { OverscaledTileID } from './tile_id.js';
13
11
 
14
12
  /**
15
13
  * `SourceCache` is responsible for
@@ -23,20 +21,29 @@ const SourceFeatureState = require('./source_state');
23
21
  * @private
24
22
  */
25
23
  class SourceCache extends Evented {
26
- constructor(id, options, dispatcher) {
24
+ // this.#sourceLoaded signifies that the TileJSON is loaded if applicable.
25
+ // if the source type does not come with a TileJSON, the flag signifies the
26
+ // source data has loaded (i.e geojson has been tiled on the worker and is ready)
27
+ #sourceLoaded = false;
28
+ #sourceErrored = false;
29
+ #paused = false;
30
+ #shouldReloadOnResume = false;
31
+
32
+ constructor(id, options, workerOpts) {
27
33
  super();
28
34
  this.id = id;
29
- this.dispatcher = dispatcher;
30
35
 
31
36
  this.on('data', e => {
32
- // this._sourceLoaded signifies that the TileJSON is loaded if applicable.
33
- // if the source type does not come with a TileJSON, the flag signifies the
34
- // source data has loaded (i.e geojson has been tiled on the worker and is ready)
35
- if (e.dataType === 'source' && e.sourceDataType === 'metadata') this._sourceLoaded = true;
37
+ if (e.dataType !== 'source') {
38
+ return;
39
+ }
40
+ if (e.sourceDataType === 'metadata') {
41
+ this.#sourceLoaded = true;
42
+ }
36
43
 
37
44
  // for sources with mutable data, this event fires when the underlying data
38
45
  // to a source is changed. (i.e. GeoJSONSource#setData and ImageSource#serCoordinates)
39
- if (this._sourceLoaded && !this._paused && e.dataType === 'source' && e.sourceDataType === 'content') {
46
+ if (this.#sourceLoaded && !this.#paused && e.sourceDataType === 'content') {
40
47
  this.reload();
41
48
  if (this.transform) {
42
49
  this.update(this.transform);
@@ -44,26 +51,18 @@ class SourceCache extends Evented {
44
51
  }
45
52
  });
46
53
 
47
- this.on('error', () => {
48
- this._sourceErrored = true;
49
- });
54
+ this.on('error', () => (this.#sourceErrored = true));
50
55
 
51
- this._source = createSource(id, options, dispatcher, this);
56
+ this._source = createSource(id, options, this, workerOpts);
52
57
 
53
- this._tiles = {};
58
+ this._tiles = new Map();
54
59
  this._cache = new TileCache(0, this._unloadTile.bind(this));
55
- this._maxTileCacheSize = null;
56
-
57
- this._isIdRenderable = this._isIdRenderable.bind(this);
58
- this._isIdRenderableForSymbols = this._isIdRenderableForSymbols.bind(this);
59
-
60
- this._coveredTiles = {};
60
+ this._coveredTiles = new Set();
61
61
  this._state = new SourceFeatureState();
62
62
  }
63
63
 
64
64
  onAdd(map) {
65
65
  this.map = map;
66
- this._maxTileCacheSize = map ? map._maxTileCacheSize : null;
67
66
  if (this._source?.onAdd) {
68
67
  this._source.onAdd(map);
69
68
  }
@@ -80,15 +79,18 @@ class SourceCache extends Evented {
80
79
  * an additional API call is received.
81
80
  */
82
81
  loaded() {
83
- if (this._sourceErrored) {
82
+ if (this.#sourceErrored) {
84
83
  return true;
85
84
  }
86
- if (!this._sourceLoaded) {
85
+
86
+ if (!this.#sourceLoaded) {
87
87
  return false;
88
88
  }
89
- for (const t in this._tiles) {
90
- const tile = this._tiles[t];
91
- if (tile.state !== 'loaded' && tile.state !== 'errored') return false;
89
+
90
+ for (const tile of this._tiles.values()) {
91
+ if (tile.state !== 'loaded' && tile.state !== 'errored') {
92
+ return false;
93
+ }
92
94
  }
93
95
  return true;
94
96
  }
@@ -98,16 +100,22 @@ class SourceCache extends Evented {
98
100
  }
99
101
 
100
102
  pause() {
101
- this._paused = true;
103
+ this.#paused = true;
102
104
  }
103
105
 
104
106
  resume() {
105
- if (!this._paused) return;
106
- const shouldReload = this._shouldReloadOnResume;
107
- this._paused = false;
108
- this._shouldReloadOnResume = false;
109
- if (shouldReload) this.reload();
110
- if (this.transform) this.update(this.transform);
107
+ if (!this.#paused) {
108
+ return;
109
+ }
110
+ const shouldReload = this.#shouldReloadOnResume;
111
+ this.#paused = false;
112
+ this.#shouldReloadOnResume = false;
113
+ if (shouldReload) {
114
+ this.reload();
115
+ }
116
+ if (this.transform) {
117
+ this.update(this.transform);
118
+ }
111
119
  }
112
120
 
113
121
  _loadTile(tile) {
@@ -122,77 +130,71 @@ class SourceCache extends Evented {
122
130
  return this._source.abortTile?.(tile);
123
131
  }
124
132
 
125
- serialize() {
126
- return this._source.serialize();
127
- }
128
-
129
133
  prepare(context) {
130
134
  this._source.prepare?.();
131
135
 
132
- this._state.coalesceChanges(this._tiles, this.map ? this.map.painter : null);
133
- for (const i in this._tiles) {
134
- this._tiles[i].upload(context);
135
- }
136
+ this._state.coalesceChanges(this._tiles.values(), this.map?.painter);
137
+ this._tiles.forEach(tile => tile.upload(context));
136
138
  }
137
139
 
138
140
  /**
139
- * Return all tile ids ordered with z-order, and cast to numbers
141
+ * Return all tile ids ordered with z-order
140
142
  */
141
- getIds() {
142
- const compareKeyZoom = (a_, b_) => {
143
- const a = this._tiles[a_].tileID;
144
- const b = this._tiles[b_].tileID;
145
- const rotatedA = new Point(a.canonical.x, a.canonical.y).rotate(this.transform.angle);
146
- const rotatedB = new Point(b.canonical.x, b.canonical.y).rotate(this.transform.angle);
147
- return a.overscaledZ - b.overscaledZ || rotatedB.y - rotatedA.y || rotatedB.x - rotatedA.x;
148
- };
149
-
150
- return Object.keys(this._tiles).map(Number).sort(compareKeyZoom);
143
+ getIds(filter = () => true) {
144
+ const angle = this.transform?.angle ?? 0;
145
+
146
+ return Array.from(this._tiles)
147
+ .filter(it => filter.call(this, it[1]))
148
+ .sort(compareKeyZoom)
149
+ .map(it => it[0]);
150
+
151
+ function compareKeyZoom([, a_], [, b_]) {
152
+ const a = a_.tileID;
153
+ const b = b_.tileID;
154
+ const zDiff = a.overscaledZ - b.overscaledZ;
155
+ if (zDiff !== 0) {
156
+ return zDiff;
157
+ }
158
+ const rotatedA = new Point(a.canonical.x, a.canonical.y).rotate(angle);
159
+ const rotatedB = new Point(b.canonical.x, b.canonical.y).rotate(angle);
160
+ return rotatedB.y - rotatedA.y || rotatedB.x - rotatedA.x;
161
+ }
151
162
  }
152
163
 
153
164
  getRenderableIds(symbolLayer) {
154
- return symbolLayer
155
- ? this.getIds().filter(this._isIdRenderableForSymbols)
156
- : this.getIds().filter(this._isIdRenderable);
165
+ const filter = symbolLayer ? this.#isTileRenderableForSymbols : this.#isTileRenderable;
166
+ return this.getIds(filter);
157
167
  }
158
168
 
159
169
  hasRenderableParent(tileID) {
160
170
  const parentTile = this.findLoadedParent(tileID, 0);
161
- if (parentTile) {
162
- return this._isIdRenderable(parentTile.tileID.key);
163
- }
164
- return false;
171
+ return this.#isTileRenderable(parentTile);
165
172
  }
166
173
 
167
- _isIdRenderable(id) {
168
- return this._tiles[id]?.hasData() && !this._coveredTiles[id] && !this._tiles[id].holdingForFade();
174
+ #isTileRenderable(tile) {
175
+ return tile?.hasData() && !this._coveredTiles.has(tile.tileID.key) && !tile.holdingForFade();
169
176
  }
170
177
 
171
- _isIdRenderableForSymbols(id) {
172
- return this._tiles[id]?.hasData() && !this._coveredTiles[id];
178
+ #isTileRenderableForSymbols(tile) {
179
+ return tile?.hasData() && !this._coveredTiles.has(tile.tileID.key);
173
180
  }
174
181
 
175
182
  reload() {
176
- if (this._paused) {
177
- this._shouldReloadOnResume = true;
183
+ if (this.#paused) {
184
+ this.#shouldReloadOnResume = true;
178
185
  return;
179
186
  }
180
187
 
181
188
  this._cache.reset();
182
189
 
183
- for (const i in this._tiles) {
184
- if (this._tiles[i].state !== 'errored') this._reloadTile(i, 'reloading');
185
- }
190
+ this._tiles.forEach(tile => {
191
+ if (tile.state !== 'errored') {
192
+ this._reloadTile(tile, 'reloading');
193
+ }
194
+ });
186
195
  }
187
196
 
188
- _reloadTile(id, state) {
189
- const tile = this._tiles[id];
190
-
191
- // this potentially does not address all underlying
192
- // issues https://github.com/mapbox/mapbox-gl-js/issues/4252
193
- // - hard to tell without repro steps
194
- if (!tile) return;
195
-
197
+ _reloadTile(tile, state) {
196
198
  // The difference between "loading" tiles and "reloading" or "expired"
197
199
  // tiles is that "reloading"/"expired" tiles are "renderable".
198
200
  // Therefore, a "loading" tile cannot become a "reloading" tile without
@@ -209,15 +211,23 @@ class SourceCache extends Evented {
209
211
  _tileLoadError(tile, err) {
210
212
  tile.state = 'errored';
211
213
  // ignore do nothing strategy
212
- if (err.doNothing) return;
213
- if (err.status !== 404) this._source.fire(new ErrorEvent(err, { tile }));
214
+ if (err.doNothing) {
215
+ return;
216
+ }
217
+ if (err.status !== 404) {
218
+ this._source.fire(new ErrorEvent(err, { tile }));
219
+ }
214
220
  // continue to try loading parent/children tiles if a tile doesn't exist (404)
215
- else this.update(this.transform);
221
+ else {
222
+ this.update(this.transform);
223
+ }
216
224
  }
217
225
 
218
226
  _tileLoaded(tile, err) {
219
227
  tile.timeAdded = browser.now();
220
- if (this.getSource().type === 'raster-dem' && tile.dem) this._backfillDEM(tile);
228
+ if (this.getSource().type === 'raster-dem' && tile.dem) {
229
+ this._backfillDEM(tile);
230
+ }
221
231
  this._state.initializeTileState(tile, this.map ? this.map.painter : null);
222
232
 
223
233
  this._source.fire(new Event('data', { dataType: 'source', tile: tile, coord: tile.tileID }));
@@ -244,7 +254,9 @@ class SourceCache extends Evented {
244
254
  const dy = borderTile.tileID.canonical.y - tile.tileID.canonical.y;
245
255
  const dim = 2 ** tile.tileID.canonical.z;
246
256
  const borderId = borderTile.tileID.key;
247
- if (dx === 0 && dy === 0) return;
257
+ if (dx === 0 && dy === 0) {
258
+ return;
259
+ }
248
260
 
249
261
  if (Math.abs(dy) > 1) {
250
262
  return;
@@ -257,9 +269,13 @@ class SourceCache extends Evented {
257
269
  dx -= dim;
258
270
  }
259
271
  }
260
- if (!borderTile.dem || !tile.dem) return;
272
+ if (!borderTile.dem || !tile.dem) {
273
+ return;
274
+ }
261
275
  tile.dem.backfillBorder(borderTile.dem, dx, dy);
262
- if (tile.neighboringTiles?.[borderId]) tile.neighboringTiles[borderId].backfilled = true;
276
+ if (tile.neighboringTiles?.[borderId]) {
277
+ tile.neighboringTiles[borderId].backfilled = true;
278
+ }
263
279
  }
264
280
  }
265
281
  /**
@@ -273,7 +289,7 @@ class SourceCache extends Evented {
273
289
  * Get a specific tile by id
274
290
  */
275
291
  getTileByID(id) {
276
- return this._tiles[id];
292
+ return this._tiles.get(+id);
277
293
  }
278
294
 
279
295
  /**
@@ -288,19 +304,23 @@ class SourceCache extends Evented {
288
304
  * between `zoom` (exclusive) and `maxCoveringZoom` (inclusive)
289
305
  */
290
306
  _retainLoadedChildren(idealTiles, zoom, maxCoveringZoom, retain) {
291
- for (const id in this._tiles) {
292
- let tile = this._tiles[id];
293
-
307
+ for (let [id, tile] of this._tiles) {
294
308
  // only consider renderable tiles up to maxCoveringZoom
295
- if (retain[id] || !tile.hasData() || tile.tileID.overscaledZ <= zoom || tile.tileID.overscaledZ > maxCoveringZoom)
309
+ if (
310
+ retain.has(id) ||
311
+ !tile.hasData() ||
312
+ tile.tileID.overscaledZ <= zoom ||
313
+ tile.tileID.overscaledZ > maxCoveringZoom
314
+ ) {
296
315
  continue;
316
+ }
297
317
 
298
318
  // loop through parents and retain the topmost loaded one if found
299
319
  let topmostLoadedID = tile.tileID;
300
320
  while (tile && tile.tileID.overscaledZ > zoom + 1) {
301
321
  const parentID = tile.tileID.scaledTo(tile.tileID.overscaledZ - 1);
302
322
 
303
- tile = this._tiles[parentID.key];
323
+ tile = this._tiles.get(parentID.key);
304
324
 
305
325
  if (tile?.hasData()) {
306
326
  topmostLoadedID = parentID;
@@ -311,10 +331,9 @@ class SourceCache extends Evented {
311
331
  let tileID = topmostLoadedID;
312
332
  while (tileID.overscaledZ > zoom) {
313
333
  tileID = tileID.scaledTo(tileID.overscaledZ - 1);
314
-
315
- if (idealTiles[tileID.key]) {
334
+ if (idealTiles.has(tileID.key)) {
316
335
  // found a parent that needed a loaded child; retain that child
317
- retain[topmostLoadedID.key] = topmostLoadedID;
336
+ retain.set(topmostLoadedID.key, topmostLoadedID);
318
337
  break;
319
338
  }
320
339
  }
@@ -327,9 +346,10 @@ class SourceCache extends Evented {
327
346
  findLoadedParent(tileID, minCoveringZoom) {
328
347
  for (let z = tileID.overscaledZ - 1; z >= minCoveringZoom; z--) {
329
348
  const parent = tileID.scaledTo(z);
330
- if (!parent) return;
331
- const id = String(parent.key);
332
- const tile = this._tiles[id];
349
+ if (!parent) {
350
+ return;
351
+ }
352
+ const tile = this._tiles.get(parent.key);
333
353
  if (tile?.hasData()) {
334
354
  return tile;
335
355
  }
@@ -341,8 +361,7 @@ class SourceCache extends Evented {
341
361
  }
342
362
 
343
363
  /**
344
- * Resizes the tile cache based on the current viewport's size
345
- * or the maxTileCacheSize option passed during map creation
364
+ * Resizes the tile cache based on the current viewport's size.
346
365
  *
347
366
  * Larger viewports use more tiles and need larger caches. Larger viewports
348
367
  * are more likely to be found on devices with more memory and on pages where
@@ -355,12 +374,7 @@ class SourceCache extends Evented {
355
374
  const commonZoomRange = 5;
356
375
 
357
376
  const viewDependentMaxSize = Math.floor(approxTilesInView * commonZoomRange);
358
- const maxSize =
359
- typeof this._maxTileCacheSize === 'number'
360
- ? Math.min(this._maxTileCacheSize, viewDependentMaxSize)
361
- : viewDependentMaxSize;
362
-
363
- this._cache.setMaxSize(maxSize);
377
+ this._cache.setMaxSize(viewDependentMaxSize);
364
378
  }
365
379
 
366
380
  handleWrapJump(lng) {
@@ -386,11 +400,10 @@ class SourceCache extends Evented {
386
400
  this._prevLng = lng;
387
401
 
388
402
  if (wrapDelta) {
389
- const tiles = {};
390
- for (const key in this._tiles) {
391
- const tile = this._tiles[key];
403
+ const tiles = new Map();
404
+ for (const tile of this._tiles.values()) {
392
405
  tile.tileID = tile.tileID.unwrapTo(tile.tileID.wrap + wrapDelta);
393
- tiles[tile.tileID.key] = tile;
406
+ tiles.set(tile.tileID.key, tile);
394
407
  }
395
408
  this._tiles = tiles;
396
409
  }
@@ -402,7 +415,7 @@ class SourceCache extends Evented {
402
415
  */
403
416
  update(transform) {
404
417
  this.transform = transform;
405
- if (!this._sourceLoaded || this._paused) {
418
+ if (!this.#sourceLoaded || this.#paused) {
406
419
  return;
407
420
  }
408
421
 
@@ -411,7 +424,7 @@ class SourceCache extends Evented {
411
424
 
412
425
  // Covered is a list of retained tiles who's areas are fully covered by other,
413
426
  // better, retained tiles. They are not drawn separately.
414
- this._coveredTiles = {};
427
+ this._coveredTiles.clear();
415
428
 
416
429
  let idealTileIDs;
417
430
  if (!this.used) {
@@ -454,82 +467,83 @@ class SourceCache extends Evented {
454
467
  const retain = this._updateRetainedTiles(idealTileIDs, zoom);
455
468
 
456
469
  if (isRasterType(this._source.type)) {
457
- const parentsForFading = {};
458
- const fadingTiles = {};
459
- const ids = Object.keys(retain);
460
- for (const id of ids) {
461
- const tileID = retain[id];
462
- assert(tileID.key === +id);
463
-
464
- const tile = this._tiles[id];
465
- if (!tile || (tile.fadeEndTime && tile.fadeEndTime <= browser.now())) continue;
470
+ const parentsForFading = new Map();
471
+ const fadingTiles = new Set();
472
+ for (const [id, tileID] of retain) {
473
+ const tile = this._tiles.get(id);
474
+ if (!tile || (tile.fadeEndTime && tile.fadeEndTime <= browser.now())) {
475
+ continue;
476
+ }
466
477
 
467
478
  // if the tile is loaded but still fading in, find parents to cross-fade with it
468
479
  const parentTile = this.findLoadedParent(tileID, minCoveringZoom);
469
480
  if (parentTile) {
470
481
  this._addTile(parentTile.tileID);
471
- parentsForFading[parentTile.tileID.key] = parentTile.tileID;
482
+ parentsForFading.set(parentTile.tileID.key, parentTile.tileID);
472
483
  }
473
484
 
474
- fadingTiles[id] = tileID;
485
+ fadingTiles.add(id);
475
486
  }
476
487
 
477
488
  // for tiles that are still fading in, also find children to cross-fade with
478
489
  this._retainLoadedChildren(fadingTiles, zoom, maxCoveringZoom, retain);
479
490
 
480
- for (const id in parentsForFading) {
481
- if (!retain[id]) {
491
+ for (const [id, tileID] of parentsForFading) {
492
+ if (!retain.has(id)) {
482
493
  // If a tile is only needed for fading, mark it as covered so that it isn't rendered on it's own.
483
- this._coveredTiles[id] = true;
484
- retain[id] = parentsForFading[id];
494
+ this._coveredTiles.add(id);
495
+ retain.set(id, tileID);
485
496
  }
486
497
  }
487
498
  }
488
499
 
489
- for (const retainedId in retain) {
500
+ for (const [retainedId] of retain) {
490
501
  // Make sure retained tiles always clear any existing fade holds
491
502
  // so that if they're removed again their fade timer starts fresh.
492
- this._tiles[retainedId].clearFadeHold();
503
+ this._tiles.get(retainedId).clearFadeHold();
493
504
  }
494
505
 
495
506
  // Remove the tiles we don't need anymore.
496
- const remove = keysDifference(this._tiles, retain);
497
- for (const tileID of remove) {
498
- const tile = this._tiles[tileID];
507
+ for (const [id, tile] of this._tiles) {
508
+ if (retain.has(id)) {
509
+ continue;
510
+ }
499
511
  if (tile.hasSymbolBuckets && !tile.holdingForFade()) {
500
512
  tile.setHoldDuration(this.map._fadeDuration);
501
513
  } else if (!tile.hasSymbolBuckets || tile.symbolFadeFinished()) {
502
- this._removeTile(tileID);
514
+ this._removeTile(id);
503
515
  }
504
516
  }
505
517
  }
506
518
 
507
519
  releaseSymbolFadeTiles() {
508
- for (const id in this._tiles) {
509
- if (this._tiles[id].holdingForFade()) {
520
+ for (const [id, tile] of this._tiles) {
521
+ if (tile.holdingForFade()) {
510
522
  this._removeTile(id);
511
523
  }
512
524
  }
513
525
  }
514
526
 
515
527
  _updateRetainedTiles(idealTileIDs, zoom) {
516
- const retain = {};
517
- const checked = {};
528
+ const retain = new Map();
529
+ const checked = new Set();
518
530
  const minCoveringZoom = Math.max(zoom - SourceCache.maxOverzooming, this._source.minzoom);
519
531
  const maxCoveringZoom = Math.max(zoom + SourceCache.maxUnderzooming, this._source.minzoom);
520
532
 
521
- const missingTiles = {};
533
+ const missingTiles = new Set();
522
534
  for (const tileID of idealTileIDs) {
523
535
  const tile = this._addTile(tileID);
524
536
 
525
537
  // retain the tile even if it's not loaded because it's an ideal tile.
526
- retain[tileID.key] = tileID;
538
+ retain.set(tileID.key, tileID);
527
539
 
528
- if (tile.hasData()) continue;
540
+ if (tile.hasData()) {
541
+ continue;
542
+ }
529
543
 
530
544
  if (zoom < this._source.maxzoom) {
531
545
  // save missing tiles that potentially have loaded children
532
- missingTiles[tileID.key] = tileID;
546
+ missingTiles.add(tileID.key);
533
547
  }
534
548
  }
535
549
 
@@ -537,9 +551,11 @@ class SourceCache extends Evented {
537
551
  this._retainLoadedChildren(missingTiles, zoom, maxCoveringZoom, retain);
538
552
 
539
553
  for (const tileID of idealTileIDs) {
540
- let tile = this._tiles[tileID.key];
554
+ let tile = this._tiles.get(tileID.key);
541
555
 
542
- if (tile.hasData()) continue;
556
+ if (tile.hasData()) {
557
+ continue;
558
+ }
543
559
 
544
560
  // The tile we require is not yet loaded or does not exist;
545
561
  // Attempt to find children that fully cover it.
@@ -549,15 +565,21 @@ class SourceCache extends Evented {
549
565
  const childCoord = tileID.children(this._source.maxzoom)[0];
550
566
  const childTile = this.getTile(childCoord);
551
567
  if (!!childTile && childTile.hasData()) {
552
- retain[childCoord.key] = childCoord;
568
+ retain.set(childCoord.key, childCoord);
553
569
  continue; // tile is covered by overzoomed child
554
570
  }
555
571
  } else {
556
572
  // check if all 4 immediate children are loaded (i.e. the missing ideal tile is covered)
557
573
  const children = tileID.children(this._source.maxzoom);
558
574
 
559
- if (retain[children[0].key] && retain[children[1].key] && retain[children[2].key] && retain[children[3].key])
575
+ if (
576
+ retain.has(children[0].key) &&
577
+ retain.has(children[1].key) &&
578
+ retain.has(children[2].key) &&
579
+ retain.has(children[3].key)
580
+ ) {
560
581
  continue; // tile is covered by children
582
+ }
561
583
  }
562
584
 
563
585
  // We couldn't find child tiles that entirely cover the ideal tile; look for parents now.
@@ -571,19 +593,23 @@ class SourceCache extends Evented {
571
593
  const parentId = tileID.scaledTo(overscaledZ);
572
594
 
573
595
  // Break parent tile ascent if this route has been previously checked by another child.
574
- if (checked[parentId.key]) break;
575
- checked[parentId.key] = true;
596
+ if (checked.has(parentId.key)) {
597
+ break;
598
+ }
599
+ checked.add(parentId.key);
576
600
 
577
601
  tile = this.getTile(parentId);
578
602
  if (!tile && parentWasRequested) {
579
603
  tile = this._addTile(parentId);
580
604
  }
581
605
  if (tile) {
582
- retain[parentId.key] = parentId;
606
+ retain.set(parentId.key, parentId);
583
607
  // Save the current values, since they're the parent of the next iteration
584
608
  // of the parent tile ascent loop.
585
609
  parentWasRequested = tile.wasRequested();
586
- if (tile.hasData()) break;
610
+ if (tile.hasData()) {
611
+ break;
612
+ }
587
613
  }
588
614
  }
589
615
  }
@@ -596,14 +622,16 @@ class SourceCache extends Evented {
596
622
  * @private
597
623
  */
598
624
  _addTile(tileID) {
599
- let tile = this._tiles[tileID.key];
600
- if (tile) return tile;
625
+ let tile = this._tiles.get(tileID.key);
626
+ if (tile) {
627
+ return tile;
628
+ }
601
629
 
602
630
  tile = this._cache.getAndRemove(tileID);
603
631
  if (tile) {
604
632
  // set the tileID because the cached tile could have had a different wrap value
605
633
  tile.tileID = tileID;
606
- this._state.initializeTileState(tile, this.map ? this.map.painter : null);
634
+ this._state.initializeTileState(tile, this.map?.painter);
607
635
  }
608
636
 
609
637
  const cached = Boolean(tile);
@@ -614,13 +642,11 @@ class SourceCache extends Evented {
614
642
  err => this._tileLoadError(tile, err)
615
643
  );
616
644
  }
617
-
618
- // Impossible, but silence flow.
619
- if (!tile) return null;
620
-
621
645
  tile.uses++;
622
- this._tiles[tileID.key] = tile;
623
- if (!cached) this._source.fire(new Event('dataloading', { tile: tile, coord: tile.tileID, dataType: 'source' }));
646
+ this._tiles.set(tileID.key, tile);
647
+ if (!cached) {
648
+ this._source.fire(new Event('dataloading', { tile: tile, coord: tile.tileID, dataType: 'source' }));
649
+ }
624
650
 
625
651
  return tile;
626
652
  }
@@ -630,13 +656,17 @@ class SourceCache extends Evented {
630
656
  * @private
631
657
  */
632
658
  _removeTile(id) {
633
- const tile = this._tiles[id];
634
- if (!tile) return;
659
+ const tile = this._tiles.get(id);
660
+ if (!tile) {
661
+ return;
662
+ }
635
663
 
636
664
  tile.uses--;
637
- delete this._tiles[id];
665
+ this._tiles.delete(id);
638
666
 
639
- if (tile.uses > 0) return;
667
+ if (tile.uses > 0) {
668
+ return;
669
+ }
640
670
 
641
671
  if (tile.hasData()) {
642
672
  this._cache.add(tile);
@@ -651,10 +681,12 @@ class SourceCache extends Evented {
651
681
  * Remove all tiles from this pyramid
652
682
  */
653
683
  clearTiles() {
654
- this._shouldReloadOnResume = false;
655
- this._paused = false;
684
+ this.#shouldReloadOnResume = false;
685
+ this.#paused = false;
656
686
 
657
- for (const id in this._tiles) this._removeTile(id);
687
+ for (const id of this._tiles.keys()) {
688
+ this._removeTile(id);
689
+ }
658
690
 
659
691
  this._cache.reset();
660
692
  }
@@ -669,7 +701,9 @@ class SourceCache extends Evented {
669
701
  const tileResults = [];
670
702
 
671
703
  const transform = this.transform;
672
- if (!transform) return tileResults;
704
+ if (!transform) {
705
+ return tileResults;
706
+ }
673
707
 
674
708
  const cameraPointQueryGeometry = has3DLayer
675
709
  ? transform.getCameraQueryGeometry(pointQueryGeometry)
@@ -693,8 +727,8 @@ class SourceCache extends Evented {
693
727
  maxY = Math.max(maxY, p.row);
694
728
  }
695
729
 
696
- for (let i = 0; i < ids.length; i++) {
697
- const tile = this._tiles[ids[i]];
730
+ for (const id of ids) {
731
+ const tile = this._tiles.get(id);
698
732
  if (tile.holdingForFade()) {
699
733
  // Tiles held for fading are covered by tiles that are closer to ideal
700
734
  continue;
@@ -731,7 +765,7 @@ class SourceCache extends Evented {
731
765
  }
732
766
 
733
767
  getVisibleCoordinates(symbolLayer) {
734
- const coords = this.getRenderableIds(symbolLayer).map(id => this._tiles[id].tileID);
768
+ const coords = this.getRenderableIds(symbolLayer).map(id => this._tiles.get(id).tileID);
735
769
  for (const coord of coords) {
736
770
  coord.posMatrix = this.transform.calculatePosMatrix(coord.toUnwrapped());
737
771
  }
@@ -744,8 +778,7 @@ class SourceCache extends Evented {
744
778
  }
745
779
 
746
780
  if (isRasterType(this._source.type)) {
747
- for (const id in this._tiles) {
748
- const tile = this._tiles[id];
781
+ for (const tile of this._tiles.values()) {
749
782
  if (tile.fadeEndTime !== undefined && tile.fadeEndTime >= browser.now()) {
750
783
  return true;
751
784
  }
@@ -764,6 +797,15 @@ class SourceCache extends Evented {
764
797
  this._state.updateState(sourceLayer, feature, state);
765
798
  }
766
799
 
800
+ /**
801
+ * Resets the value of a particular state key for a feature
802
+ * @private
803
+ */
804
+ removeFeatureState(sourceLayer, feature, key) {
805
+ sourceLayer = sourceLayer || '_geojsonTileLayer';
806
+ this._state.removeFeatureState(sourceLayer, feature, key);
807
+ }
808
+
767
809
  /**
768
810
  * Get the entire state object for a feature
769
811
  * @private
@@ -793,4 +835,4 @@ function isRasterType(type) {
793
835
  return type === 'raster' || type === 'image';
794
836
  }
795
837
 
796
- module.exports = SourceCache;
838
+ export default SourceCache;