@scoova/mgl 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 (565) hide show
  1. package/LICENSE.txt +116 -0
  2. package/README.md +174 -0
  3. package/build/banner.ts +12 -0
  4. package/build/bump-version-changelog.js +26 -0
  5. package/build/check-bundle-size.js +77 -0
  6. package/build/generate-dist-package.js +26 -0
  7. package/build/generate-doc-images.ts +78 -0
  8. package/build/generate-docs.ts +190 -0
  9. package/build/generate-shaders.ts +68 -0
  10. package/build/generate-struct-arrays.ts +438 -0
  11. package/build/generate-style-code.ts +283 -0
  12. package/build/readme.md +56 -0
  13. package/build/release-notes.js +45 -0
  14. package/build/rollup/bundle_prelude.js +29 -0
  15. package/build/rollup/maplibregl.js +22 -0
  16. package/build/rollup_plugins.ts +58 -0
  17. package/dist/LICENSE.txt +116 -0
  18. package/dist/maplibre-gl.css +1 -0
  19. package/dist/maplibre-gl.d.ts +13304 -0
  20. package/dist/maplibre-gl.js +59 -0
  21. package/dist/maplibre-gl.js.map +1 -0
  22. package/dist/package.json +1 -0
  23. package/package.json +192 -0
  24. package/src/css/maplibre-gl.css +854 -0
  25. package/src/css/svg/maplibregl-ctrl-attrib.svg +3 -0
  26. package/src/css/svg/maplibregl-ctrl-compass.svg +4 -0
  27. package/src/css/svg/maplibregl-ctrl-fullscreen.svg +3 -0
  28. package/src/css/svg/maplibregl-ctrl-geolocate.svg +5 -0
  29. package/src/css/svg/maplibregl-ctrl-logo.svg +11 -0
  30. package/src/css/svg/maplibregl-ctrl-shrink.svg +3 -0
  31. package/src/css/svg/maplibregl-ctrl-terrain.svg +3 -0
  32. package/src/css/svg/maplibregl-ctrl-zoom-in.svg +3 -0
  33. package/src/css/svg/maplibregl-ctrl-zoom-out.svg +3 -0
  34. package/src/data/array_types.g.ts +1130 -0
  35. package/src/data/bucket/circle_attributes.ts +8 -0
  36. package/src/data/bucket/circle_bucket.ts +197 -0
  37. package/src/data/bucket/fill_attributes.ts +8 -0
  38. package/src/data/bucket/fill_bucket.test.ts +95 -0
  39. package/src/data/bucket/fill_bucket.ts +228 -0
  40. package/src/data/bucket/fill_extrusion_attributes.ts +13 -0
  41. package/src/data/bucket/fill_extrusion_bucket.ts +305 -0
  42. package/src/data/bucket/heatmap_bucket.ts +12 -0
  43. package/src/data/bucket/line_attributes.ts +8 -0
  44. package/src/data/bucket/line_attributes_ext.ts +8 -0
  45. package/src/data/bucket/line_bucket.test.ts +142 -0
  46. package/src/data/bucket/line_bucket.ts +592 -0
  47. package/src/data/bucket/pattern_attributes.ts +9 -0
  48. package/src/data/bucket/pattern_bucket_features.ts +57 -0
  49. package/src/data/bucket/symbol_attributes.ts +122 -0
  50. package/src/data/bucket/symbol_bucket.test.ts +243 -0
  51. package/src/data/bucket/symbol_bucket.ts +975 -0
  52. package/src/data/bucket.ts +123 -0
  53. package/src/data/dem_data.test.ts +237 -0
  54. package/src/data/dem_data.ts +171 -0
  55. package/src/data/evaluation_feature.ts +18 -0
  56. package/src/data/extent.ts +13 -0
  57. package/src/data/feature_index.ts +337 -0
  58. package/src/data/feature_position_map.test.ts +33 -0
  59. package/src/data/feature_position_map.ts +126 -0
  60. package/src/data/index_array_type.ts +9 -0
  61. package/src/data/load_geometry.test.ts +49 -0
  62. package/src/data/load_geometry.ts +44 -0
  63. package/src/data/pos3d_attributes.ts +5 -0
  64. package/src/data/pos_attributes.ts +5 -0
  65. package/src/data/program_configuration.ts +735 -0
  66. package/src/data/raster_bounds_attributes.ts +6 -0
  67. package/src/data/segment.ts +89 -0
  68. package/src/geo/edge_insets.test.ts +83 -0
  69. package/src/geo/edge_insets.ts +146 -0
  70. package/src/geo/lng_lat.test.ts +65 -0
  71. package/src/geo/lng_lat.ts +169 -0
  72. package/src/geo/lng_lat_bounds.test.ts +357 -0
  73. package/src/geo/lng_lat_bounds.ts +356 -0
  74. package/src/geo/mercator_coordinate.test.ts +34 -0
  75. package/src/geo/mercator_coordinate.ts +157 -0
  76. package/src/geo/projection/projection.ts +72 -0
  77. package/src/geo/transform.test.ts +509 -0
  78. package/src/geo/transform.ts +1072 -0
  79. package/src/gl/color_mode.ts +31 -0
  80. package/src/gl/context.ts +321 -0
  81. package/src/gl/cull_face_mode.ts +22 -0
  82. package/src/gl/depth_mode.ts +26 -0
  83. package/src/gl/framebuffer.ts +48 -0
  84. package/src/gl/index_buffer.ts +55 -0
  85. package/src/gl/render_pool.test.ts +69 -0
  86. package/src/gl/render_pool.ts +93 -0
  87. package/src/gl/state.test.ts +125 -0
  88. package/src/gl/stencil_mode.ts +27 -0
  89. package/src/gl/types.ts +59 -0
  90. package/src/gl/value.ts +534 -0
  91. package/src/gl/vertex_buffer.test.ts +57 -0
  92. package/src/gl/vertex_buffer.ts +111 -0
  93. package/src/gl/webgl2.ts +12 -0
  94. package/src/index.test.ts +121 -0
  95. package/src/index.ts +250 -0
  96. package/src/render/draw_background.ts +53 -0
  97. package/src/render/draw_circle.ts +113 -0
  98. package/src/render/draw_collision_debug.ts +168 -0
  99. package/src/render/draw_custom.test.ts +73 -0
  100. package/src/render/draw_custom.ts +45 -0
  101. package/src/render/draw_debug.test.ts +122 -0
  102. package/src/render/draw_debug.ts +148 -0
  103. package/src/render/draw_fill.test.ts +137 -0
  104. package/src/render/draw_fill.ts +128 -0
  105. package/src/render/draw_fill_extrusion.ts +97 -0
  106. package/src/render/draw_heatmap.ts +228 -0
  107. package/src/render/draw_hillshade.ts +119 -0
  108. package/src/render/draw_line.ts +125 -0
  109. package/src/render/draw_raster.ts +133 -0
  110. package/src/render/draw_sky.ts +44 -0
  111. package/src/render/draw_symbol.test.ts +223 -0
  112. package/src/render/draw_symbol.ts +499 -0
  113. package/src/render/draw_terrain.ts +99 -0
  114. package/src/render/glyph_atlas.ts +83 -0
  115. package/src/render/glyph_manager.test.ts +147 -0
  116. package/src/render/glyph_manager.ts +198 -0
  117. package/src/render/image_atlas.ts +159 -0
  118. package/src/render/image_manager.ts +337 -0
  119. package/src/render/line_atlas.test.ts +38 -0
  120. package/src/render/line_atlas.ts +214 -0
  121. package/src/render/mesh.ts +25 -0
  122. package/src/render/painter.test.ts +51 -0
  123. package/src/render/painter.ts +666 -0
  124. package/src/render/program/background_program.ts +100 -0
  125. package/src/render/program/circle_program.ts +61 -0
  126. package/src/render/program/clipping_mask_program.ts +19 -0
  127. package/src/render/program/collision_program.ts +47 -0
  128. package/src/render/program/debug_program.ts +29 -0
  129. package/src/render/program/fill_extrusion_program.ts +120 -0
  130. package/src/render/program/fill_program.ts +121 -0
  131. package/src/render/program/heatmap_program.ts +76 -0
  132. package/src/render/program/hillshade_program.ts +116 -0
  133. package/src/render/program/line_program.ts +207 -0
  134. package/src/render/program/pattern.ts +102 -0
  135. package/src/render/program/program_uniforms.ts +46 -0
  136. package/src/render/program/raster_program.ts +88 -0
  137. package/src/render/program/sky_program.ts +28 -0
  138. package/src/render/program/symbol_program.ts +266 -0
  139. package/src/render/program/terrain_program.ts +116 -0
  140. package/src/render/program.ts +233 -0
  141. package/src/render/render_to_texture.test.ts +151 -0
  142. package/src/render/render_to_texture.ts +197 -0
  143. package/src/render/terrain.test.ts +322 -0
  144. package/src/render/terrain.ts +464 -0
  145. package/src/render/texture.ts +114 -0
  146. package/src/render/uniform_binding.test.ts +122 -0
  147. package/src/render/uniform_binding.ts +157 -0
  148. package/src/render/update_pattern_positions_in_program.test.ts +74 -0
  149. package/src/render/update_pattern_positions_in_program.ts +50 -0
  150. package/src/render/vertex_array_object.ts +163 -0
  151. package/src/shaders/README.md +42 -0
  152. package/src/shaders/_prelude.fragment.glsl +19 -0
  153. package/src/shaders/_prelude.fragment.glsl.g.ts +2 -0
  154. package/src/shaders/_prelude.vertex.glsl +148 -0
  155. package/src/shaders/_prelude.vertex.glsl.g.ts +2 -0
  156. package/src/shaders/background.fragment.glsl +10 -0
  157. package/src/shaders/background.fragment.glsl.g.ts +2 -0
  158. package/src/shaders/background.vertex.glsl +7 -0
  159. package/src/shaders/background.vertex.glsl.g.ts +2 -0
  160. package/src/shaders/background_pattern.fragment.glsl +28 -0
  161. package/src/shaders/background_pattern.fragment.glsl.g.ts +2 -0
  162. package/src/shaders/background_pattern.vertex.glsl +19 -0
  163. package/src/shaders/background_pattern.vertex.glsl.g.ts +2 -0
  164. package/src/shaders/circle.fragment.glsl +34 -0
  165. package/src/shaders/circle.fragment.glsl.g.ts +2 -0
  166. package/src/shaders/circle.vertex.glsl +68 -0
  167. package/src/shaders/circle.vertex.glsl.g.ts +2 -0
  168. package/src/shaders/clipping_mask.fragment.glsl +3 -0
  169. package/src/shaders/clipping_mask.fragment.glsl.g.ts +2 -0
  170. package/src/shaders/clipping_mask.vertex.glsl +7 -0
  171. package/src/shaders/clipping_mask.vertex.glsl.g.ts +2 -0
  172. package/src/shaders/collision_box.fragment.glsl +20 -0
  173. package/src/shaders/collision_box.fragment.glsl.g.ts +2 -0
  174. package/src/shaders/collision_box.vertex.glsl +27 -0
  175. package/src/shaders/collision_box.vertex.glsl.g.ts +2 -0
  176. package/src/shaders/collision_circle.fragment.glsl +17 -0
  177. package/src/shaders/collision_circle.fragment.glsl.g.ts +2 -0
  178. package/src/shaders/collision_circle.vertex.glsl +59 -0
  179. package/src/shaders/collision_circle.vertex.glsl.g.ts +2 -0
  180. package/src/shaders/debug.fragment.glsl +9 -0
  181. package/src/shaders/debug.fragment.glsl.g.ts +2 -0
  182. package/src/shaders/debug.vertex.glsl +12 -0
  183. package/src/shaders/debug.vertex.glsl.g.ts +2 -0
  184. package/src/shaders/encode_attribute.test.ts +11 -0
  185. package/src/shaders/encode_attribute.ts +13 -0
  186. package/src/shaders/fill.fragment.glsl +13 -0
  187. package/src/shaders/fill.fragment.glsl.g.ts +2 -0
  188. package/src/shaders/fill.vertex.glsl +13 -0
  189. package/src/shaders/fill.vertex.glsl.g.ts +2 -0
  190. package/src/shaders/fill_extrusion.fragment.glsl +9 -0
  191. package/src/shaders/fill_extrusion.fragment.glsl.g.ts +2 -0
  192. package/src/shaders/fill_extrusion.vertex.glsl +84 -0
  193. package/src/shaders/fill_extrusion.vertex.glsl.g.ts +2 -0
  194. package/src/shaders/fill_extrusion_pattern.fragment.glsl +47 -0
  195. package/src/shaders/fill_extrusion_pattern.fragment.glsl.g.ts +2 -0
  196. package/src/shaders/fill_extrusion_pattern.vertex.glsl +96 -0
  197. package/src/shaders/fill_extrusion_pattern.vertex.glsl.g.ts +2 -0
  198. package/src/shaders/fill_outline.fragment.glsl +17 -0
  199. package/src/shaders/fill_outline.fragment.glsl.g.ts +2 -0
  200. package/src/shaders/fill_outline.vertex.glsl +17 -0
  201. package/src/shaders/fill_outline.vertex.glsl.g.ts +2 -0
  202. package/src/shaders/fill_outline_pattern.fragment.glsl +43 -0
  203. package/src/shaders/fill_outline_pattern.fragment.glsl.g.ts +2 -0
  204. package/src/shaders/fill_outline_pattern.vertex.glsl +44 -0
  205. package/src/shaders/fill_outline_pattern.vertex.glsl.g.ts +2 -0
  206. package/src/shaders/fill_pattern.fragment.glsl +39 -0
  207. package/src/shaders/fill_pattern.fragment.glsl.g.ts +2 -0
  208. package/src/shaders/fill_pattern.vertex.glsl +39 -0
  209. package/src/shaders/fill_pattern.vertex.glsl.g.ts +2 -0
  210. package/src/shaders/heatmap.fragment.glsl +22 -0
  211. package/src/shaders/heatmap.fragment.glsl.g.ts +2 -0
  212. package/src/shaders/heatmap.vertex.glsl +54 -0
  213. package/src/shaders/heatmap.vertex.glsl.g.ts +2 -0
  214. package/src/shaders/heatmap_texture.fragment.glsl +15 -0
  215. package/src/shaders/heatmap_texture.fragment.glsl.g.ts +2 -0
  216. package/src/shaders/heatmap_texture.vertex.glsl +11 -0
  217. package/src/shaders/heatmap_texture.vertex.glsl.g.ts +2 -0
  218. package/src/shaders/hillshade.fragment.glsl +52 -0
  219. package/src/shaders/hillshade.fragment.glsl.g.ts +2 -0
  220. package/src/shaders/hillshade.vertex.glsl +11 -0
  221. package/src/shaders/hillshade.vertex.glsl.g.ts +2 -0
  222. package/src/shaders/hillshade_prepare.fragment.glsl +77 -0
  223. package/src/shaders/hillshade_prepare.fragment.glsl.g.ts +2 -0
  224. package/src/shaders/hillshade_prepare.vertex.glsl +15 -0
  225. package/src/shaders/hillshade_prepare.vertex.glsl.g.ts +2 -0
  226. package/src/shaders/line.fragment.glsl +30 -0
  227. package/src/shaders/line.fragment.glsl.g.ts +2 -0
  228. package/src/shaders/line.vertex.glsl +89 -0
  229. package/src/shaders/line.vertex.glsl.g.ts +2 -0
  230. package/src/shaders/line_gradient.fragment.glsl +34 -0
  231. package/src/shaders/line_gradient.fragment.glsl.g.ts +2 -0
  232. package/src/shaders/line_gradient.vertex.glsl +92 -0
  233. package/src/shaders/line_gradient.vertex.glsl.g.ts +2 -0
  234. package/src/shaders/line_pattern.fragment.glsl +77 -0
  235. package/src/shaders/line_pattern.fragment.glsl.g.ts +2 -0
  236. package/src/shaders/line_pattern.vertex.glsl +103 -0
  237. package/src/shaders/line_pattern.vertex.glsl.g.ts +2 -0
  238. package/src/shaders/line_sdf.fragment.glsl +45 -0
  239. package/src/shaders/line_sdf.fragment.glsl.g.ts +2 -0
  240. package/src/shaders/line_sdf.vertex.glsl +101 -0
  241. package/src/shaders/line_sdf.vertex.glsl.g.ts +2 -0
  242. package/src/shaders/raster.fragment.glsl +53 -0
  243. package/src/shaders/raster.fragment.glsl.g.ts +2 -0
  244. package/src/shaders/raster.vertex.glsl +21 -0
  245. package/src/shaders/raster.vertex.glsl.g.ts +2 -0
  246. package/src/shaders/shaders.ts +197 -0
  247. package/src/shaders/sky.fragment.glsl +17 -0
  248. package/src/shaders/sky.fragment.glsl.g.ts +2 -0
  249. package/src/shaders/sky.vertex.glsl +5 -0
  250. package/src/shaders/sky.vertex.glsl.g.ts +2 -0
  251. package/src/shaders/symbol_icon.fragment.glsl +17 -0
  252. package/src/shaders/symbol_icon.fragment.glsl.g.ts +2 -0
  253. package/src/shaders/symbol_icon.vertex.glsl +117 -0
  254. package/src/shaders/symbol_icon.vertex.glsl.g.ts +2 -0
  255. package/src/shaders/symbol_sdf.fragment.glsl +58 -0
  256. package/src/shaders/symbol_sdf.fragment.glsl.g.ts +2 -0
  257. package/src/shaders/symbol_sdf.vertex.glsl +142 -0
  258. package/src/shaders/symbol_sdf.vertex.glsl.g.ts +2 -0
  259. package/src/shaders/symbol_text_and_icon.fragment.glsl +68 -0
  260. package/src/shaders/symbol_text_and_icon.fragment.glsl.g.ts +2 -0
  261. package/src/shaders/symbol_text_and_icon.vertex.glsl +140 -0
  262. package/src/shaders/symbol_text_and_icon.vertex.glsl.g.ts +2 -0
  263. package/src/shaders/terrain.fragment.glsl +32 -0
  264. package/src/shaders/terrain.fragment.glsl.g.ts +2 -0
  265. package/src/shaders/terrain.vertex.glsl +17 -0
  266. package/src/shaders/terrain.vertex.glsl.g.ts +2 -0
  267. package/src/shaders/terrain_coords.fragment.glsl +11 -0
  268. package/src/shaders/terrain_coords.fragment.glsl.g.ts +2 -0
  269. package/src/shaders/terrain_coords.vertex.glsl +13 -0
  270. package/src/shaders/terrain_coords.vertex.glsl.g.ts +2 -0
  271. package/src/shaders/terrain_depth.fragment.glsl +15 -0
  272. package/src/shaders/terrain_depth.fragment.glsl.g.ts +2 -0
  273. package/src/shaders/terrain_depth.vertex.glsl +13 -0
  274. package/src/shaders/terrain_depth.vertex.glsl.g.ts +2 -0
  275. package/src/source/canvas_source.test.ts +210 -0
  276. package/src/source/canvas_source.ts +227 -0
  277. package/src/source/geojson_source.test.ts +492 -0
  278. package/src/source/geojson_source.ts +431 -0
  279. package/src/source/geojson_source_diff.test.ts +364 -0
  280. package/src/source/geojson_source_diff.ts +172 -0
  281. package/src/source/geojson_worker_source.test.ts +399 -0
  282. package/src/source/geojson_worker_source.ts +303 -0
  283. package/src/source/geojson_wrapper.test.ts +32 -0
  284. package/src/source/geojson_wrapper.ts +81 -0
  285. package/src/source/image_source.test.ts +235 -0
  286. package/src/source/image_source.ts +338 -0
  287. package/src/source/load_tilejson.ts +47 -0
  288. package/src/source/pixels_to_tile_units.ts +25 -0
  289. package/src/source/protocol_crud.ts +48 -0
  290. package/src/source/query_features.test.ts +31 -0
  291. package/src/source/query_features.ts +252 -0
  292. package/src/source/raster_dem_tile_source.test.ts +158 -0
  293. package/src/source/raster_dem_tile_source.ts +166 -0
  294. package/src/source/raster_dem_tile_worker_source.test.ts +36 -0
  295. package/src/source/raster_dem_tile_worker_source.ts +38 -0
  296. package/src/source/raster_tile_source.test.ts +206 -0
  297. package/src/source/raster_tile_source.ts +227 -0
  298. package/src/source/rtl_text_plugin_main_thread.test.ts +170 -0
  299. package/src/source/rtl_text_plugin_main_thread.ts +89 -0
  300. package/src/source/rtl_text_plugin_status.ts +33 -0
  301. package/src/source/rtl_text_plugin_worker.ts +49 -0
  302. package/src/source/source.test.ts +41 -0
  303. package/src/source/source.ts +186 -0
  304. package/src/source/source_cache.test.ts +2069 -0
  305. package/src/source/source_cache.ts +1102 -0
  306. package/src/source/source_state.ts +157 -0
  307. package/src/source/terrain_source_cache.test.ts +105 -0
  308. package/src/source/terrain_source_cache.ts +204 -0
  309. package/src/source/tile.test.ts +290 -0
  310. package/src/source/tile.ts +478 -0
  311. package/src/source/tile_bounds.ts +34 -0
  312. package/src/source/tile_cache.test.ts +130 -0
  313. package/src/source/tile_cache.ts +208 -0
  314. package/src/source/tile_id.test.ts +112 -0
  315. package/src/source/tile_id.ts +221 -0
  316. package/src/source/vector_tile_source.test.ts +401 -0
  317. package/src/source/vector_tile_source.ts +283 -0
  318. package/src/source/vector_tile_worker_source.test.ts +396 -0
  319. package/src/source/vector_tile_worker_source.ts +199 -0
  320. package/src/source/video_source.test.ts +124 -0
  321. package/src/source/video_source.ts +204 -0
  322. package/src/source/worker.test.ts +233 -0
  323. package/src/source/worker.ts +301 -0
  324. package/src/source/worker_source.ts +117 -0
  325. package/src/source/worker_tile.test.ts +226 -0
  326. package/src/source/worker_tile.ts +208 -0
  327. package/src/style/create_style_layer.ts +39 -0
  328. package/src/style/evaluation_parameters.ts +62 -0
  329. package/src/style/format_section_override.test.ts +62 -0
  330. package/src/style/format_section_override.ts +50 -0
  331. package/src/style/light.test.ts +86 -0
  332. package/src/style/light.ts +135 -0
  333. package/src/style/load_glyph_range.test.ts +40 -0
  334. package/src/style/load_glyph_range.ts +32 -0
  335. package/src/style/load_sprite.test.ts +227 -0
  336. package/src/style/load_sprite.ts +71 -0
  337. package/src/style/parse_glyph_pbf.ts +42 -0
  338. package/src/style/pauseable_placement.ts +138 -0
  339. package/src/style/properties.ts +726 -0
  340. package/src/style/query_utils.test.ts +107 -0
  341. package/src/style/query_utils.ts +70 -0
  342. package/src/style/sky.ts +127 -0
  343. package/src/style/style.test.ts +2654 -0
  344. package/src/style/style.ts +1814 -0
  345. package/src/style/style_glyph.ts +25 -0
  346. package/src/style/style_image.ts +188 -0
  347. package/src/style/style_layer/background_style_layer.ts +17 -0
  348. package/src/style/style_layer/background_style_layer_properties.g.ts +40 -0
  349. package/src/style/style_layer/circle_style_layer.ts +98 -0
  350. package/src/style/style_layer/circle_style_layer_properties.g.ts +76 -0
  351. package/src/style/style_layer/custom_style_layer.ts +233 -0
  352. package/src/style/style_layer/fill_extrusion_style_layer.ts +224 -0
  353. package/src/style/style_layer/fill_extrusion_style_layer_properties.g.ts +55 -0
  354. package/src/style/style_layer/fill_style_layer.test.ts +37 -0
  355. package/src/style/style_layer/fill_style_layer.ts +65 -0
  356. package/src/style/style_layer/fill_style_layer_properties.g.ts +64 -0
  357. package/src/style/style_layer/heatmap_style_layer.ts +74 -0
  358. package/src/style/style_layer/heatmap_style_layer_properties.g.ts +46 -0
  359. package/src/style/style_layer/hillshade_style_layer.ts +21 -0
  360. package/src/style/style_layer/hillshade_style_layer_properties.g.ts +49 -0
  361. package/src/style/style_layer/line_style_layer.test.ts +50 -0
  362. package/src/style/style_layer/line_style_layer.ts +131 -0
  363. package/src/style/style_layer/line_style_layer_properties.g.ts +88 -0
  364. package/src/style/style_layer/overlap_mode.test.ts +57 -0
  365. package/src/style/style_layer/overlap_mode.ts +25 -0
  366. package/src/style/style_layer/raster_style_layer.ts +17 -0
  367. package/src/style/style_layer/raster_style_layer_properties.g.ts +55 -0
  368. package/src/style/style_layer/symbol_style_layer.ts +195 -0
  369. package/src/style/style_layer/symbol_style_layer_properties.g.ts +218 -0
  370. package/src/style/style_layer/typed_style_layer.ts +9 -0
  371. package/src/style/style_layer/variable_text_anchor.test.ts +117 -0
  372. package/src/style/style_layer/variable_text_anchor.ts +163 -0
  373. package/src/style/style_layer.test.ts +372 -0
  374. package/src/style/style_layer.ts +287 -0
  375. package/src/style/style_layer_index.test.ts +99 -0
  376. package/src/style/style_layer_index.ts +78 -0
  377. package/src/style/validate_style.ts +53 -0
  378. package/src/style/zoom_history.ts +40 -0
  379. package/src/symbol/anchor.test.ts +14 -0
  380. package/src/symbol/anchor.ts +22 -0
  381. package/src/symbol/check_max_angle.test.ts +54 -0
  382. package/src/symbol/check_max_angle.ts +76 -0
  383. package/src/symbol/clip_line.test.ts +154 -0
  384. package/src/symbol/clip_line.ts +66 -0
  385. package/src/symbol/collision_feature.test.ts +98 -0
  386. package/src/symbol/collision_feature.ts +114 -0
  387. package/src/symbol/collision_index.test.ts +19 -0
  388. package/src/symbol/collision_index.ts +618 -0
  389. package/src/symbol/cross_tile_symbol_index.test.ts +260 -0
  390. package/src/symbol/cross_tile_symbol_index.ts +367 -0
  391. package/src/symbol/get_anchors.test.ts +113 -0
  392. package/src/symbol/get_anchors.ts +167 -0
  393. package/src/symbol/grid_index.test.ts +75 -0
  394. package/src/symbol/grid_index.ts +414 -0
  395. package/src/symbol/merge_lines.test.ts +30 -0
  396. package/src/symbol/merge_lines.ts +80 -0
  397. package/src/symbol/one_em.ts +3 -0
  398. package/src/symbol/opacity_state.ts +23 -0
  399. package/src/symbol/path_interpolator.test.ts +134 -0
  400. package/src/symbol/path_interpolator.ts +55 -0
  401. package/src/symbol/placement.ts +1371 -0
  402. package/src/symbol/projection.test.ts +171 -0
  403. package/src/symbol/projection.ts +833 -0
  404. package/src/symbol/quads.test.ts +157 -0
  405. package/src/symbol/quads.ts +349 -0
  406. package/src/symbol/shaping.test.ts +360 -0
  407. package/src/symbol/shaping.ts +911 -0
  408. package/src/symbol/symbol_layout.ts +739 -0
  409. package/src/symbol/symbol_size.ts +129 -0
  410. package/src/symbol/symbol_style_layer.test.ts +103 -0
  411. package/src/symbol/transform_text.ts +27 -0
  412. package/src/ui/anchor.ts +27 -0
  413. package/src/ui/camera.test.ts +2301 -0
  414. package/src/ui/camera.ts +1520 -0
  415. package/src/ui/control/attribution_control.test.ts +543 -0
  416. package/src/ui/control/attribution_control.ts +209 -0
  417. package/src/ui/control/control.ts +67 -0
  418. package/src/ui/control/fullscreen_control.test.ts +114 -0
  419. package/src/ui/control/fullscreen_control.ts +189 -0
  420. package/src/ui/control/geolocate_control.test.ts +619 -0
  421. package/src/ui/control/geolocate_control.ts +725 -0
  422. package/src/ui/control/logo_control.test.ts +88 -0
  423. package/src/ui/control/logo_control.ts +86 -0
  424. package/src/ui/control/navigation_control.test.ts +238 -0
  425. package/src/ui/control/navigation_control.ts +294 -0
  426. package/src/ui/control/scale_control.test.ts +52 -0
  427. package/src/ui/control/scale_control.ts +152 -0
  428. package/src/ui/control/terrain_control.test.ts +58 -0
  429. package/src/ui/control/terrain_control.ts +74 -0
  430. package/src/ui/default_locale.ts +25 -0
  431. package/src/ui/events.ts +758 -0
  432. package/src/ui/handler/box_zoom.test.ts +163 -0
  433. package/src/ui/handler/box_zoom.ts +171 -0
  434. package/src/ui/handler/click_zoom.ts +55 -0
  435. package/src/ui/handler/cooperative_gestures.test.ts +338 -0
  436. package/src/ui/handler/cooperative_gestures.ts +111 -0
  437. package/src/ui/handler/dblclick_zoom.test.ts +151 -0
  438. package/src/ui/handler/drag_handler.ts +174 -0
  439. package/src/ui/handler/drag_move_state_manager.ts +115 -0
  440. package/src/ui/handler/drag_pan.test.ts +487 -0
  441. package/src/ui/handler/drag_rotate.test.ts +859 -0
  442. package/src/ui/handler/handler_util.ts +10 -0
  443. package/src/ui/handler/keyboard.test.ts +235 -0
  444. package/src/ui/handler/keyboard.ts +212 -0
  445. package/src/ui/handler/map_event.test.ts +158 -0
  446. package/src/ui/handler/map_event.ts +161 -0
  447. package/src/ui/handler/mouse.ts +92 -0
  448. package/src/ui/handler/mouse_handler_interface.test.ts +111 -0
  449. package/src/ui/handler/mouse_rotate.test.ts +62 -0
  450. package/src/ui/handler/one_finger_touch_drag.ts +45 -0
  451. package/src/ui/handler/one_finger_touch_drag_handler_interface.test.ts +77 -0
  452. package/src/ui/handler/scroll_zoom.test.ts +382 -0
  453. package/src/ui/handler/scroll_zoom.ts +379 -0
  454. package/src/ui/handler/shim/dblclick_zoom.ts +64 -0
  455. package/src/ui/handler/shim/drag_pan.ts +104 -0
  456. package/src/ui/handler/shim/drag_rotate.ts +76 -0
  457. package/src/ui/handler/shim/two_fingers_touch.ts +112 -0
  458. package/src/ui/handler/tap_drag_zoom.test.ts +113 -0
  459. package/src/ui/handler/tap_drag_zoom.ts +112 -0
  460. package/src/ui/handler/tap_recognizer.ts +138 -0
  461. package/src/ui/handler/tap_zoom.ts +98 -0
  462. package/src/ui/handler/touch_pan.ts +115 -0
  463. package/src/ui/handler/transform-provider.ts +44 -0
  464. package/src/ui/handler/two_fingers_touch.test.ts +283 -0
  465. package/src/ui/handler/two_fingers_touch.ts +336 -0
  466. package/src/ui/handler_inertia.ts +157 -0
  467. package/src/ui/handler_manager.ts +637 -0
  468. package/src/ui/hash.test.ts +404 -0
  469. package/src/ui/hash.ts +153 -0
  470. package/src/ui/map.ts +3393 -0
  471. package/src/ui/map_tests/map_animation.test.ts +61 -0
  472. package/src/ui/map_tests/map_basic.test.ts +223 -0
  473. package/src/ui/map_tests/map_bounds.test.ts +123 -0
  474. package/src/ui/map_tests/map_calculate_camera_options.test.ts +113 -0
  475. package/src/ui/map_tests/map_canvas.test.ts +59 -0
  476. package/src/ui/map_tests/map_control.test.ts +61 -0
  477. package/src/ui/map_tests/map_disable_handlers.test.ts +38 -0
  478. package/src/ui/map_tests/map_events.test.ts +1001 -0
  479. package/src/ui/map_tests/map_feature_state.test.ts +421 -0
  480. package/src/ui/map_tests/map_images.test.ts +175 -0
  481. package/src/ui/map_tests/map_is_moving.test.ts +164 -0
  482. package/src/ui/map_tests/map_is_rotating.test.ts +62 -0
  483. package/src/ui/map_tests/map_is_zooming.test.ts +86 -0
  484. package/src/ui/map_tests/map_layer.test.ts +457 -0
  485. package/src/ui/map_tests/map_options.test.ts +64 -0
  486. package/src/ui/map_tests/map_pitch.test.ts +90 -0
  487. package/src/ui/map_tests/map_pixel_ratio.test.ts +75 -0
  488. package/src/ui/map_tests/map_query_rendered_features.test.ts +93 -0
  489. package/src/ui/map_tests/map_render.test.ts +90 -0
  490. package/src/ui/map_tests/map_request_render_frame.test.ts +51 -0
  491. package/src/ui/map_tests/map_resize.test.ts +120 -0
  492. package/src/ui/map_tests/map_style.test.ts +541 -0
  493. package/src/ui/map_tests/map_terrian.test.ts +104 -0
  494. package/src/ui/map_tests/map_webgl.test.ts +72 -0
  495. package/src/ui/map_tests/map_world_copies.test.ts +103 -0
  496. package/src/ui/map_tests/map_zoom.test.ts +95 -0
  497. package/src/ui/marker.test.ts +1149 -0
  498. package/src/ui/marker.ts +880 -0
  499. package/src/ui/popup.test.ts +827 -0
  500. package/src/ui/popup.ts +717 -0
  501. package/src/util/abort_error.ts +21 -0
  502. package/src/util/actor.test.ts +218 -0
  503. package/src/util/actor.ts +241 -0
  504. package/src/util/actor_messages.ts +149 -0
  505. package/src/util/ajax.test.ts +237 -0
  506. package/src/util/ajax.ts +297 -0
  507. package/src/util/browser.test.ts +23 -0
  508. package/src/util/browser.ts +63 -0
  509. package/src/util/color_ramp.test.ts +105 -0
  510. package/src/util/color_ramp.ts +56 -0
  511. package/src/util/config.ts +29 -0
  512. package/src/util/dictionary_coder.ts +23 -0
  513. package/src/util/dispatcher.test.ts +76 -0
  514. package/src/util/dispatcher.ts +78 -0
  515. package/src/util/dom.ts +135 -0
  516. package/src/util/evented.test.ts +231 -0
  517. package/src/util/evented.ts +178 -0
  518. package/src/util/find_pole_of_inaccessibility.test.ts +21 -0
  519. package/src/util/find_pole_of_inaccessibility.ts +130 -0
  520. package/src/util/geolocation_support.test.ts +43 -0
  521. package/src/util/geolocation_support.ts +23 -0
  522. package/src/util/global_worker_pool.ts +65 -0
  523. package/src/util/image.ts +150 -0
  524. package/src/util/image_request.test.ts +408 -0
  525. package/src/util/image_request.ts +246 -0
  526. package/src/util/intersection_tests.ts +206 -0
  527. package/src/util/is_char_in_unicode_block.test.ts +15 -0
  528. package/src/util/is_char_in_unicode_block.ts +345 -0
  529. package/src/util/offscreen_canvas_distorted.test.ts +13 -0
  530. package/src/util/offscreen_canvas_distorted.ts +39 -0
  531. package/src/util/offscreen_canvas_supported.ts +11 -0
  532. package/src/util/performance.ts +117 -0
  533. package/src/util/primitives.test.ts +140 -0
  534. package/src/util/primitives.ts +143 -0
  535. package/src/util/request_manager.ts +42 -0
  536. package/src/util/resolve_tokens.test.ts +45 -0
  537. package/src/util/resolve_tokens.ts +17 -0
  538. package/src/util/script_detection.test.ts +138 -0
  539. package/src/util/script_detection.ts +376 -0
  540. package/src/util/smart_wrap.test.ts +97 -0
  541. package/src/util/smart_wrap.ts +58 -0
  542. package/src/util/struct_array.test.ts +101 -0
  543. package/src/util/struct_array.ts +246 -0
  544. package/src/util/style.test.ts +34 -0
  545. package/src/util/style.ts +28 -0
  546. package/src/util/task_queue.test.ts +114 -0
  547. package/src/util/task_queue.ts +64 -0
  548. package/src/util/test/util.ts +185 -0
  549. package/src/util/throttle.test.ts +42 -0
  550. package/src/util/throttle.ts +28 -0
  551. package/src/util/throttled_invoker.ts +41 -0
  552. package/src/util/transferable_grid_index.test.ts +56 -0
  553. package/src/util/transferable_grid_index.ts +214 -0
  554. package/src/util/util.test.ts +414 -0
  555. package/src/util/util.ts +724 -0
  556. package/src/util/vectortile_to_geojson.ts +72 -0
  557. package/src/util/verticalize_punctuation.ts +110 -0
  558. package/src/util/web_worker.ts +16 -0
  559. package/src/util/web_worker_transfer.test.ts +153 -0
  560. package/src/util/web_worker_transfer.ts +254 -0
  561. package/src/util/webp_supported.ts +63 -0
  562. package/src/util/worker_pool.test.ts +43 -0
  563. package/src/util/worker_pool.ts +58 -0
  564. package/src/util/world_bounds.test.ts +59 -0
  565. package/src/util/world_bounds.ts +46 -0
