@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.
- package/LICENSE.txt +116 -0
- package/README.md +174 -0
- package/build/banner.ts +12 -0
- package/build/bump-version-changelog.js +26 -0
- package/build/check-bundle-size.js +77 -0
- package/build/generate-dist-package.js +26 -0
- package/build/generate-doc-images.ts +78 -0
- package/build/generate-docs.ts +190 -0
- package/build/generate-shaders.ts +68 -0
- package/build/generate-struct-arrays.ts +438 -0
- package/build/generate-style-code.ts +283 -0
- package/build/readme.md +56 -0
- package/build/release-notes.js +45 -0
- package/build/rollup/bundle_prelude.js +29 -0
- package/build/rollup/maplibregl.js +22 -0
- package/build/rollup_plugins.ts +58 -0
- package/dist/LICENSE.txt +116 -0
- package/dist/maplibre-gl.css +1 -0
- package/dist/maplibre-gl.d.ts +13304 -0
- package/dist/maplibre-gl.js +59 -0
- package/dist/maplibre-gl.js.map +1 -0
- package/dist/package.json +1 -0
- package/package.json +192 -0
- package/src/css/maplibre-gl.css +854 -0
- package/src/css/svg/maplibregl-ctrl-attrib.svg +3 -0
- package/src/css/svg/maplibregl-ctrl-compass.svg +4 -0
- package/src/css/svg/maplibregl-ctrl-fullscreen.svg +3 -0
- package/src/css/svg/maplibregl-ctrl-geolocate.svg +5 -0
- package/src/css/svg/maplibregl-ctrl-logo.svg +11 -0
- package/src/css/svg/maplibregl-ctrl-shrink.svg +3 -0
- package/src/css/svg/maplibregl-ctrl-terrain.svg +3 -0
- package/src/css/svg/maplibregl-ctrl-zoom-in.svg +3 -0
- package/src/css/svg/maplibregl-ctrl-zoom-out.svg +3 -0
- package/src/data/array_types.g.ts +1130 -0
- package/src/data/bucket/circle_attributes.ts +8 -0
- package/src/data/bucket/circle_bucket.ts +197 -0
- package/src/data/bucket/fill_attributes.ts +8 -0
- package/src/data/bucket/fill_bucket.test.ts +95 -0
- package/src/data/bucket/fill_bucket.ts +228 -0
- package/src/data/bucket/fill_extrusion_attributes.ts +13 -0
- package/src/data/bucket/fill_extrusion_bucket.ts +305 -0
- package/src/data/bucket/heatmap_bucket.ts +12 -0
- package/src/data/bucket/line_attributes.ts +8 -0
- package/src/data/bucket/line_attributes_ext.ts +8 -0
- package/src/data/bucket/line_bucket.test.ts +142 -0
- package/src/data/bucket/line_bucket.ts +592 -0
- package/src/data/bucket/pattern_attributes.ts +9 -0
- package/src/data/bucket/pattern_bucket_features.ts +57 -0
- package/src/data/bucket/symbol_attributes.ts +122 -0
- package/src/data/bucket/symbol_bucket.test.ts +243 -0
- package/src/data/bucket/symbol_bucket.ts +975 -0
- package/src/data/bucket.ts +123 -0
- package/src/data/dem_data.test.ts +237 -0
- package/src/data/dem_data.ts +171 -0
- package/src/data/evaluation_feature.ts +18 -0
- package/src/data/extent.ts +13 -0
- package/src/data/feature_index.ts +337 -0
- package/src/data/feature_position_map.test.ts +33 -0
- package/src/data/feature_position_map.ts +126 -0
- package/src/data/index_array_type.ts +9 -0
- package/src/data/load_geometry.test.ts +49 -0
- package/src/data/load_geometry.ts +44 -0
- package/src/data/pos3d_attributes.ts +5 -0
- package/src/data/pos_attributes.ts +5 -0
- package/src/data/program_configuration.ts +735 -0
- package/src/data/raster_bounds_attributes.ts +6 -0
- package/src/data/segment.ts +89 -0
- package/src/geo/edge_insets.test.ts +83 -0
- package/src/geo/edge_insets.ts +146 -0
- package/src/geo/lng_lat.test.ts +65 -0
- package/src/geo/lng_lat.ts +169 -0
- package/src/geo/lng_lat_bounds.test.ts +357 -0
- package/src/geo/lng_lat_bounds.ts +356 -0
- package/src/geo/mercator_coordinate.test.ts +34 -0
- package/src/geo/mercator_coordinate.ts +157 -0
- package/src/geo/projection/projection.ts +72 -0
- package/src/geo/transform.test.ts +509 -0
- package/src/geo/transform.ts +1072 -0
- package/src/gl/color_mode.ts +31 -0
- package/src/gl/context.ts +321 -0
- package/src/gl/cull_face_mode.ts +22 -0
- package/src/gl/depth_mode.ts +26 -0
- package/src/gl/framebuffer.ts +48 -0
- package/src/gl/index_buffer.ts +55 -0
- package/src/gl/render_pool.test.ts +69 -0
- package/src/gl/render_pool.ts +93 -0
- package/src/gl/state.test.ts +125 -0
- package/src/gl/stencil_mode.ts +27 -0
- package/src/gl/types.ts +59 -0
- package/src/gl/value.ts +534 -0
- package/src/gl/vertex_buffer.test.ts +57 -0
- package/src/gl/vertex_buffer.ts +111 -0
- package/src/gl/webgl2.ts +12 -0
- package/src/index.test.ts +121 -0
- package/src/index.ts +250 -0
- package/src/render/draw_background.ts +53 -0
- package/src/render/draw_circle.ts +113 -0
- package/src/render/draw_collision_debug.ts +168 -0
- package/src/render/draw_custom.test.ts +73 -0
- package/src/render/draw_custom.ts +45 -0
- package/src/render/draw_debug.test.ts +122 -0
- package/src/render/draw_debug.ts +148 -0
- package/src/render/draw_fill.test.ts +137 -0
- package/src/render/draw_fill.ts +128 -0
- package/src/render/draw_fill_extrusion.ts +97 -0
- package/src/render/draw_heatmap.ts +228 -0
- package/src/render/draw_hillshade.ts +119 -0
- package/src/render/draw_line.ts +125 -0
- package/src/render/draw_raster.ts +133 -0
- package/src/render/draw_sky.ts +44 -0
- package/src/render/draw_symbol.test.ts +223 -0
- package/src/render/draw_symbol.ts +499 -0
- package/src/render/draw_terrain.ts +99 -0
- package/src/render/glyph_atlas.ts +83 -0
- package/src/render/glyph_manager.test.ts +147 -0
- package/src/render/glyph_manager.ts +198 -0
- package/src/render/image_atlas.ts +159 -0
- package/src/render/image_manager.ts +337 -0
- package/src/render/line_atlas.test.ts +38 -0
- package/src/render/line_atlas.ts +214 -0
- package/src/render/mesh.ts +25 -0
- package/src/render/painter.test.ts +51 -0
- package/src/render/painter.ts +666 -0
- package/src/render/program/background_program.ts +100 -0
- package/src/render/program/circle_program.ts +61 -0
- package/src/render/program/clipping_mask_program.ts +19 -0
- package/src/render/program/collision_program.ts +47 -0
- package/src/render/program/debug_program.ts +29 -0
- package/src/render/program/fill_extrusion_program.ts +120 -0
- package/src/render/program/fill_program.ts +121 -0
- package/src/render/program/heatmap_program.ts +76 -0
- package/src/render/program/hillshade_program.ts +116 -0
- package/src/render/program/line_program.ts +207 -0
- package/src/render/program/pattern.ts +102 -0
- package/src/render/program/program_uniforms.ts +46 -0
- package/src/render/program/raster_program.ts +88 -0
- package/src/render/program/sky_program.ts +28 -0
- package/src/render/program/symbol_program.ts +266 -0
- package/src/render/program/terrain_program.ts +116 -0
- package/src/render/program.ts +233 -0
- package/src/render/render_to_texture.test.ts +151 -0
- package/src/render/render_to_texture.ts +197 -0
- package/src/render/terrain.test.ts +322 -0
- package/src/render/terrain.ts +464 -0
- package/src/render/texture.ts +114 -0
- package/src/render/uniform_binding.test.ts +122 -0
- package/src/render/uniform_binding.ts +157 -0
- package/src/render/update_pattern_positions_in_program.test.ts +74 -0
- package/src/render/update_pattern_positions_in_program.ts +50 -0
- package/src/render/vertex_array_object.ts +163 -0
- package/src/shaders/README.md +42 -0
- package/src/shaders/_prelude.fragment.glsl +19 -0
- package/src/shaders/_prelude.fragment.glsl.g.ts +2 -0
- package/src/shaders/_prelude.vertex.glsl +148 -0
- package/src/shaders/_prelude.vertex.glsl.g.ts +2 -0
- package/src/shaders/background.fragment.glsl +10 -0
- package/src/shaders/background.fragment.glsl.g.ts +2 -0
- package/src/shaders/background.vertex.glsl +7 -0
- package/src/shaders/background.vertex.glsl.g.ts +2 -0
- package/src/shaders/background_pattern.fragment.glsl +28 -0
- package/src/shaders/background_pattern.fragment.glsl.g.ts +2 -0
- package/src/shaders/background_pattern.vertex.glsl +19 -0
- package/src/shaders/background_pattern.vertex.glsl.g.ts +2 -0
- package/src/shaders/circle.fragment.glsl +34 -0
- package/src/shaders/circle.fragment.glsl.g.ts +2 -0
- package/src/shaders/circle.vertex.glsl +68 -0
- package/src/shaders/circle.vertex.glsl.g.ts +2 -0
- package/src/shaders/clipping_mask.fragment.glsl +3 -0
- package/src/shaders/clipping_mask.fragment.glsl.g.ts +2 -0
- package/src/shaders/clipping_mask.vertex.glsl +7 -0
- package/src/shaders/clipping_mask.vertex.glsl.g.ts +2 -0
- package/src/shaders/collision_box.fragment.glsl +20 -0
- package/src/shaders/collision_box.fragment.glsl.g.ts +2 -0
- package/src/shaders/collision_box.vertex.glsl +27 -0
- package/src/shaders/collision_box.vertex.glsl.g.ts +2 -0
- package/src/shaders/collision_circle.fragment.glsl +17 -0
- package/src/shaders/collision_circle.fragment.glsl.g.ts +2 -0
- package/src/shaders/collision_circle.vertex.glsl +59 -0
- package/src/shaders/collision_circle.vertex.glsl.g.ts +2 -0
- package/src/shaders/debug.fragment.glsl +9 -0
- package/src/shaders/debug.fragment.glsl.g.ts +2 -0
- package/src/shaders/debug.vertex.glsl +12 -0
- package/src/shaders/debug.vertex.glsl.g.ts +2 -0
- package/src/shaders/encode_attribute.test.ts +11 -0
- package/src/shaders/encode_attribute.ts +13 -0
- package/src/shaders/fill.fragment.glsl +13 -0
- package/src/shaders/fill.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill.vertex.glsl +13 -0
- package/src/shaders/fill.vertex.glsl.g.ts +2 -0
- package/src/shaders/fill_extrusion.fragment.glsl +9 -0
- package/src/shaders/fill_extrusion.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill_extrusion.vertex.glsl +84 -0
- package/src/shaders/fill_extrusion.vertex.glsl.g.ts +2 -0
- package/src/shaders/fill_extrusion_pattern.fragment.glsl +47 -0
- package/src/shaders/fill_extrusion_pattern.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill_extrusion_pattern.vertex.glsl +96 -0
- package/src/shaders/fill_extrusion_pattern.vertex.glsl.g.ts +2 -0
- package/src/shaders/fill_outline.fragment.glsl +17 -0
- package/src/shaders/fill_outline.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill_outline.vertex.glsl +17 -0
- package/src/shaders/fill_outline.vertex.glsl.g.ts +2 -0
- package/src/shaders/fill_outline_pattern.fragment.glsl +43 -0
- package/src/shaders/fill_outline_pattern.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill_outline_pattern.vertex.glsl +44 -0
- package/src/shaders/fill_outline_pattern.vertex.glsl.g.ts +2 -0
- package/src/shaders/fill_pattern.fragment.glsl +39 -0
- package/src/shaders/fill_pattern.fragment.glsl.g.ts +2 -0
- package/src/shaders/fill_pattern.vertex.glsl +39 -0
- package/src/shaders/fill_pattern.vertex.glsl.g.ts +2 -0
- package/src/shaders/heatmap.fragment.glsl +22 -0
- package/src/shaders/heatmap.fragment.glsl.g.ts +2 -0
- package/src/shaders/heatmap.vertex.glsl +54 -0
- package/src/shaders/heatmap.vertex.glsl.g.ts +2 -0
- package/src/shaders/heatmap_texture.fragment.glsl +15 -0
- package/src/shaders/heatmap_texture.fragment.glsl.g.ts +2 -0
- package/src/shaders/heatmap_texture.vertex.glsl +11 -0
- package/src/shaders/heatmap_texture.vertex.glsl.g.ts +2 -0
- package/src/shaders/hillshade.fragment.glsl +52 -0
- package/src/shaders/hillshade.fragment.glsl.g.ts +2 -0
- package/src/shaders/hillshade.vertex.glsl +11 -0
- package/src/shaders/hillshade.vertex.glsl.g.ts +2 -0
- package/src/shaders/hillshade_prepare.fragment.glsl +77 -0
- package/src/shaders/hillshade_prepare.fragment.glsl.g.ts +2 -0
- package/src/shaders/hillshade_prepare.vertex.glsl +15 -0
- package/src/shaders/hillshade_prepare.vertex.glsl.g.ts +2 -0
- package/src/shaders/line.fragment.glsl +30 -0
- package/src/shaders/line.fragment.glsl.g.ts +2 -0
- package/src/shaders/line.vertex.glsl +89 -0
- package/src/shaders/line.vertex.glsl.g.ts +2 -0
- package/src/shaders/line_gradient.fragment.glsl +34 -0
- package/src/shaders/line_gradient.fragment.glsl.g.ts +2 -0
- package/src/shaders/line_gradient.vertex.glsl +92 -0
- package/src/shaders/line_gradient.vertex.glsl.g.ts +2 -0
- package/src/shaders/line_pattern.fragment.glsl +77 -0
- package/src/shaders/line_pattern.fragment.glsl.g.ts +2 -0
- package/src/shaders/line_pattern.vertex.glsl +103 -0
- package/src/shaders/line_pattern.vertex.glsl.g.ts +2 -0
- package/src/shaders/line_sdf.fragment.glsl +45 -0
- package/src/shaders/line_sdf.fragment.glsl.g.ts +2 -0
- package/src/shaders/line_sdf.vertex.glsl +101 -0
- package/src/shaders/line_sdf.vertex.glsl.g.ts +2 -0
- package/src/shaders/raster.fragment.glsl +53 -0
- package/src/shaders/raster.fragment.glsl.g.ts +2 -0
- package/src/shaders/raster.vertex.glsl +21 -0
- package/src/shaders/raster.vertex.glsl.g.ts +2 -0
- package/src/shaders/shaders.ts +197 -0
- package/src/shaders/sky.fragment.glsl +17 -0
- package/src/shaders/sky.fragment.glsl.g.ts +2 -0
- package/src/shaders/sky.vertex.glsl +5 -0
- package/src/shaders/sky.vertex.glsl.g.ts +2 -0
- package/src/shaders/symbol_icon.fragment.glsl +17 -0
- package/src/shaders/symbol_icon.fragment.glsl.g.ts +2 -0
- package/src/shaders/symbol_icon.vertex.glsl +117 -0
- package/src/shaders/symbol_icon.vertex.glsl.g.ts +2 -0
- package/src/shaders/symbol_sdf.fragment.glsl +58 -0
- package/src/shaders/symbol_sdf.fragment.glsl.g.ts +2 -0
- package/src/shaders/symbol_sdf.vertex.glsl +142 -0
- package/src/shaders/symbol_sdf.vertex.glsl.g.ts +2 -0
- package/src/shaders/symbol_text_and_icon.fragment.glsl +68 -0
- package/src/shaders/symbol_text_and_icon.fragment.glsl.g.ts +2 -0
- package/src/shaders/symbol_text_and_icon.vertex.glsl +140 -0
- package/src/shaders/symbol_text_and_icon.vertex.glsl.g.ts +2 -0
- package/src/shaders/terrain.fragment.glsl +32 -0
- package/src/shaders/terrain.fragment.glsl.g.ts +2 -0
- package/src/shaders/terrain.vertex.glsl +17 -0
- package/src/shaders/terrain.vertex.glsl.g.ts +2 -0
- package/src/shaders/terrain_coords.fragment.glsl +11 -0
- package/src/shaders/terrain_coords.fragment.glsl.g.ts +2 -0
- package/src/shaders/terrain_coords.vertex.glsl +13 -0
- package/src/shaders/terrain_coords.vertex.glsl.g.ts +2 -0
- package/src/shaders/terrain_depth.fragment.glsl +15 -0
- package/src/shaders/terrain_depth.fragment.glsl.g.ts +2 -0
- package/src/shaders/terrain_depth.vertex.glsl +13 -0
- package/src/shaders/terrain_depth.vertex.glsl.g.ts +2 -0
- package/src/source/canvas_source.test.ts +210 -0
- package/src/source/canvas_source.ts +227 -0
- package/src/source/geojson_source.test.ts +492 -0
- package/src/source/geojson_source.ts +431 -0
- package/src/source/geojson_source_diff.test.ts +364 -0
- package/src/source/geojson_source_diff.ts +172 -0
- package/src/source/geojson_worker_source.test.ts +399 -0
- package/src/source/geojson_worker_source.ts +303 -0
- package/src/source/geojson_wrapper.test.ts +32 -0
- package/src/source/geojson_wrapper.ts +81 -0
- package/src/source/image_source.test.ts +235 -0
- package/src/source/image_source.ts +338 -0
- package/src/source/load_tilejson.ts +47 -0
- package/src/source/pixels_to_tile_units.ts +25 -0
- package/src/source/protocol_crud.ts +48 -0
- package/src/source/query_features.test.ts +31 -0
- package/src/source/query_features.ts +252 -0
- package/src/source/raster_dem_tile_source.test.ts +158 -0
- package/src/source/raster_dem_tile_source.ts +166 -0
- package/src/source/raster_dem_tile_worker_source.test.ts +36 -0
- package/src/source/raster_dem_tile_worker_source.ts +38 -0
- package/src/source/raster_tile_source.test.ts +206 -0
- package/src/source/raster_tile_source.ts +227 -0
- package/src/source/rtl_text_plugin_main_thread.test.ts +170 -0
- package/src/source/rtl_text_plugin_main_thread.ts +89 -0
- package/src/source/rtl_text_plugin_status.ts +33 -0
- package/src/source/rtl_text_plugin_worker.ts +49 -0
- package/src/source/source.test.ts +41 -0
- package/src/source/source.ts +186 -0
- package/src/source/source_cache.test.ts +2069 -0
- package/src/source/source_cache.ts +1102 -0
- package/src/source/source_state.ts +157 -0
- package/src/source/terrain_source_cache.test.ts +105 -0
- package/src/source/terrain_source_cache.ts +204 -0
- package/src/source/tile.test.ts +290 -0
- package/src/source/tile.ts +478 -0
- package/src/source/tile_bounds.ts +34 -0
- package/src/source/tile_cache.test.ts +130 -0
- package/src/source/tile_cache.ts +208 -0
- package/src/source/tile_id.test.ts +112 -0
- package/src/source/tile_id.ts +221 -0
- package/src/source/vector_tile_source.test.ts +401 -0
- package/src/source/vector_tile_source.ts +283 -0
- package/src/source/vector_tile_worker_source.test.ts +396 -0
- package/src/source/vector_tile_worker_source.ts +199 -0
- package/src/source/video_source.test.ts +124 -0
- package/src/source/video_source.ts +204 -0
- package/src/source/worker.test.ts +233 -0
- package/src/source/worker.ts +301 -0
- package/src/source/worker_source.ts +117 -0
- package/src/source/worker_tile.test.ts +226 -0
- package/src/source/worker_tile.ts +208 -0
- package/src/style/create_style_layer.ts +39 -0
- package/src/style/evaluation_parameters.ts +62 -0
- package/src/style/format_section_override.test.ts +62 -0
- package/src/style/format_section_override.ts +50 -0
- package/src/style/light.test.ts +86 -0
- package/src/style/light.ts +135 -0
- package/src/style/load_glyph_range.test.ts +40 -0
- package/src/style/load_glyph_range.ts +32 -0
- package/src/style/load_sprite.test.ts +227 -0
- package/src/style/load_sprite.ts +71 -0
- package/src/style/parse_glyph_pbf.ts +42 -0
- package/src/style/pauseable_placement.ts +138 -0
- package/src/style/properties.ts +726 -0
- package/src/style/query_utils.test.ts +107 -0
- package/src/style/query_utils.ts +70 -0
- package/src/style/sky.ts +127 -0
- package/src/style/style.test.ts +2654 -0
- package/src/style/style.ts +1814 -0
- package/src/style/style_glyph.ts +25 -0
- package/src/style/style_image.ts +188 -0
- package/src/style/style_layer/background_style_layer.ts +17 -0
- package/src/style/style_layer/background_style_layer_properties.g.ts +40 -0
- package/src/style/style_layer/circle_style_layer.ts +98 -0
- package/src/style/style_layer/circle_style_layer_properties.g.ts +76 -0
- package/src/style/style_layer/custom_style_layer.ts +233 -0
- package/src/style/style_layer/fill_extrusion_style_layer.ts +224 -0
- package/src/style/style_layer/fill_extrusion_style_layer_properties.g.ts +55 -0
- package/src/style/style_layer/fill_style_layer.test.ts +37 -0
- package/src/style/style_layer/fill_style_layer.ts +65 -0
- package/src/style/style_layer/fill_style_layer_properties.g.ts +64 -0
- package/src/style/style_layer/heatmap_style_layer.ts +74 -0
- package/src/style/style_layer/heatmap_style_layer_properties.g.ts +46 -0
- package/src/style/style_layer/hillshade_style_layer.ts +21 -0
- package/src/style/style_layer/hillshade_style_layer_properties.g.ts +49 -0
- package/src/style/style_layer/line_style_layer.test.ts +50 -0
- package/src/style/style_layer/line_style_layer.ts +131 -0
- package/src/style/style_layer/line_style_layer_properties.g.ts +88 -0
- package/src/style/style_layer/overlap_mode.test.ts +57 -0
- package/src/style/style_layer/overlap_mode.ts +25 -0
- package/src/style/style_layer/raster_style_layer.ts +17 -0
- package/src/style/style_layer/raster_style_layer_properties.g.ts +55 -0
- package/src/style/style_layer/symbol_style_layer.ts +195 -0
- package/src/style/style_layer/symbol_style_layer_properties.g.ts +218 -0
- package/src/style/style_layer/typed_style_layer.ts +9 -0
- package/src/style/style_layer/variable_text_anchor.test.ts +117 -0
- package/src/style/style_layer/variable_text_anchor.ts +163 -0
- package/src/style/style_layer.test.ts +372 -0
- package/src/style/style_layer.ts +287 -0
- package/src/style/style_layer_index.test.ts +99 -0
- package/src/style/style_layer_index.ts +78 -0
- package/src/style/validate_style.ts +53 -0
- package/src/style/zoom_history.ts +40 -0
- package/src/symbol/anchor.test.ts +14 -0
- package/src/symbol/anchor.ts +22 -0
- package/src/symbol/check_max_angle.test.ts +54 -0
- package/src/symbol/check_max_angle.ts +76 -0
- package/src/symbol/clip_line.test.ts +154 -0
- package/src/symbol/clip_line.ts +66 -0
- package/src/symbol/collision_feature.test.ts +98 -0
- package/src/symbol/collision_feature.ts +114 -0
- package/src/symbol/collision_index.test.ts +19 -0
- package/src/symbol/collision_index.ts +618 -0
- package/src/symbol/cross_tile_symbol_index.test.ts +260 -0
- package/src/symbol/cross_tile_symbol_index.ts +367 -0
- package/src/symbol/get_anchors.test.ts +113 -0
- package/src/symbol/get_anchors.ts +167 -0
- package/src/symbol/grid_index.test.ts +75 -0
- package/src/symbol/grid_index.ts +414 -0
- package/src/symbol/merge_lines.test.ts +30 -0
- package/src/symbol/merge_lines.ts +80 -0
- package/src/symbol/one_em.ts +3 -0
- package/src/symbol/opacity_state.ts +23 -0
- package/src/symbol/path_interpolator.test.ts +134 -0
- package/src/symbol/path_interpolator.ts +55 -0
- package/src/symbol/placement.ts +1371 -0
- package/src/symbol/projection.test.ts +171 -0
- package/src/symbol/projection.ts +833 -0
- package/src/symbol/quads.test.ts +157 -0
- package/src/symbol/quads.ts +349 -0
- package/src/symbol/shaping.test.ts +360 -0
- package/src/symbol/shaping.ts +911 -0
- package/src/symbol/symbol_layout.ts +739 -0
- package/src/symbol/symbol_size.ts +129 -0
- package/src/symbol/symbol_style_layer.test.ts +103 -0
- package/src/symbol/transform_text.ts +27 -0
- package/src/ui/anchor.ts +27 -0
- package/src/ui/camera.test.ts +2301 -0
- package/src/ui/camera.ts +1520 -0
- package/src/ui/control/attribution_control.test.ts +543 -0
- package/src/ui/control/attribution_control.ts +209 -0
- package/src/ui/control/control.ts +67 -0
- package/src/ui/control/fullscreen_control.test.ts +114 -0
- package/src/ui/control/fullscreen_control.ts +189 -0
- package/src/ui/control/geolocate_control.test.ts +619 -0
- package/src/ui/control/geolocate_control.ts +725 -0
- package/src/ui/control/logo_control.test.ts +88 -0
- package/src/ui/control/logo_control.ts +86 -0
- package/src/ui/control/navigation_control.test.ts +238 -0
- package/src/ui/control/navigation_control.ts +294 -0
- package/src/ui/control/scale_control.test.ts +52 -0
- package/src/ui/control/scale_control.ts +152 -0
- package/src/ui/control/terrain_control.test.ts +58 -0
- package/src/ui/control/terrain_control.ts +74 -0
- package/src/ui/default_locale.ts +25 -0
- package/src/ui/events.ts +758 -0
- package/src/ui/handler/box_zoom.test.ts +163 -0
- package/src/ui/handler/box_zoom.ts +171 -0
- package/src/ui/handler/click_zoom.ts +55 -0
- package/src/ui/handler/cooperative_gestures.test.ts +338 -0
- package/src/ui/handler/cooperative_gestures.ts +111 -0
- package/src/ui/handler/dblclick_zoom.test.ts +151 -0
- package/src/ui/handler/drag_handler.ts +174 -0
- package/src/ui/handler/drag_move_state_manager.ts +115 -0
- package/src/ui/handler/drag_pan.test.ts +487 -0
- package/src/ui/handler/drag_rotate.test.ts +859 -0
- package/src/ui/handler/handler_util.ts +10 -0
- package/src/ui/handler/keyboard.test.ts +235 -0
- package/src/ui/handler/keyboard.ts +212 -0
- package/src/ui/handler/map_event.test.ts +158 -0
- package/src/ui/handler/map_event.ts +161 -0
- package/src/ui/handler/mouse.ts +92 -0
- package/src/ui/handler/mouse_handler_interface.test.ts +111 -0
- package/src/ui/handler/mouse_rotate.test.ts +62 -0
- package/src/ui/handler/one_finger_touch_drag.ts +45 -0
- package/src/ui/handler/one_finger_touch_drag_handler_interface.test.ts +77 -0
- package/src/ui/handler/scroll_zoom.test.ts +382 -0
- package/src/ui/handler/scroll_zoom.ts +379 -0
- package/src/ui/handler/shim/dblclick_zoom.ts +64 -0
- package/src/ui/handler/shim/drag_pan.ts +104 -0
- package/src/ui/handler/shim/drag_rotate.ts +76 -0
- package/src/ui/handler/shim/two_fingers_touch.ts +112 -0
- package/src/ui/handler/tap_drag_zoom.test.ts +113 -0
- package/src/ui/handler/tap_drag_zoom.ts +112 -0
- package/src/ui/handler/tap_recognizer.ts +138 -0
- package/src/ui/handler/tap_zoom.ts +98 -0
- package/src/ui/handler/touch_pan.ts +115 -0
- package/src/ui/handler/transform-provider.ts +44 -0
- package/src/ui/handler/two_fingers_touch.test.ts +283 -0
- package/src/ui/handler/two_fingers_touch.ts +336 -0
- package/src/ui/handler_inertia.ts +157 -0
- package/src/ui/handler_manager.ts +637 -0
- package/src/ui/hash.test.ts +404 -0
- package/src/ui/hash.ts +153 -0
- package/src/ui/map.ts +3393 -0
- package/src/ui/map_tests/map_animation.test.ts +61 -0
- package/src/ui/map_tests/map_basic.test.ts +223 -0
- package/src/ui/map_tests/map_bounds.test.ts +123 -0
- package/src/ui/map_tests/map_calculate_camera_options.test.ts +113 -0
- package/src/ui/map_tests/map_canvas.test.ts +59 -0
- package/src/ui/map_tests/map_control.test.ts +61 -0
- package/src/ui/map_tests/map_disable_handlers.test.ts +38 -0
- package/src/ui/map_tests/map_events.test.ts +1001 -0
- package/src/ui/map_tests/map_feature_state.test.ts +421 -0
- package/src/ui/map_tests/map_images.test.ts +175 -0
- package/src/ui/map_tests/map_is_moving.test.ts +164 -0
- package/src/ui/map_tests/map_is_rotating.test.ts +62 -0
- package/src/ui/map_tests/map_is_zooming.test.ts +86 -0
- package/src/ui/map_tests/map_layer.test.ts +457 -0
- package/src/ui/map_tests/map_options.test.ts +64 -0
- package/src/ui/map_tests/map_pitch.test.ts +90 -0
- package/src/ui/map_tests/map_pixel_ratio.test.ts +75 -0
- package/src/ui/map_tests/map_query_rendered_features.test.ts +93 -0
- package/src/ui/map_tests/map_render.test.ts +90 -0
- package/src/ui/map_tests/map_request_render_frame.test.ts +51 -0
- package/src/ui/map_tests/map_resize.test.ts +120 -0
- package/src/ui/map_tests/map_style.test.ts +541 -0
- package/src/ui/map_tests/map_terrian.test.ts +104 -0
- package/src/ui/map_tests/map_webgl.test.ts +72 -0
- package/src/ui/map_tests/map_world_copies.test.ts +103 -0
- package/src/ui/map_tests/map_zoom.test.ts +95 -0
- package/src/ui/marker.test.ts +1149 -0
- package/src/ui/marker.ts +880 -0
- package/src/ui/popup.test.ts +827 -0
- package/src/ui/popup.ts +717 -0
- package/src/util/abort_error.ts +21 -0
- package/src/util/actor.test.ts +218 -0
- package/src/util/actor.ts +241 -0
- package/src/util/actor_messages.ts +149 -0
- package/src/util/ajax.test.ts +237 -0
- package/src/util/ajax.ts +297 -0
- package/src/util/browser.test.ts +23 -0
- package/src/util/browser.ts +63 -0
- package/src/util/color_ramp.test.ts +105 -0
- package/src/util/color_ramp.ts +56 -0
- package/src/util/config.ts +29 -0
- package/src/util/dictionary_coder.ts +23 -0
- package/src/util/dispatcher.test.ts +76 -0
- package/src/util/dispatcher.ts +78 -0
- package/src/util/dom.ts +135 -0
- package/src/util/evented.test.ts +231 -0
- package/src/util/evented.ts +178 -0
- package/src/util/find_pole_of_inaccessibility.test.ts +21 -0
- package/src/util/find_pole_of_inaccessibility.ts +130 -0
- package/src/util/geolocation_support.test.ts +43 -0
- package/src/util/geolocation_support.ts +23 -0
- package/src/util/global_worker_pool.ts +65 -0
- package/src/util/image.ts +150 -0
- package/src/util/image_request.test.ts +408 -0
- package/src/util/image_request.ts +246 -0
- package/src/util/intersection_tests.ts +206 -0
- package/src/util/is_char_in_unicode_block.test.ts +15 -0
- package/src/util/is_char_in_unicode_block.ts +345 -0
- package/src/util/offscreen_canvas_distorted.test.ts +13 -0
- package/src/util/offscreen_canvas_distorted.ts +39 -0
- package/src/util/offscreen_canvas_supported.ts +11 -0
- package/src/util/performance.ts +117 -0
- package/src/util/primitives.test.ts +140 -0
- package/src/util/primitives.ts +143 -0
- package/src/util/request_manager.ts +42 -0
- package/src/util/resolve_tokens.test.ts +45 -0
- package/src/util/resolve_tokens.ts +17 -0
- package/src/util/script_detection.test.ts +138 -0
- package/src/util/script_detection.ts +376 -0
- package/src/util/smart_wrap.test.ts +97 -0
- package/src/util/smart_wrap.ts +58 -0
- package/src/util/struct_array.test.ts +101 -0
- package/src/util/struct_array.ts +246 -0
- package/src/util/style.test.ts +34 -0
- package/src/util/style.ts +28 -0
- package/src/util/task_queue.test.ts +114 -0
- package/src/util/task_queue.ts +64 -0
- package/src/util/test/util.ts +185 -0
- package/src/util/throttle.test.ts +42 -0
- package/src/util/throttle.ts +28 -0
- package/src/util/throttled_invoker.ts +41 -0
- package/src/util/transferable_grid_index.test.ts +56 -0
- package/src/util/transferable_grid_index.ts +214 -0
- package/src/util/util.test.ts +414 -0
- package/src/util/util.ts +724 -0
- package/src/util/vectortile_to_geojson.ts +72 -0
- package/src/util/verticalize_punctuation.ts +110 -0
- package/src/util/web_worker.ts +16 -0
- package/src/util/web_worker_transfer.test.ts +153 -0
- package/src/util/web_worker_transfer.ts +254 -0
- package/src/util/webp_supported.ts +63 -0
- package/src/util/worker_pool.test.ts +43 -0
- package/src/util/worker_pool.ts +58 -0
- package/src/util/world_bounds.test.ts +59 -0
- 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
|
+
}
|