@@ -0,0 +1,1814 @@
1
+ import {Event, ErrorEvent, Evented} from '../util/evented';
2
+ import {StyleLayer} from './style_layer';
3
+ import {createStyleLayer} from './create_style_layer';
4
+ import {loadSprite} from './load_sprite';
5
+ import {ImageManager} from '../render/image_manager';
6
+ import {GlyphManager} from '../render/glyph_manager';
7
+ import {Light} from './light';
8
+ import {Sky} from './sky';
9
+ import {LineAtlas} from '../render/line_atlas';
10
+ import {clone, extend, deepEqual, filterObject, mapObject} from '../util/util';
11
+ import {coerceSpriteToArray} from '../util/style';
12
+ import {getJSON, getReferrer} from '../util/ajax';
13
+ import {ResourceType} from '../util/request_manager';
14
+ import {browser} from '../util/browser';
15
+ import {Dispatcher} from '../util/dispatcher';
16
+ import {validateStyle, emitValidationErrors as _emitValidationErrors} from './validate_style';
17
+ import {Source} from '../source/source';
18
+ import {QueryRenderedFeaturesOptions, QuerySourceFeatureOptions, queryRenderedFeatures, queryRenderedSymbols, querySourceFeatures} from '../source/query_features';
19
+ import {SourceCache} from '../source/source_cache';
20
+ import {GeoJSONSource} from '../source/geojson_source';
21
+ import {latest as styleSpec, derefLayers as deref, emptyStyle, diff as diffStyles, DiffCommand} from '@maplibre/maplibre-gl-style-spec';
22
+ import {getGlobalWorkerPool} from '../util/global_worker_pool';
23
+ import {rtlMainThreadPluginFactory} from '../source/rtl_text_plugin_main_thread';
24
+ import {RTLPluginLoadedEventName} from '../source/rtl_text_plugin_status';
25
+ import {PauseablePlacement} from './pauseable_placement';
26
+ import {ZoomHistory} from './zoom_history';
27
+ import {CrossTileSymbolIndex} from '../symbol/cross_tile_symbol_index';
28
+ import {validateCustomStyleLayer} from './style_layer/custom_style_layer';
29
+ import type {MapGeoJSONFeature} from '../util/vectortile_to_geojson';
30
+
31
+ // We're skipping validation errors with the `source.canvas` identifier in order
32
+ // to continue to allow canvas sources to be added at runtime/updated in
33
+ // smart setStyle (see https://github.com/mapbox/mapbox-gl-js/pull/6424):
34
+ const emitValidationErrors = (evented: Evented, errors?: ReadonlyArray<{
35
+ message: string;
36
+ identifier?: string;
37
+ }> | null) =>
38
+ _emitValidationErrors(evented, errors && errors.filter(error => error.identifier !== 'source.canvas'));
39
+
40
+ import type {Map} from '../ui/map';
41
+ import type {Transform} from '../geo/transform';
42
+ import type {StyleImage} from './style_image';
43
+ import type {EvaluationParameters} from './evaluation_parameters';
44
+ import type {Placement} from '../symbol/placement';
45
+ import type {
46
+ LayerSpecification,
47
+ FilterSpecification,
48
+ StyleSpecification,
49
+ LightSpecification,
50
+ SourceSpecification,
51
+ SpriteSpecification,
52
+ DiffOperations,
53
+ SkySpecification
54
+ } from '@maplibre/maplibre-gl-style-spec';
55
+ import type {CanvasSourceSpecification} from '../source/canvas_source';
56
+ import type {CustomLayerInterface} from './style_layer/custom_style_layer';
57
+ import type {Validator} from './validate_style';
58
+ import {
59
+ MessageType,
60
+ type GetGlyphsParameters,
61
+ type GetGlyphsResponse,
62
+ type GetImagesParameters,
63
+ type GetImagesResponse
64
+ } from '../util/actor_messages';
65
+
66
+ const empty = emptyStyle() as StyleSpecification;
67
+ /**
68
+ * A feature identifier that is bound to a source
69
+ */
70
+ export type FeatureIdentifier = {
71
+ /**
72
+ * Unique id of the feature.
73
+ */
74
+ id?: string | number | undefined;
75
+ /**
76
+ * The id of the vector or GeoJSON source for the feature.
77
+ */
78
+ source: string;
79
+ /**
80
+ * *For vector tile sources, `sourceLayer` is required.*
81
+ */
82
+ sourceLayer?: string | undefined;
83
+ };
84
+
85
+ /**
86
+ * The options object related to the {@link Map}'s style related methods
87
+ */
88
+ export type StyleOptions = {
89
+ /**
90
+ * If false, style validation will be skipped. Useful in production environment.
91
+ */
92
+ validate?: boolean;
93
+ /**
94
+ * Defines a CSS
95
+ * font-family for locally overriding generation of Chinese, Japanese, and Korean characters.
96
+ * For these characters, font settings from the map's style will be ignored, except for font-weight keywords (light/regular/medium/bold).
97
+ * Set to `false`, to enable font settings from the map's style for these glyph ranges.
98
+ * Forces a full update.
99
+ */
100
+ localIdeographFontFamily?: string | false;
101
+ };
102
+
103
+ /**
104
+ * Supporting type to add validation to another style related type
105
+ */
106
+ export type StyleSetterOptions = {
107
+ /**
108
+ * Whether to check if the filter conforms to the MapLibre Style Specification. Disabling validation is a performance optimization that should only be used if you have previously validated the values you will be passing to this function.
109
+ */
110
+ validate?: boolean;
111
+ };
112
+
113
+ /**
114
+ * Part of {@link Map#setStyle} options, transformStyle is a convenience function that allows to modify a style after it is fetched but before it is committed to the map state.
115
+ *
116
+ * This function exposes previous and next styles, it can be commonly used to support a range of functionalities like:
117
+ *
118
+ * - when previous style carries certain 'state' that needs to be carried over to a new style gracefully;
119
+ * - when a desired style is a certain combination of previous and incoming style;
120
+ * - when an incoming style requires modification based on external state.
121
+ *
122
+ * @param previous - The current style.
123
+ * @param next - The next style.
124
+ * @returns resulting style that will to be applied to the map
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * map.setStyle('https://demotiles.maplibre.org/style.json', {
129
+ * transformStyle: (previousStyle, nextStyle) => ({
130
+ * ...nextStyle,
131
+ * sources: {
132
+ * ...nextStyle.sources,
133
+ * // copy a source from previous style
134
+ * 'osm': previousStyle.sources.osm
135
+ * },
136
+ * layers: [
137
+ * // background layer
138
+ * nextStyle.layers[0],
139
+ * // copy a layer from previous style
140
+ * previousStyle.layers[0],
141
+ * // other layers from the next style
142
+ * ...nextStyle.layers.slice(1).map(layer => {
143
+ * // hide the layers we don't need from demotiles style
144
+ * if (layer.id.startsWith('geolines')) {
145
+ * layer.layout = {...layer.layout || {}, visibility: 'none'};
146
+ * // filter out US polygons
147
+ * } else if (layer.id.startsWith('coastline') || layer.id.startsWith('countries')) {
148
+ * layer.filter = ['!=', ['get', 'ADM0_A3'], 'USA'];
149
+ * }
150
+ * return layer;
151
+ * })
152
+ * ]
153
+ * })
154
+ * });
155
+ * ```
156
+ */
157
+ export type TransformStyleFunction = (previous: StyleSpecification | undefined, next: StyleSpecification) => StyleSpecification;
158
+
159
+ /**
160
+ * The options object related to the {@link Map}'s style related methods
161
+ */
162
+ export type StyleSwapOptions = {
163
+ /**
164
+ * If false, force a 'full' update, removing the current style
165
+ * and building the given one instead of attempting a diff-based update.
166
+ */
167
+ diff?: boolean;
168
+ /**
169
+ * TransformStyleFunction is a convenience function
170
+ * that allows to modify a style after it is fetched but before it is committed to the map state. Refer to {@link TransformStyleFunction}.
171
+ */
172
+ transformStyle?: TransformStyleFunction;
173
+ }
174
+
175
+ /**
176
+ * Specifies a layer to be added to a {@link Style}. In addition to a standard {@link LayerSpecification}
177
+ * or a {@link CustomLayerInterface}, a {@link LayerSpecification} with an embedded {@link SourceSpecification} can also be provided.
178
+ */
179
+ export type AddLayerObject = LayerSpecification | (Omit<LayerSpecification, 'source'> & {source: SourceSpecification}) | CustomLayerInterface;
180
+
181
+ /**
182
+ * The Style base class
183
+ */
184
+ export class Style extends Evented {
185
+ map: Map;
186
+ stylesheet: StyleSpecification;
187
+ dispatcher: Dispatcher;
188
+ imageManager: ImageManager;
189
+ glyphManager: GlyphManager;
190
+ lineAtlas: LineAtlas;
191
+ light: Light;
192
+ sky: Sky;
193
+
194
+ _frameRequest: AbortController;
195
+ _loadStyleRequest: AbortController;
196
+ _spriteRequest: AbortController;
197
+ _layers: {[_: string]: StyleLayer};
198
+ _serializedLayers: {[_: string]: LayerSpecification};
199
+ _order: Array<string>;
200
+ sourceCaches: {[_: string]: SourceCache};
201
+ zoomHistory: ZoomHistory;
202
+ _loaded: boolean;
203
+ _changed: boolean;
204
+ _updatedSources: {[_: string]: 'clear' | 'reload'};
205
+ _updatedLayers: {[_: string]: true};
206
+ _removedLayers: {[_: string]: StyleLayer};
207
+ _changedImages: {[_: string]: true};
208
+ _glyphsDidChange: boolean;
209
+ _updatedPaintProps: {[layer: string]: true};
210
+ _layerOrderChanged: boolean;
211
+ // image ids of images loaded from style's sprite
212
+ _spritesImagesIds: {[spriteId: string]: string[]};
213
+ // image ids of all images loaded (sprite + user)
214
+ _availableImages: Array<string>;
215
+
216
+ crossTileSymbolIndex: CrossTileSymbolIndex;
217
+ pauseablePlacement: PauseablePlacement;
218
+ placement: Placement;
219
+ z: number;
220
+
221
+ constructor(map: Map, options: StyleOptions = {}) {
222
+ super();
223
+
224
+ this.map = map;
225
+ this.dispatcher = new Dispatcher(getGlobalWorkerPool(), map._getMapId());
226
+ this.dispatcher.registerMessageHandler(MessageType.getGlyphs, (mapId, params) => {
227
+ return this.getGlyphs(mapId, params);
228
+ });
229
+ this.dispatcher.registerMessageHandler(MessageType.getImages, (mapId, params) => {
230
+ return this.getImages(mapId, params);
231
+ });
232
+ this.imageManager = new ImageManager();
233
+ this.imageManager.setEventedParent(this);
234
+ this.glyphManager = new GlyphManager(map._requestManager, options.localIdeographFontFamily);
235
+ this.lineAtlas = new LineAtlas(256, 512);
236
+ this.crossTileSymbolIndex = new CrossTileSymbolIndex();
237
+
238
+ this._spritesImagesIds = {};
239
+ this._layers = {};
240
+
241
+ this._order = [];
242
+ this.sourceCaches = {};
243
+ this.zoomHistory = new ZoomHistory();
244
+ this._loaded = false;
245
+ this._availableImages = [];
246
+
247
+ this._resetUpdates();
248
+
249
+ this.dispatcher.broadcast(MessageType.setReferrer, getReferrer());
250
+ rtlMainThreadPluginFactory().on(RTLPluginLoadedEventName, this._rtlPluginLoaded);
251
+
252
+ this.on('data', (event) => {
253
+ if (event.dataType !== 'source' || event.sourceDataType !== 'metadata') {
254
+ return;
255
+ }
256
+
257
+ const sourceCache = this.sourceCaches[event.sourceId];
258
+ if (!sourceCache) {
259
+ return;
260
+ }
261
+
262
+ const source = sourceCache.getSource();
263
+ if (!source || !source.vectorLayerIds) {
264
+ return;
265
+ }
266
+
267
+ for (const layerId in this._layers) {
268
+ const layer = this._layers[layerId];
269
+ if (layer.source === source.id) {
270
+ this._validateLayer(layer);
271
+ }
272
+ }
273
+ });
274
+ }
275
+
276
+ _rtlPluginLoaded = () => {
277
+ for (const id in this.sourceCaches) {
278
+ const sourceType = this.sourceCaches[id].getSource().type;
279
+ if (sourceType === 'vector' || sourceType === 'geojson') {
280
+ // Non-vector sources don't have any symbols buckets to reload when the RTL text plugin loads
281
+ // They also load more quickly, so they're more likely to have already displaying tiles
282
+ // that would be unnecessarily booted by the plugin load event
283
+ this.sourceCaches[id].reload(); // Should be a no-op if the plugin loads before any tiles load
284
+ }
285
+ }
286
+ };
287
+
288
+ loadURL(url: string, options: StyleSwapOptions & StyleSetterOptions = {}, previousStyle?: StyleSpecification) {
289
+ this.fire(new Event('dataloading', {dataType: 'style'}));
290
+
291
+ options.validate = typeof options.validate === 'boolean' ?
292
+ options.validate : true;
293
+
294
+ const request = this.map._requestManager.transformRequest(url, ResourceType.Style);
295
+ this._loadStyleRequest = new AbortController();
296
+ const abortController = this._loadStyleRequest;
297
+ getJSON<StyleSpecification>(request, this._loadStyleRequest).then((response) => {
298
+ this._loadStyleRequest = null;
299
+ this._load(response.data, options, previousStyle);
300
+ }).catch((error) => {
301
+ this._loadStyleRequest = null;
302
+ if (error && !abortController.signal.aborted) { // ignore abort
303
+ this.fire(new ErrorEvent(error));
304
+ }
305
+ });
306
+ }
307
+
308
+ loadJSON(json: StyleSpecification, options: StyleSetterOptions & StyleSwapOptions = {}, previousStyle?: StyleSpecification) {
309
+ this.fire(new Event('dataloading', {dataType: 'style'}));
310
+
311
+ this._frameRequest = new AbortController();
312
+ browser.frameAsync(this._frameRequest).then(() => {
313
+ this._frameRequest = null;
314
+ options.validate = options.validate !== false;
315
+ this._load(json, options, previousStyle);
316
+ }).catch(() => {}); // ignore abort
317
+ }
318
+
319
+ loadEmpty() {
320
+ this.fire(new Event('dataloading', {dataType: 'style'}));
321
+ this._load(empty, {validate: false});
322
+ }
323
+
324
+ _load(json: StyleSpecification, options: StyleSwapOptions & StyleSetterOptions, previousStyle?: StyleSpecification) {
325
+ const nextState = options.transformStyle ? options.transformStyle(previousStyle, json) : json;
326
+ if (options.validate && emitValidationErrors(this, validateStyle(nextState))) {
327
+ return;
328
+ }
329
+
330
+ this._loaded = true;
331
+ this.stylesheet = nextState;
332
+
333
+ for (const id in nextState.sources) {
334
+ this.addSource(id, nextState.sources[id], {validate: false});
335
+ }
336
+
337
+ if (nextState.sprite) {
338
+ this._loadSprite(nextState.sprite);
339
+ } else {
340
+ this.imageManager.setLoaded(true);
341
+ }
342
+
343
+ this.glyphManager.setURL(nextState.glyphs);
344
+ this._createLayers();
345
+
346
+ this.light = new Light(this.stylesheet.light);
347
+ this.sky = new Sky(this.stylesheet.sky);
348
+
349
+ this.map.setTerrain(this.stylesheet.terrain ?? null);
350
+
351
+ this.fire(new Event('data', {dataType: 'style'}));
352
+ this.fire(new Event('style.load'));
353
+ }
354
+
355
+ private _createLayers() {
356
+ const dereferencedLayers = deref(this.stylesheet.layers);
357
+
358
+ // Broadcast layers to workers first, so that expensive style processing (createStyleLayer)
359
+ // can happen in parallel on both main and worker threads.
360
+ this.dispatcher.broadcast(MessageType.setLayers, dereferencedLayers);
361
+
362
+ this._order = dereferencedLayers.map((layer) => layer.id);
363
+ this._layers = {};
364
+
365
+ // reset serialization field, to be populated only when needed
366
+ this._serializedLayers = null;
367
+ for (const layer of dereferencedLayers) {
368
+ const styledLayer = createStyleLayer(layer);
369
+ styledLayer.setEventedParent(this, {layer: {id: layer.id}});
370
+ this._layers[layer.id] = styledLayer;
371
+ }
372
+ }
373
+
374
+ _loadSprite(sprite: SpriteSpecification, isUpdate: boolean = false, completion: (err: Error) => void = undefined) {
375
+ this.imageManager.setLoaded(false);
376
+
377
+ this._spriteRequest = new AbortController();
378
+ let err: Error;
379
+ loadSprite(sprite, this.map._requestManager, this.map.getPixelRatio(), this._spriteRequest).then((images) => {
380
+ this._spriteRequest = null;
381
+ if (images) {
382
+ for (const spriteId in images) {
383
+ this._spritesImagesIds[spriteId] = [];
384
+
385
+ // remove old sprite's loaded images (for the same sprite id) that are not in new sprite
386
+ const imagesToRemove = this._spritesImagesIds[spriteId] ? this._spritesImagesIds[spriteId].filter(id => !(id in images)) : [];
387
+ for (const id of imagesToRemove) {
388
+ this.imageManager.removeImage(id);
389
+ this._changedImages[id] = true;
390
+ }
391
+
392
+ for (const id in images[spriteId]) {
393
+ // don't prefix images of the "default" sprite
394
+ const imageId = spriteId === 'default' ? id : `${spriteId}:${id}`;
395
+ // save all the sprite's images' ids to be able to delete them in `removeSprite`
396
+ this._spritesImagesIds[spriteId].push(imageId);
397
+ if (imageId in this.imageManager.images) {
398
+ this.imageManager.updateImage(imageId, images[spriteId][id], false);
399
+ } else {
400
+ this.imageManager.addImage(imageId, images[spriteId][id]);
401
+ }
402
+
403
+ if (isUpdate) {
404
+ this._changedImages[imageId] = true;
405
+ }
406
+ }
407
+ }
408
+ }
409
+ }).catch((error) => {
410
+ this._spriteRequest = null;
411
+ err = error;
412
+ this.fire(new ErrorEvent(err));
413
+ }).finally(() => {
414
+ this.imageManager.setLoaded(true);
415
+ this._availableImages = this.imageManager.listImages();
416
+
417
+ if (isUpdate) {
418
+ this._changed = true;
419
+ }
420
+
421
+ this.dispatcher.broadcast(MessageType.setImages, this._availableImages);
422
+ this.fire(new Event('data', {dataType: 'style'}));
423
+
424
+ if (completion) {
425
+ completion(err);
426
+ }
427
+ });
428
+ }
429
+
430
+ _unloadSprite() {
431
+ for (const id of Object.values(this._spritesImagesIds).flat()) {
432
+ this.imageManager.removeImage(id);
433
+ this._changedImages[id] = true;
434
+ }
435
+
436
+ this._spritesImagesIds = {};
437
+ this._availableImages = this.imageManager.listImages();
438
+ this._changed = true;
439
+ this.dispatcher.broadcast(MessageType.setImages, this._availableImages);
440
+ this.fire(new Event('data', {dataType: 'style'}));
441
+ }
442
+
443
+ _validateLayer(layer: StyleLayer) {
444
+ const sourceCache = this.sourceCaches[layer.source];
445
+ if (!sourceCache) {
446
+ return;
447
+ }
448
+
449
+ const sourceLayer = layer.sourceLayer;
450
+ if (!sourceLayer) {
451
+ return;
452
+ }
453
+
454
+ const source = sourceCache.getSource();
455
+ if (source.type === 'geojson' || (source.vectorLayerIds && source.vectorLayerIds.indexOf(sourceLayer) === -1)) {
456
+ this.fire(new ErrorEvent(new Error(
457
+ `Source layer "${sourceLayer}" ` +
458
+ `does not exist on source "${source.id}" ` +
459
+ `as specified by style layer "${layer.id}".`
460
+ )));
461
+ }
462
+ }
463
+
464
+ loaded() {
465
+ if (!this._loaded)
466
+ return false;
467
+
468
+ if (Object.keys(this._updatedSources).length)
469
+ return false;
470
+
471
+ for (const id in this.sourceCaches)
472
+ if (!this.sourceCaches[id].loaded())
473
+ return false;
474
+
475
+ if (!this.imageManager.isLoaded())
476
+ return false;
477
+
478
+ return true;
479
+ }
480
+
481
+ /**
482
+ * @hidden
483
+ * take an array of string IDs, and based on this._layers, generate an array of LayerSpecification
484
+ * @param ids - an array of string IDs, for which serialized layers will be generated. If omitted, all serialized layers will be returned
485
+ * @param returnClose - if true, return a clone of the layer object
486
+ * @returns generated result
487
+ */
488
+ private _serializeByIds(ids: Array<string>, returnClone: boolean = false): Array<LayerSpecification> {
489
+
490
+ const serializedLayersDictionary = this._serializedAllLayers();
491
+ if (!ids || ids.length === 0) {
492
+ return returnClone ? Object.values(clone(serializedLayersDictionary)) : Object.values(serializedLayersDictionary);
493
+ }
494
+
495
+ const serializedLayers = [];
496
+ for (const id of ids) {
497
+ // this check will skip all custom layers
498
+ if (serializedLayersDictionary[id]) {
499
+ const toPush = returnClone ? clone(serializedLayersDictionary[id]) : serializedLayersDictionary[id];
500
+ serializedLayers.push(toPush);
501
+ }
502
+ }
503
+
504
+ return serializedLayers;
505
+ }
506
+
507
+ /**
508
+ * @hidden
509
+ * Lazy initialization of this._serializedLayers dictionary and return it
510
+ * @returns this._serializedLayers dictionary
511
+ */
512
+ private _serializedAllLayers(): {[_: string]: LayerSpecification} {
513
+ let serializedLayers = this._serializedLayers;
514
+ if (serializedLayers) {
515
+ return serializedLayers;
516
+ }
517
+
518
+ serializedLayers = this._serializedLayers = {};
519
+ const allLayerIds: string [] = Object.keys(this._layers);
520
+ for (const layerId of allLayerIds) {
521
+ const layer = this._layers[layerId];
522
+ if (layer.type !== 'custom') {
523
+ serializedLayers[layerId] = layer.serialize();
524
+ }
525
+ }
526
+
527
+ return serializedLayers;
528
+ }
529
+
530
+ hasTransitions() {
531
+ if (this.light && this.light.hasTransition()) {
532
+ return true;
533
+ }
534
+
535
+ if (this.sky && this.sky.hasTransition()) {
536
+ return true;
537
+ }
538
+
539
+ for (const id in this.sourceCaches) {
540
+ if (this.sourceCaches[id].hasTransition()) {
541
+ return true;
542
+ }
543
+ }
544
+
545
+ for (const id in this._layers) {
546
+ if (this._layers[id].hasTransition()) {
547
+ return true;
548
+ }
549
+ }
550
+
551
+ return false;
552
+ }
553
+
554
+ _checkLoaded() {
555
+ if (!this._loaded) {
556
+ throw new Error('Style is not done loading.');
557
+ }
558
+ }
559
+
560
+ /**
561
+ * @internal
562
+ * Apply queued style updates in a batch and recalculate zoom-dependent paint properties.
563
+ */
564
+ update(parameters: EvaluationParameters) {
565
+ if (!this._loaded) {
566
+ return;
567
+ }
568
+
569
+ const changed = this._changed;
570
+ if (changed) {
571
+ const updatedIds = Object.keys(this._updatedLayers);
572
+ const removedIds = Object.keys(this._removedLayers);
573
+
574
+ if (updatedIds.length || removedIds.length) {
575
+ this._updateWorkerLayers(updatedIds, removedIds);
576
+ }
577
+ for (const id in this._updatedSources) {
578
+ const action = this._updatedSources[id];
579
+
580
+ if (action === 'reload') {
581
+ this._reloadSource(id);
582
+ } else if (action === 'clear') {
583
+ this._clearSource(id);
584
+ } else {
585
+ throw new Error(`Invalid action ${action}`);
586
+ }
587
+ }
588
+
589
+ this._updateTilesForChangedImages();
590
+ this._updateTilesForChangedGlyphs();
591
+
592
+ for (const id in this._updatedPaintProps) {
593
+ this._layers[id].updateTransitions(parameters);
594
+ }
595
+
596
+ this.light.updateTransitions(parameters);
597
+ this.sky.updateTransitions(parameters);
598
+
599
+ this._resetUpdates();
600
+ }
601
+
602
+ const sourcesUsedBefore = {};
603
+
604
+ // save 'used' status to sourcesUsedBefore object and reset all sourceCaches 'used' field to false
605
+ for (const sourceCacheId in this.sourceCaches) {
606
+ const sourceCache = this.sourceCaches[sourceCacheId];
607
+
608
+ // sourceCache.used could be undefined, and sourcesUsedBefore[sourceCacheId] is also 'undefined'
609
+ sourcesUsedBefore[sourceCacheId] = sourceCache.used;
610
+ sourceCache.used = false;
611
+ }
612
+
613
+ // loop all layers and find layers that are not hidden at parameters.zoom
614
+ // and set used to true in sourceCaches dictionary for the sources of these layers
615
+ for (const layerId of this._order) {
616
+ const layer = this._layers[layerId];
617
+
618
+ layer.recalculate(parameters, this._availableImages);
619
+ if (!layer.isHidden(parameters.zoom) && layer.source) {
620
+ this.sourceCaches[layer.source].used = true;
621
+ }
622
+ }
623
+
624
+ // cross check sourcesUsedBefore against updated this.sourceCaches dictionary
625
+ // if "used" field is different fire visibility event
626
+ for (const sourcesUsedBeforeId in sourcesUsedBefore) {
627
+ const sourceCache = this.sourceCaches[sourcesUsedBeforeId];
628
+
629
+ // (undefine !== false) will evaluate to true and fire an useless visibility event
630
+ // need force "falsy" values to boolean to avoid the case above
631
+ if (!!sourcesUsedBefore[sourcesUsedBeforeId] !== !!sourceCache.used) {
632
+ sourceCache.fire(new Event('data',
633
+ {
634
+ sourceDataType: 'visibility',
635
+ dataType: 'source',
636
+ sourceId: sourcesUsedBeforeId
637
+ }));
638
+ }
639
+ }
640
+
641
+ this.light.recalculate(parameters);
642
+ this.sky.recalculate(parameters);
643
+ this.z = parameters.zoom;
644
+
645
+ if (changed) {
646
+ this.fire(new Event('data', {dataType: 'style'}));
647
+ }
648
+ }
649
+
650
+ /*
651
+ * Apply any queued image changes.
652
+ */
653
+ _updateTilesForChangedImages() {
654
+ const changedImages = Object.keys(this._changedImages);
655
+ if (changedImages.length) {
656
+ for (const name in this.sourceCaches) {
657
+ this.sourceCaches[name].reloadTilesForDependencies(['icons', 'patterns'], changedImages);
658
+ }
659
+ this._changedImages = {};
660
+ }
661
+ }
662
+
663
+ _updateTilesForChangedGlyphs() {
664
+ if (this._glyphsDidChange) {
665
+ for (const name in this.sourceCaches) {
666
+ this.sourceCaches[name].reloadTilesForDependencies(['glyphs'], ['']);
667
+ }
668
+ this._glyphsDidChange = false;
669
+ }
670
+ }
671
+
672
+ _updateWorkerLayers(updatedIds: Array<string>, removedIds: Array<string>) {
673
+ this.dispatcher.broadcast(MessageType.updateLayers, {
674
+ layers: this._serializeByIds(updatedIds, false),
675
+ removedIds
676
+ });
677
+ }
678
+
679
+ _resetUpdates() {
680
+ this._changed = false;
681
+
682
+ this._updatedLayers = {};
683
+ this._removedLayers = {};
684
+
685
+ this._updatedSources = {};
686
+ this._updatedPaintProps = {};
687
+
688
+ this._changedImages = {};
689
+ this._glyphsDidChange = false;
690
+ }
691
+
692
+ /**
693
+ * Update this style's state to match the given style JSON, performing only
694
+ * the necessary mutations.
695
+ *
696
+ * May throw an Error ('Unimplemented: METHOD') if the mapbox-gl-style-spec
697
+ * diff algorithm produces an operation that is not supported.
698
+ *
699
+ * @returns true if any changes were made; false otherwise
700
+ */
701
+ setState(nextState: StyleSpecification, options: StyleSwapOptions & StyleSetterOptions = {}) {
702
+ this._checkLoaded();
703
+
704
+ const serializedStyle = this.serialize();
705
+ nextState = options.transformStyle ? options.transformStyle(serializedStyle, nextState) : nextState;
706
+ const validate = options.validate ?? true;
707
+ if (validate && emitValidationErrors(this, validateStyle(nextState))) return false;
708
+
709
+ nextState = clone(nextState);
710
+ nextState.layers = deref(nextState.layers);
711
+
712
+ const changes = diffStyles(serializedStyle, nextState);
713
+ const operations = this._getOperationsToPerform(changes);
714
+
715
+ if (operations.unimplemented.length > 0) {
716
+ throw new Error(`Unimplemented: ${operations.unimplemented.join(', ')}.`);
717
+ }
718
+
719
+ if (operations.operations.length === 0) {
720
+ return false;
721
+ }
722
+
723
+ for (const styleChangeOperation of operations.operations) {
724
+ styleChangeOperation();
725
+ }
726
+
727
+ this.stylesheet = nextState;
728
+
729
+ // reset serialization field, to be populated only when needed
730
+ this._serializedLayers = null;
731
+
732
+ return true;
733
+ }
734
+
735
+ _getOperationsToPerform(diff: DiffCommand<DiffOperations>[]) {
736
+ const operations: Function[] = [];
737
+ const unimplemented: string[] = [];
738
+ for (const op of diff) {
739
+ switch (op.command) {
740
+ case 'setCenter':
741
+ case 'setZoom':
742
+ case 'setBearing':
743
+ case 'setPitch':
744
+ continue;
745
+ case 'addLayer':
746
+ operations.push(() => this.addLayer.apply(this, op.args));
747
+ break;
748
+ case 'removeLayer':
749
+ operations.push(() => this.removeLayer.apply(this, op.args));
750
+ break;
751
+ case 'setPaintProperty':
752
+ operations.push(() => this.setPaintProperty.apply(this, op.args));
753
+ break;
754
+ case 'setLayoutProperty':
755
+ operations.push(() => this.setLayoutProperty.apply(this, op.args));
756
+ break;
757
+ case 'setFilter':
758
+ operations.push(() => this.setFilter.apply(this, op.args));
759
+ break;
760
+ case 'addSource':
761
+ operations.push(() => this.addSource.apply(this, op.args));
762
+ break;
763
+ case 'removeSource':
764
+ operations.push(() => this.removeSource.apply(this, op.args));
765
+ break;
766
+ case 'setLayerZoomRange':
767
+ operations.push(() => this.setLayerZoomRange.apply(this, op.args));
768
+ break;
769
+ case 'setLight':
770
+ operations.push(() => this.setLight.apply(this, op.args));
771
+ break;
772
+ case 'setGeoJSONSourceData':
773
+ operations.push(() => this.setGeoJSONSourceData.apply(this, op.args));
774
+ break;
775
+ case 'setGlyphs':
776
+ operations.push(() => this.setGlyphs.apply(this, op.args));
777
+ break;
778
+ case 'setSprite':
779
+ operations.push(() => this.setSprite.apply(this, op.args));
780
+ break;
781
+ case 'setSky':
782
+ operations.push(() => this.setSky.apply(this, op.args));
783
+ break;
784
+ case 'setTerrain':
785
+ operations.push(() => this.map.setTerrain.apply(this, op.args));
786
+ break;
787
+ case 'setTransition':
788
+ operations.push(() => {});
789
+ break;
790
+ default:
791
+ unimplemented.push(op.command);
792
+ break;
793
+ }
794
+ }
795
+ return {
796
+ operations,
797
+ unimplemented
798
+ };
799
+ }
800
+
801
+ addImage(id: string, image: StyleImage) {
802
+ if (this.getImage(id)) {
803
+ return this.fire(new ErrorEvent(new Error(`An image named "${id}" already exists.`)));
804
+ }
805
+ this.imageManager.addImage(id, image);
806
+ this._afterImageUpdated(id);
807
+ }
808
+
809
+ updateImage(id: string, image: StyleImage) {
810
+ this.imageManager.updateImage(id, image);
811
+ }
812
+
813
+ getImage(id: string): StyleImage {
814
+ return this.imageManager.getImage(id);
815
+ }
816
+
817
+ removeImage(id: string) {
818
+ if (!this.getImage(id)) {
819
+ return this.fire(new ErrorEvent(new Error(`An image named "${id}" does not exist.`)));
820
+ }
821
+ this.imageManager.removeImage(id);
822
+ this._afterImageUpdated(id);
823
+ }
824
+
825
+ _afterImageUpdated(id: string) {
826
+ this._availableImages = this.imageManager.listImages();
827
+ this._changedImages[id] = true;
828
+ this._changed = true;
829
+ this.dispatcher.broadcast(MessageType.setImages, this._availableImages);
830
+ this.fire(new Event('data', {dataType: 'style'}));
831
+ }
832
+
833
+ listImages() {
834
+ this._checkLoaded();
835
+
836
+ return this.imageManager.listImages();
837
+ }
838
+
839
+ addSource(id: string, source: SourceSpecification | CanvasSourceSpecification, options: StyleSetterOptions = {}) {
840
+ this._checkLoaded();
841
+
842
+ if (this.sourceCaches[id] !== undefined) {
843
+ throw new Error(`Source "${id}" already exists.`);
844
+ }
845
+
846
+ if (!source.type) {
847
+ throw new Error(`The type property must be defined, but only the following properties were given: ${Object.keys(source).join(', ')}.`);
848
+ }
849
+
850
+ const builtIns = ['vector', 'raster', 'geojson', 'video', 'image'];
851
+ const shouldValidate = builtIns.indexOf(source.type) >= 0;
852
+ if (shouldValidate && this._validate(validateStyle.source, `sources.${id}`, source, null, options)) return;
853
+ if (this.map && this.map._collectResourceTiming) (source as any).collectResourceTiming = true;
854
+ const sourceCache = this.sourceCaches[id] = new SourceCache(id, source, this.dispatcher);
855
+ sourceCache.style = this;
856
+ sourceCache.setEventedParent(this, () => ({
857
+ isSourceLoaded: sourceCache.loaded(),
858
+ source: sourceCache.serialize(),
859
+ sourceId: id
860
+ }));
861
+
862
+ sourceCache.onAdd(this.map);
863
+ this._changed = true;
864
+ }
865
+
866
+ /**
867
+ * Remove a source from this stylesheet, given its id.
868
+ * @param id - id of the source to remove
869
+ * @throws if no source is found with the given ID
870
+ */
871
+ removeSource(id: string): this {
872
+ this._checkLoaded();
873
+
874
+ if (this.sourceCaches[id] === undefined) {
875
+ throw new Error('There is no source with this ID');
876
+ }
877
+ for (const layerId in this._layers) {
878
+ if (this._layers[layerId].source === id) {
879
+ return this.fire(new ErrorEvent(new Error(`Source "${id}" cannot be removed while layer "${layerId}" is using it.`)));
880
+ }
881
+ }
882
+
883
+ const sourceCache = this.sourceCaches[id];
884
+ delete this.sourceCaches[id];
885
+ delete this._updatedSources[id];
886
+ sourceCache.fire(new Event('data', {sourceDataType: 'metadata', dataType: 'source', sourceId: id}));
887
+ sourceCache.setEventedParent(null);
888
+ sourceCache.onRemove(this.map);
889
+ this._changed = true;
890
+ }
891
+
892
+ /**
893
+ * Set the data of a GeoJSON source, given its id.
894
+ * @param id - id of the source
895
+ * @param data - GeoJSON source
896
+ */
897
+ setGeoJSONSourceData(id: string, data: GeoJSON.GeoJSON | string) {
898
+ this._checkLoaded();
899
+
900
+ if (this.sourceCaches[id] === undefined) throw new Error(`There is no source with this ID=${id}`);
901
+ const geojsonSource: GeoJSONSource = (this.sourceCaches[id].getSource() as any);
902
+ if (geojsonSource.type !== 'geojson') throw new Error(`geojsonSource.type is ${geojsonSource.type}, which is !== 'geojson`);
903
+
904
+ geojsonSource.setData(data);
905
+ this._changed = true;
906
+ }
907
+
908
+ /**
909
+ * Get a source by ID.
910
+ * @param id - ID of the desired source
911
+ * @returns source
912
+ */
913
+ getSource(id: string): Source | undefined {
914
+ return this.sourceCaches[id] && this.sourceCaches[id].getSource();
915
+ }
916
+
917
+ /**
918
+ * Add a layer to the map style. The layer will be inserted before the layer with
919
+ * ID `before`, or appended if `before` is omitted.
920
+ * @param layerObject - The style layer to add.
921
+ * @param before - ID of an existing layer to insert before
922
+ * @param options - Style setter options.
923
+ */
924
+ addLayer(layerObject: AddLayerObject, before?: string, options: StyleSetterOptions = {}): this {
925
+ this._checkLoaded();
926
+
927
+ const id = layerObject.id;
928
+
929
+ if (this.getLayer(id)) {
930
+ this.fire(new ErrorEvent(new Error(`Layer "${id}" already exists on this map.`)));
931
+ return;
932
+ }
933
+
934
+ let layer: ReturnType<typeof createStyleLayer>;
935
+ if (layerObject.type === 'custom') {
936
+
937
+ if (emitValidationErrors(this, validateCustomStyleLayer(layerObject))) return;
938
+
939
+ layer = createStyleLayer(layerObject);
940
+
941
+ } else {
942
+ if ('source' in layerObject && typeof layerObject.source === 'object') {
943
+ this.addSource(id, layerObject.source);
944
+ layerObject = clone(layerObject);
945
+ layerObject = extend(layerObject, {source: id});
946
+ }
947
+
948
+ // this layer is not in the style.layers array, so we pass an impossible array index
949
+ if (this._validate(validateStyle.layer,
950
+ `layers.${id}`, layerObject, {arrayIndex: -1}, options)) return;
951
+
952
+ layer = createStyleLayer(layerObject as LayerSpecification | CustomLayerInterface);
953
+ this._validateLayer(layer);
954
+
955
+ layer.setEventedParent(this, {layer: {id}});
956
+ }
957
+
958
+ const index = before ? this._order.indexOf(before) : this._order.length;
959
+ if (before && index === -1) {
960
+ this.fire(new ErrorEvent(new Error(`Cannot add layer "${id}" before non-existing layer "${before}".`)));
961
+ return;
962
+ }
963
+
964
+ this._order.splice(index, 0, id);
965
+ this._layerOrderChanged = true;
966
+
967
+ this._layers[id] = layer;
968
+
969
+ if (this._removedLayers[id] && layer.source && layer.type !== 'custom') {
970
+ // If, in the current batch, we have already removed this layer
971
+ // and we are now re-adding it with a different `type`, then we
972
+ // need to clear (rather than just reload) the underlying source's
973
+ // tiles. Otherwise, tiles marked 'reloading' will have buckets /
974
+ // buffers that are set up for the _previous_ version of this
975
+ // layer, causing, e.g.:
976
+ // https://github.com/mapbox/mapbox-gl-js/issues/3633
977
+ const removed = this._removedLayers[id];
978
+ delete this._removedLayers[id];
979
+ if (removed.type !== layer.type) {
980
+ this._updatedSources[layer.source] = 'clear';
981
+ } else {
982
+ this._updatedSources[layer.source] = 'reload';
983
+ this.sourceCaches[layer.source].pause();
984
+ }
985
+ }
986
+ this._updateLayer(layer);
987
+
988
+ if (layer.onAdd) {
989
+ layer.onAdd(this.map);
990
+ }
991
+ }
992
+
993
+ /**
994
+ * Moves a layer to a different z-position. The layer will be inserted before the layer with
995
+ * ID `before`, or appended if `before` is omitted.
996
+ * @param id - ID of the layer to move
997
+ * @param before - ID of an existing layer to insert before
998
+ */
999
+ moveLayer(id: string, before?: string) {
1000
+ this._checkLoaded();
1001
+ this._changed = true;
1002
+
1003
+ const layer = this._layers[id];
1004
+ if (!layer) {
1005
+ this.fire(new ErrorEvent(new Error(`The layer '${id}' does not exist in the map's style and cannot be moved.`)));
1006
+ return;
1007
+ }
1008
+
1009
+ if (id === before) {
1010
+ return;
1011
+ }
1012
+
1013
+ const index = this._order.indexOf(id);
1014
+ this._order.splice(index, 1);
1015
+
1016
+ const newIndex = before ? this._order.indexOf(before) : this._order.length;
1017
+ if (before && newIndex === -1) {
1018
+ this.fire(new ErrorEvent(new Error(`Cannot move layer "${id}" before non-existing layer "${before}".`)));
1019
+ return;
1020
+ }
1021
+ this._order.splice(newIndex, 0, id);
1022
+
1023
+ this._layerOrderChanged = true;
1024
+ }
1025
+
1026
+ /**
1027
+ * Remove the layer with the given id from the style.
1028
+ * A {@link ErrorEvent} event will be fired if no such layer exists.
1029
+ *
1030
+ * @param id - id of the layer to remove
1031
+ */
1032
+ removeLayer(id: string) {
1033
+ this._checkLoaded();
1034
+
1035
+ const layer = this._layers[id];
1036
+ if (!layer) {
1037
+ this.fire(new ErrorEvent(new Error(`Cannot remove non-existing layer "${id}".`)));
1038
+ return;
1039
+ }
1040
+
1041
+ layer.setEventedParent(null);
1042
+
1043
+ const index = this._order.indexOf(id);
1044
+ this._order.splice(index, 1);
1045
+
1046
+ this._layerOrderChanged = true;
1047
+ this._changed = true;
1048
+ this._removedLayers[id] = layer;
1049
+ delete this._layers[id];
1050
+
1051
+ if (this._serializedLayers) {
1052
+ delete this._serializedLayers[id];
1053
+ }
1054
+ delete this._updatedLayers[id];
1055
+ delete this._updatedPaintProps[id];
1056
+
1057
+ if (layer.onRemove) {
1058
+ layer.onRemove(this.map);
1059
+ }
1060
+ }
1061
+
1062
+ /**
1063
+ * Return the style layer object with the given `id`.
1064
+ *
1065
+ * @param id - id of the desired layer
1066
+ * @returns a layer, if one with the given `id` exists
1067
+ */
1068
+ getLayer(id: string): StyleLayer | undefined {
1069
+ return this._layers[id];
1070
+ }
1071
+
1072
+ /**
1073
+ * Return the ids of all layers currently in the style, including custom layers, in order.
1074
+ *
1075
+ * @returns ids of layers, in order
1076
+ */
1077
+ getLayersOrder(): string[] {
1078
+ return [...this._order];
1079
+ }
1080
+
1081
+ /**
1082
+ * Checks if a specific layer is present within the style.
1083
+ *
1084
+ * @param id - the id of the desired layer
1085
+ * @returns a boolean specifying if the given layer is present
1086
+ */
1087
+ hasLayer(id: string): boolean {
1088
+ return id in this._layers;
1089
+ }
1090
+
1091
+ setLayerZoomRange(layerId: string, minzoom?: number | null, maxzoom?: number | null) {
1092
+ this._checkLoaded();
1093
+
1094
+ const layer = this.getLayer(layerId);
1095
+ if (!layer) {
1096
+ this.fire(new ErrorEvent(new Error(`Cannot set the zoom range of non-existing layer "${layerId}".`)));
1097
+ return;
1098
+ }
1099
+
1100
+ if (layer.minzoom === minzoom && layer.maxzoom === maxzoom) return;
1101
+
1102
+ if (minzoom != null) {
1103
+ layer.minzoom = minzoom;
1104
+ }
1105
+ if (maxzoom != null) {
1106
+ layer.maxzoom = maxzoom;
1107
+ }
1108
+ this._updateLayer(layer);
1109
+ }
1110
+
1111
+ setFilter(layerId: string, filter?: FilterSpecification | null, options: StyleSetterOptions = {}) {
1112
+ this._checkLoaded();
1113
+
1114
+ const layer = this.getLayer(layerId);
1115
+ if (!layer) {
1116
+ this.fire(new ErrorEvent(new Error(`Cannot filter non-existing layer "${layerId}".`)));
1117
+ return;
1118
+ }
1119
+
1120
+ if (deepEqual(layer.filter, filter)) {
1121
+ return;
1122
+ }
1123
+
1124
+ if (filter === null || filter === undefined) {
1125
+ layer.filter = undefined;
1126
+ this._updateLayer(layer);
1127
+ return;
1128
+ }
1129
+
1130
+ if (this._validate(validateStyle.filter, `layers.${layer.id}.filter`, filter, null, options)) {
1131
+ return;
1132
+ }
1133
+
1134
+ layer.filter = clone(filter);
1135
+ this._updateLayer(layer);
1136
+ }
1137
+
1138
+ /**
1139
+ * Get a layer's filter object
1140
+ * @param layer - the layer to inspect
1141
+ * @returns the layer's filter, if any
1142
+ */
1143
+ getFilter(layer: string): FilterSpecification | void {
1144
+ return clone(this.getLayer(layer).filter);
1145
+ }
1146
+
1147
+ setLayoutProperty(layerId: string, name: string, value: any, options: StyleSetterOptions = {}) {
1148
+ this._checkLoaded();
1149
+
1150
+ const layer = this.getLayer(layerId);
1151
+ if (!layer) {
1152
+ this.fire(new ErrorEvent(new Error(`Cannot style non-existing layer "${layerId}".`)));
1153
+ return;
1154
+ }
1155
+
1156
+ if (deepEqual(layer.getLayoutProperty(name), value)) return;
1157
+
1158
+ layer.setLayoutProperty(name, value, options);
1159
+ this._updateLayer(layer);
1160
+ }
1161
+
1162
+ /**
1163
+ * Get a layout property's value from a given layer
1164
+ * @param layerId - the layer to inspect
1165
+ * @param name - the name of the layout property
1166
+ * @returns the property value
1167
+ */
1168
+ getLayoutProperty(layerId: string, name: string) {
1169
+ const layer = this.getLayer(layerId);
1170
+ if (!layer) {
1171
+ this.fire(new ErrorEvent(new Error(`Cannot get style of non-existing layer "${layerId}".`)));
1172
+ return;
1173
+ }
1174
+
1175
+ return layer.getLayoutProperty(name);
1176
+ }
1177
+
1178
+ setPaintProperty(layerId: string, name: string, value: any, options: StyleSetterOptions = {}) {
1179
+ this._checkLoaded();
1180
+
1181
+ const layer = this.getLayer(layerId);
1182
+ if (!layer) {
1183
+ this.fire(new ErrorEvent(new Error(`Cannot style non-existing layer "${layerId}".`)));
1184
+ return;
1185
+ }
1186
+
1187
+ if (deepEqual(layer.getPaintProperty(name), value)) return;
1188
+
1189
+ const requiresRelayout = layer.setPaintProperty(name, value, options);
1190
+ if (requiresRelayout) {
1191
+ this._updateLayer(layer);
1192
+ }
1193
+
1194
+ this._changed = true;
1195
+ this._updatedPaintProps[layerId] = true;
1196
+ // reset serialization field, to be populated only when needed
1197
+ this._serializedLayers = null;
1198
+ }
1199
+
1200
+ getPaintProperty(layer: string, name: string) {
1201
+ return this.getLayer(layer).getPaintProperty(name);
1202
+ }
1203
+
1204
+ setFeatureState(target: FeatureIdentifier, state: any) {
1205
+ this._checkLoaded();
1206
+ const sourceId = target.source;
1207
+ const sourceLayer = target.sourceLayer;
1208
+ const sourceCache = this.sourceCaches[sourceId];
1209
+
1210
+ if (sourceCache === undefined) {
1211
+ this.fire(new ErrorEvent(new Error(`The source '${sourceId}' does not exist in the map's style.`)));
1212
+ return;
1213
+ }
1214
+ const sourceType = sourceCache.getSource().type;
1215
+ if (sourceType === 'geojson' && sourceLayer) {
1216
+ this.fire(new ErrorEvent(new Error('GeoJSON sources cannot have a sourceLayer parameter.')));
1217
+ return;
1218
+ }
1219
+ if (sourceType === 'vector' && !sourceLayer) {
1220
+ this.fire(new ErrorEvent(new Error('The sourceLayer parameter must be provided for vector source types.')));
1221
+ return;
1222
+ }
1223
+ if (target.id === undefined) {
1224
+ this.fire(new ErrorEvent(new Error('The feature id parameter must be provided.')));
1225
+ }
1226
+
1227
+ sourceCache.setFeatureState(sourceLayer, target.id, state);
1228
+ }
1229
+
1230
+ removeFeatureState(target: FeatureIdentifier, key?: string) {
1231
+ this._checkLoaded();
1232
+ const sourceId = target.source;
1233
+ const sourceCache = this.sourceCaches[sourceId];
1234
+
1235
+ if (sourceCache === undefined) {
1236
+ this.fire(new ErrorEvent(new Error(`The source '${sourceId}' does not exist in the map's style.`)));
1237
+ return;
1238
+ }
1239
+
1240
+ const sourceType = sourceCache.getSource().type;
1241
+ const sourceLayer = sourceType === 'vector' ? target.sourceLayer : undefined;
1242
+
1243
+ if (sourceType === 'vector' && !sourceLayer) {
1244
+ this.fire(new ErrorEvent(new Error('The sourceLayer parameter must be provided for vector source types.')));
1245
+ return;
1246
+ }
1247
+
1248
+ if (key && (typeof target.id !== 'string' && typeof target.id !== 'number')) {
1249
+ this.fire(new ErrorEvent(new Error('A feature id is required to remove its specific state property.')));
1250
+ return;
1251
+ }
1252
+
1253
+ sourceCache.removeFeatureState(sourceLayer, target.id, key);
1254
+ }
1255
+
1256
+ getFeatureState(target: FeatureIdentifier) {
1257
+ this._checkLoaded();
1258
+ const sourceId = target.source;
1259
+ const sourceLayer = target.sourceLayer;
1260
+ const sourceCache = this.sourceCaches[sourceId];
1261
+
1262
+ if (sourceCache === undefined) {
1263
+ this.fire(new ErrorEvent(new Error(`The source '${sourceId}' does not exist in the map's style.`)));
1264
+ return;
1265
+ }
1266
+ const sourceType = sourceCache.getSource().type;
1267
+ if (sourceType === 'vector' && !sourceLayer) {
1268
+ this.fire(new ErrorEvent(new Error('The sourceLayer parameter must be provided for vector source types.')));
1269
+ return;
1270
+ }
1271
+ if (target.id === undefined) {
1272
+ this.fire(new ErrorEvent(new Error('The feature id parameter must be provided.')));
1273
+ }
1274
+
1275
+ return sourceCache.getFeatureState(sourceLayer, target.id);
1276
+ }
1277
+
1278
+ getTransition() {
1279
+ return extend({duration: 300, delay: 0}, this.stylesheet && this.stylesheet.transition);
1280
+ }
1281
+
1282
+ serialize(): StyleSpecification | undefined {
1283
+ // We return undefined before we're loaded, following the pattern of Map.getStyle() before
1284
+ // the Style object is initialized.
1285
+ // Internally, Style._validate() calls Style.serialize() but callers are responsible for
1286
+ // calling Style._checkLoaded() first if their validation requires the style to be loaded.
1287
+ if (!this._loaded) return;
1288
+
1289
+ const sources = mapObject(this.sourceCaches, (source) => source.serialize());
1290
+ const layers = this._serializeByIds(this._order, true);
1291
+ const terrain = this.map.getTerrain() || undefined;
1292
+ const myStyleSheet = this.stylesheet;
1293
+
1294
+ return filterObject({
1295
+ version: myStyleSheet.version,
1296
+ name: myStyleSheet.name,
1297
+ metadata: myStyleSheet.metadata,
1298
+ light: myStyleSheet.light,
1299
+ sky: myStyleSheet.sky,
1300
+ center: myStyleSheet.center,
1301
+ zoom: myStyleSheet.zoom,
1302
+ bearing: myStyleSheet.bearing,
1303
+ pitch: myStyleSheet.pitch,
1304
+ sprite: myStyleSheet.sprite,
1305
+ glyphs: myStyleSheet.glyphs,
1306
+ transition: myStyleSheet.transition,
1307
+ sources,
1308
+ layers,
1309
+ terrain
1310
+ },
1311
+ (value) => { return value !== undefined; });
1312
+ }
1313
+
1314
+ _updateLayer(layer: StyleLayer) {
1315
+ this._updatedLayers[layer.id] = true;
1316
+ if (layer.source && !this._updatedSources[layer.source] &&
1317
+ //Skip for raster layers (https://github.com/mapbox/mapbox-gl-js/issues/7865)
1318
+ this.sourceCaches[layer.source].getSource().type !== 'raster') {
1319
+ this._updatedSources[layer.source] = 'reload';
1320
+ this.sourceCaches[layer.source].pause();
1321
+ }
1322
+
1323
+ // upon updating, serialized layer dictionary should be reset.
1324
+ // When needed, it will be populated with the correct copy again.
1325
+ this._serializedLayers = null;
1326
+ this._changed = true;
1327
+ }
1328
+
1329
+ _flattenAndSortRenderedFeatures(sourceResults: Array<{ [key: string]: Array<{featureIndex: number; feature: MapGeoJSONFeature}> }>) {
1330
+ // Feature order is complicated.
1331
+ // The order between features in two 2D layers is always determined by layer order.
1332
+ // The order between features in two 3D layers is always determined by depth.
1333
+ // The order between a feature in a 2D layer and a 3D layer is tricky:
1334
+ // Most often layer order determines the feature order in this case. If
1335
+ // a line layer is above a extrusion layer the line feature will be rendered
1336
+ // above the extrusion. If the line layer is below the extrusion layer,
1337
+ // it will be rendered below it.
1338
+ //
1339
+ // There is a weird case though.
1340
+ // You have layers in this order: extrusion_layer_a, line_layer, extrusion_layer_b
1341
+ // Each layer has a feature that overlaps the other features.
1342
+ // The feature in extrusion_layer_a is closer than the feature in extrusion_layer_b so it is rendered above.
1343
+ // The feature in line_layer is rendered above extrusion_layer_a.
1344
+ // This means that that the line_layer feature is above the extrusion_layer_b feature despite
1345
+ // it being in an earlier layer.
1346
+
1347
+ const isLayer3D = layerId => this._layers[layerId].type === 'fill-extrusion';
1348
+
1349
+ const layerIndex = {};
1350
+ const features3D = [];
1351
+ for (let l = this._order.length - 1; l >= 0; l--) {
1352
+ const layerId = this._order[l];
1353
+ if (isLayer3D(layerId)) {
1354
+ layerIndex[layerId] = l;
1355
+ for (const sourceResult of sourceResults) {
1356
+ const layerFeatures = sourceResult[layerId];
1357
+ if (layerFeatures) {
1358
+ for (const featureWrapper of layerFeatures) {
1359
+ features3D.push(featureWrapper);
1360
+ }
1361
+ }
1362
+ }
1363
+ }
1364
+ }
1365
+
1366
+ features3D.sort((a, b) => {
1367
+ return b.intersectionZ - a.intersectionZ;
1368
+ });
1369
+
1370
+ const features = [];
1371
+ for (let l = this._order.length - 1; l >= 0; l--) {
1372
+ const layerId = this._order[l];
1373
+
1374
+ if (isLayer3D(layerId)) {
1375
+ // add all 3D features that are in or above the current layer
1376
+ for (let i = features3D.length - 1; i >= 0; i--) {
1377
+ const topmost3D = features3D[i].feature;
1378
+ if (layerIndex[topmost3D.layer.id] < l) break;
1379
+ features.push(topmost3D);
1380
+ features3D.pop();
1381
+ }
1382
+ } else {
1383
+ for (const sourceResult of sourceResults) {
1384
+ const layerFeatures = sourceResult[layerId];
1385
+ if (layerFeatures) {
1386
+ for (const featureWrapper of layerFeatures) {
1387
+ features.push(featureWrapper.feature);
1388
+ }
1389
+ }
1390
+ }
1391
+ }
1392
+ }
1393
+
1394
+ return features;
1395
+ }
1396
+
1397
+ queryRenderedFeatures(queryGeometry: any, params: QueryRenderedFeaturesOptions, transform: Transform) {
1398
+ if (params && params.filter) {
1399
+ this._validate(validateStyle.filter, 'queryRenderedFeatures.filter', params.filter, null, params);
1400
+ }
1401
+
1402
+ const includedSources = {};
1403
+ if (params && params.layers) {
1404
+ if (!Array.isArray(params.layers)) {
1405
+ this.fire(new ErrorEvent(new Error('parameters.layers must be an Array.')));
1406
+ return [];
1407
+ }
1408
+ for (const layerId of params.layers) {
1409
+ const layer = this._layers[layerId];
1410
+ if (!layer) {
1411
+ // this layer is not in the style.layers array
1412
+ this.fire(new ErrorEvent(new Error(`The layer '${layerId}' does not exist in the map's style and cannot be queried for features.`)));
1413
+ return [];
1414
+ }
1415
+ includedSources[layer.source] = true;
1416
+ }
1417
+ }
1418
+
1419
+ const sourceResults = [];
1420
+
1421
+ params.availableImages = this._availableImages;
1422
+
1423
+ // LayerSpecification is serialized StyleLayer, and this casting is safe.
1424
+ const serializedLayers = this._serializedAllLayers() as {[_: string]: StyleLayer};
1425
+
1426
+ for (const id in this.sourceCaches) {
1427
+ if (params.layers && !includedSources[id]) continue;
1428
+ sourceResults.push(
1429
+ queryRenderedFeatures(
1430
+ this.sourceCaches[id],
1431
+ this._layers,
1432
+ serializedLayers,
1433
+ queryGeometry,
1434
+ params,
1435
+ transform)
1436
+ );
1437
+ }
1438
+
1439
+ if (this.placement) {
1440
+ // If a placement has run, query against its CollisionIndex
1441
+ // for symbol results, and treat it as an extra source to merge
1442
+ sourceResults.push(
1443
+ queryRenderedSymbols(
1444
+ this._layers,
1445
+ serializedLayers,
1446
+ this.sourceCaches,
1447
+ queryGeometry,
1448
+ params,
1449
+ this.placement.collisionIndex,
1450
+ this.placement.retainedQueryData)
1451
+ );
1452
+ }
1453
+
1454
+ return this._flattenAndSortRenderedFeatures(sourceResults);
1455
+ }
1456
+
1457
+ querySourceFeatures(
1458
+ sourceID: string,
1459
+ params?: QuerySourceFeatureOptions
1460
+ ) {
1461
+ if (params && params.filter) {
1462
+ this._validate(validateStyle.filter, 'querySourceFeatures.filter', params.filter, null, params);
1463
+ }
1464
+ const sourceCache = this.sourceCaches[sourceID];
1465
+ return sourceCache ? querySourceFeatures(sourceCache, params) : [];
1466
+ }
1467
+
1468
+ getLight() {
1469
+ return this.light.getLight();
1470
+ }
1471
+
1472
+ setLight(lightOptions: LightSpecification, options: StyleSetterOptions = {}) {
1473
+ this._checkLoaded();
1474
+
1475
+ const light = this.light.getLight();
1476
+ let _update = false;
1477
+ for (const key in lightOptions) {
1478
+ if (!deepEqual(lightOptions[key], light[key])) {
1479
+ _update = true;
1480
+ break;
1481
+ }
1482
+ }
1483
+ if (!_update) return;
1484
+
1485
+ const parameters = {
1486
+ now: browser.now(),
1487
+ transition: extend({
1488
+ duration: 300,
1489
+ delay: 0
1490
+ }, this.stylesheet.transition)
1491
+ };
1492
+
1493
+ this.light.setLight(lightOptions, options);
1494
+ this.light.updateTransitions(parameters);
1495
+ }
1496
+
1497
+ getSky(): SkySpecification {
1498
+ return this.stylesheet?.sky;
1499
+ }
1500
+
1501
+ setSky(skyOptions?: SkySpecification, options: StyleSetterOptions = {}) {
1502
+ const sky = this.getSky();
1503
+ let update = false;
1504
+ if (!skyOptions && !sky) return;
1505
+
1506
+ if (skyOptions && !sky) {
1507
+ update = true;
1508
+ } else if (!skyOptions && sky) {
1509
+ update = true;
1510
+ } else {
1511
+ for (const key in skyOptions) {
1512
+ if (!deepEqual(skyOptions[key], sky[key])) {
1513
+ update = true;
1514
+ break;
1515
+ }
1516
+ }
1517
+ }
1518
+ if (!update) return;
1519
+
1520
+ const parameters = {
1521
+ now: browser.now(),
1522
+ transition: extend({
1523
+ duration: 300,
1524
+ delay: 0
1525
+ }, this.stylesheet.transition)
1526
+ };
1527
+
1528
+ this.stylesheet.sky = skyOptions;
1529
+ this.sky.setSky(skyOptions, options);
1530
+ this.sky.updateTransitions(parameters);
1531
+ }
1532
+
1533
+ _validate(validate: Validator, key: string, value: any, props: any, options: {
1534
+ validate?: boolean;
1535
+ } = {}) {
1536
+ if (options && options.validate === false) {
1537
+ return false;
1538
+ }
1539
+ return emitValidationErrors(this, validate.call(validateStyle, extend({
1540
+ key,
1541
+ style: this.serialize(),
1542
+ value,
1543
+ styleSpec
1544
+ }, props)));
1545
+ }
1546
+
1547
+ _remove(mapRemoved: boolean = true) {
1548
+ if (this._frameRequest) {
1549
+ this._frameRequest.abort();
1550
+ this._frameRequest = null;
1551
+ }
1552
+ if (this._loadStyleRequest) {
1553
+ this._loadStyleRequest.abort();
1554
+ this._loadStyleRequest = null;
1555
+ }
1556
+ if (this._spriteRequest) {
1557
+ this._spriteRequest.abort();
1558
+ this._spriteRequest = null;
1559
+ }
1560
+ rtlMainThreadPluginFactory().off(RTLPluginLoadedEventName, this._rtlPluginLoaded);
1561
+ for (const layerId in this._layers) {
1562
+ const layer: StyleLayer = this._layers[layerId];
1563
+ layer.setEventedParent(null);
1564
+ }
1565
+ for (const id in this.sourceCaches) {
1566
+ const sourceCache = this.sourceCaches[id];
1567
+ sourceCache.setEventedParent(null);
1568
+ sourceCache.onRemove(this.map);
1569
+ }
1570
+ this.imageManager.setEventedParent(null);
1571
+ this.setEventedParent(null);
1572
+ if (mapRemoved) {
1573
+ this.dispatcher.broadcast(MessageType.removeMap, undefined);
1574
+ }
1575
+ this.dispatcher.remove(mapRemoved);
1576
+ }
1577
+
1578
+ _clearSource(id: string) {
1579
+ this.sourceCaches[id].clearTiles();
1580
+ }
1581
+
1582
+ _reloadSource(id: string) {
1583
+ this.sourceCaches[id].resume();
1584
+ this.sourceCaches[id].reload();
1585
+ }
1586
+
1587
+ _updateSources(transform: Transform) {
1588
+ for (const id in this.sourceCaches) {
1589
+ this.sourceCaches[id].update(transform, this.map.terrain);
1590
+ }
1591
+ }
1592
+
1593
+ _generateCollisionBoxes() {
1594
+ for (const id in this.sourceCaches) {
1595
+ this._reloadSource(id);
1596
+ }
1597
+ }
1598
+
1599
+ _updatePlacement(transform: Transform, showCollisionBoxes: boolean, fadeDuration: number, crossSourceCollisions: boolean, forceFullPlacement: boolean = false) {
1600
+ let symbolBucketsChanged = false;
1601
+ let placementCommitted = false;
1602
+
1603
+ const layerTiles = {};
1604
+
1605
+ for (const layerID of this._order) {
1606
+ const styleLayer = this._layers[layerID];
1607
+ if (styleLayer.type !== 'symbol') continue;
1608
+
1609
+ if (!layerTiles[styleLayer.source]) {
1610
+ const sourceCache = this.sourceCaches[styleLayer.source];
1611
+ layerTiles[styleLayer.source] = sourceCache.getRenderableIds(true)
1612
+ .map((id) => sourceCache.getTileByID(id))
1613
+ .sort((a, b) => (b.tileID.overscaledZ - a.tileID.overscaledZ) || (a.tileID.isLessThan(b.tileID) ? -1 : 1));
1614
+ }
1615
+
1616
+ const layerBucketsChanged = this.crossTileSymbolIndex.addLayer(styleLayer, layerTiles[styleLayer.source], transform.center.lng);
1617
+ symbolBucketsChanged = symbolBucketsChanged || layerBucketsChanged;
1618
+ }
1619
+ this.crossTileSymbolIndex.pruneUnusedLayers(this._order);
1620
+
1621
+ // Anything that changes our "in progress" layer and tile indices requires us
1622
+ // to start over. When we start over, we do a full placement instead of incremental
1623
+ // to prevent starvation.
1624
+ // We need to restart placement to keep layer indices in sync.
1625
+ // Also force full placement when fadeDuration === 0 to ensure that newly loaded
1626
+ // tiles will fully display symbols in their first frame
1627
+ forceFullPlacement = forceFullPlacement || this._layerOrderChanged || fadeDuration === 0;
1628
+
1629
+ if (forceFullPlacement || !this.pauseablePlacement || (this.pauseablePlacement.isDone() && !this.placement.stillRecent(browser.now(), transform.zoom))) {
1630
+ this.pauseablePlacement = new PauseablePlacement(transform, this.map.terrain, this._order, forceFullPlacement, showCollisionBoxes, fadeDuration, crossSourceCollisions, this.placement);
1631
+ this._layerOrderChanged = false;
1632
+ }
1633
+
1634
+ if (this.pauseablePlacement.isDone()) {
1635
+ // the last placement finished running, but the next one hasn’t
1636
+ // started yet because of the `stillRecent` check immediately
1637
+ // above, so mark it stale to ensure that we request another
1638
+ // render frame
1639
+ this.placement.setStale();
1640
+ } else {
1641
+ this.pauseablePlacement.continuePlacement(this._order, this._layers, layerTiles);
1642
+
1643
+ if (this.pauseablePlacement.isDone()) {
1644
+ this.placement = this.pauseablePlacement.commit(browser.now());
1645
+ placementCommitted = true;
1646
+ }
1647
+
1648
+ if (symbolBucketsChanged) {
1649
+ // since the placement gets split over multiple frames it is possible
1650
+ // these buckets were processed before they were changed and so the
1651
+ // placement is already stale while it is in progress
1652
+ this.pauseablePlacement.placement.setStale();
1653
+ }
1654
+ }
1655
+
1656
+ if (placementCommitted || symbolBucketsChanged) {
1657
+ for (const layerID of this._order) {
1658
+ const styleLayer = this._layers[layerID];
1659
+ if (styleLayer.type !== 'symbol') continue;
1660
+ this.placement.updateLayerOpacities(styleLayer, layerTiles[styleLayer.source]);
1661
+ }
1662
+ }
1663
+
1664
+ // needsRender is false when we have just finished a placement that didn't change the visibility of any symbols
1665
+ const needsRerender = !this.pauseablePlacement.isDone() || this.placement.hasTransitions(browser.now());
1666
+ return needsRerender;
1667
+ }
1668
+
1669
+ _releaseSymbolFadeTiles() {
1670
+ for (const id in this.sourceCaches) {
1671
+ this.sourceCaches[id].releaseSymbolFadeTiles();
1672
+ }
1673
+ }
1674
+
1675
+ // Callbacks from web workers
1676
+
1677
+ async getImages(mapId: string | number, params: GetImagesParameters): Promise<GetImagesResponse> {
1678
+ const images = await this.imageManager.getImages(params.icons);
1679
+
1680
+ // Apply queued image changes before setting the tile's dependencies so that the tile
1681
+ // is not reloaded unnecessarily. Without this forced update the reload could happen in cases
1682
+ // like this one:
1683
+ // - icons contains "my-image"
1684
+ // - imageManager.getImages(...) triggers `onstyleimagemissing`
1685
+ // - the user adds "my-image" within the callback
1686
+ // - addImage adds "my-image" to this._changedImages
1687
+ // - the next frame triggers a reload of this tile even though it already has the latest version
1688
+ this._updateTilesForChangedImages();
1689
+
1690
+ const sourceCache = this.sourceCaches[params.source];
1691
+ if (sourceCache) {
1692
+ sourceCache.setDependencies(params.tileID.key, params.type, params.icons);
1693
+ }
1694
+ return images;
1695
+ }
1696
+
1697
+ async getGlyphs(mapId: string | number, params: GetGlyphsParameters): Promise<GetGlyphsResponse> {
1698
+ const glypgs = await this.glyphManager.getGlyphs(params.stacks);
1699
+ const sourceCache = this.sourceCaches[params.source];
1700
+ if (sourceCache) {
1701
+ // we are not setting stacks as dependencies since for now
1702
+ // we just need to know which tiles have glyph dependencies
1703
+ sourceCache.setDependencies(params.tileID.key, params.type, ['']);
1704
+ }
1705
+ return glypgs;
1706
+ }
1707
+
1708
+ getGlyphsUrl() {
1709
+ return this.stylesheet.glyphs || null;
1710
+ }
1711
+
1712
+ setGlyphs(glyphsUrl: string | null, options: StyleSetterOptions = {}) {
1713
+ this._checkLoaded();
1714
+ if (glyphsUrl && this._validate(validateStyle.glyphs, 'glyphs', glyphsUrl, null, options)) {
1715
+ return;
1716
+ }
1717
+
1718
+ this._glyphsDidChange = true;
1719
+ this.stylesheet.glyphs = glyphsUrl;
1720
+ this.glyphManager.entries = {};
1721
+ this.glyphManager.setURL(glyphsUrl);
1722
+ }
1723
+
1724
+ /**
1725
+ * Add a sprite.
1726
+ *
1727
+ * @param id - The id of the desired sprite
1728
+ * @param url - The url to load the desired sprite from
1729
+ * @param options - The style setter options
1730
+ * @param completion - The completion handler
1731
+ */
1732
+ addSprite(id: string, url: string, options: StyleSetterOptions = {}, completion?: (err: Error) => void) {
1733
+ this._checkLoaded();
1734
+
1735
+ const spriteToAdd = [{id, url}];
1736
+ const updatedSprite = [
1737
+ ...coerceSpriteToArray(this.stylesheet.sprite),
1738
+ ...spriteToAdd
1739
+ ];
1740
+
1741
+ if (this._validate(validateStyle.sprite, 'sprite', updatedSprite, null, options)) return;
1742
+
1743
+ this.stylesheet.sprite = updatedSprite;
1744
+ this._loadSprite(spriteToAdd, true, completion);
1745
+ }
1746
+
1747
+ /**
1748
+ * Remove a sprite by its id. When the last sprite is removed, the whole `this.stylesheet.sprite` object becomes
1749
+ * `undefined`. This falsy `undefined` value later prevents attempts to load the sprite when it's absent.
1750
+ *
1751
+ * @param id - the id of the sprite to remove
1752
+ */
1753
+ removeSprite(id: string) {
1754
+ this._checkLoaded();
1755
+
1756
+ const internalSpriteRepresentation = coerceSpriteToArray(this.stylesheet.sprite);
1757
+
1758
+ if (!internalSpriteRepresentation.find(sprite => sprite.id === id)) {
1759
+ this.fire(new ErrorEvent(new Error(`Sprite "${id}" doesn't exists on this map.`)));
1760
+ return;
1761
+ }
1762
+
1763
+ if (this._spritesImagesIds[id]) {
1764
+ for (const imageId of this._spritesImagesIds[id]) {
1765
+ this.imageManager.removeImage(imageId);
1766
+ this._changedImages[imageId] = true;
1767
+ }
1768
+ }
1769
+
1770
+ internalSpriteRepresentation.splice(internalSpriteRepresentation.findIndex(sprite => sprite.id === id), 1);
1771
+ this.stylesheet.sprite = internalSpriteRepresentation.length > 0 ? internalSpriteRepresentation : undefined;
1772
+
1773
+ delete this._spritesImagesIds[id];
1774
+ this._availableImages = this.imageManager.listImages();
1775
+ this._changed = true;
1776
+ this.dispatcher.broadcast(MessageType.setImages, this._availableImages);
1777
+ this.fire(new Event('data', {dataType: 'style'}));
1778
+ }
1779
+
1780
+ /**
1781
+ * Get the current sprite value.
1782
+ *
1783
+ * @returns empty array when no sprite is set; id-url pairs otherwise
1784
+ */
1785
+ getSprite() {
1786
+ return coerceSpriteToArray(this.stylesheet.sprite);
1787
+ }
1788
+
1789
+ /**
1790
+ * Set a new value for the style's sprite.
1791
+ *
1792
+ * @param sprite - new sprite value
1793
+ * @param options - style setter options
1794
+ * @param completion - the completion handler
1795
+ */
1796
+ setSprite(sprite: SpriteSpecification, options: StyleSetterOptions = {}, completion?: (err: Error) => void) {
1797
+ this._checkLoaded();
1798
+
1799
+ if (sprite && this._validate(validateStyle.sprite, 'sprite', sprite, null, options)) {
1800
+ return;
1801
+ }
1802
+
1803
+ this.stylesheet.sprite = sprite;
1804
+
1805
+ if (sprite) {
1806
+ this._loadSprite(sprite, true, completion);
1807
+ } else {
1808
+ this._unloadSprite();
1809
+ if (completion) {
1810
+ completion(null);
1811
+ }
1812
+ }
1813
+ }
1814
+ }