@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,2654 @@
|
|
|
1
|
+
import {Style} from './style';
|
|
2
|
+
import {SourceCache} from '../source/source_cache';
|
|
3
|
+
import {StyleLayer} from './style_layer';
|
|
4
|
+
import {Transform} from '../geo/transform';
|
|
5
|
+
import {extend} from '../util/util';
|
|
6
|
+
import {RequestManager} from '../util/request_manager';
|
|
7
|
+
import {Event, Evented} from '../util/evented';
|
|
8
|
+
import {RGBAImage} from '../util/image';
|
|
9
|
+
import {rtlMainThreadPluginFactory} from '../source/rtl_text_plugin_main_thread';
|
|
10
|
+
import {browser} from '../util/browser';
|
|
11
|
+
import {OverscaledTileID} from '../source/tile_id';
|
|
12
|
+
import {fakeServer, type FakeServer} from 'nise';
|
|
13
|
+
|
|
14
|
+
import {EvaluationParameters} from './evaluation_parameters';
|
|
15
|
+
import {LayerSpecification, GeoJSONSourceSpecification, FilterSpecification, SourceSpecification, StyleSpecification, SymbolLayerSpecification, TerrainSpecification, SkySpecification} from '@maplibre/maplibre-gl-style-spec';
|
|
16
|
+
import {GeoJSONSource} from '../source/geojson_source';
|
|
17
|
+
import {sleep} from '../util/test/util';
|
|
18
|
+
import {RTLPluginLoadedEventName} from '../source/rtl_text_plugin_status';
|
|
19
|
+
import {MessageType} from '../util/actor_messages';
|
|
20
|
+
|
|
21
|
+
function createStyleJSON(properties?): StyleSpecification {
|
|
22
|
+
return extend({
|
|
23
|
+
'version': 8,
|
|
24
|
+
'sources': {},
|
|
25
|
+
'layers': []
|
|
26
|
+
}, properties);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function createSource() {
|
|
30
|
+
return {
|
|
31
|
+
type: 'vector',
|
|
32
|
+
minzoom: 1,
|
|
33
|
+
maxzoom: 10,
|
|
34
|
+
attribution: 'MapLibre',
|
|
35
|
+
tiles: ['http://example.com/{z}/{x}/{y}.png']
|
|
36
|
+
} as any as SourceSpecification;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function createGeoJSONSource() {
|
|
40
|
+
return {
|
|
41
|
+
'type': 'geojson',
|
|
42
|
+
'data': {
|
|
43
|
+
'type': 'FeatureCollection',
|
|
44
|
+
'features': []
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class StubMap extends Evented {
|
|
50
|
+
style: Style;
|
|
51
|
+
transform: Transform;
|
|
52
|
+
private _requestManager: RequestManager;
|
|
53
|
+
_terrain: TerrainSpecification;
|
|
54
|
+
|
|
55
|
+
constructor() {
|
|
56
|
+
super();
|
|
57
|
+
this.transform = new Transform();
|
|
58
|
+
this._requestManager = new RequestManager();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_getMapId() {
|
|
62
|
+
return 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getPixelRatio() {
|
|
66
|
+
return 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setTerrain(terrain) { this._terrain = terrain; }
|
|
70
|
+
getTerrain() { return this._terrain; }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const getStubMap = () => new StubMap() as any;
|
|
74
|
+
|
|
75
|
+
function createStyle(map = getStubMap()) {
|
|
76
|
+
const style = new Style(map);
|
|
77
|
+
map.style = style;
|
|
78
|
+
return style;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let server: FakeServer;
|
|
82
|
+
let mockConsoleError: jest.SpyInstance;
|
|
83
|
+
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
global.fetch = null;
|
|
86
|
+
server = fakeServer.create();
|
|
87
|
+
mockConsoleError = jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
afterEach(() => {
|
|
91
|
+
server.restore();
|
|
92
|
+
mockConsoleError.mockRestore();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('Style', () => {
|
|
96
|
+
test('RTL plugin load reloads vector source but not raster source', async() => {
|
|
97
|
+
const map = getStubMap();
|
|
98
|
+
const style = new Style(map);
|
|
99
|
+
map.style = style;
|
|
100
|
+
style.loadJSON({
|
|
101
|
+
'version': 8,
|
|
102
|
+
'sources': {
|
|
103
|
+
'raster': {
|
|
104
|
+
type: 'raster',
|
|
105
|
+
tiles: ['http://tiles.server']
|
|
106
|
+
},
|
|
107
|
+
'vector': {
|
|
108
|
+
type: 'vector',
|
|
109
|
+
tiles: ['http://tiles.server']
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
'layers': [{
|
|
113
|
+
'id': 'raster',
|
|
114
|
+
'type': 'raster',
|
|
115
|
+
'source': 'raster'
|
|
116
|
+
}]
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await style.once('style.load');
|
|
120
|
+
jest.spyOn(style.sourceCaches['raster'], 'reload');
|
|
121
|
+
jest.spyOn(style.sourceCaches['vector'], 'reload');
|
|
122
|
+
|
|
123
|
+
rtlMainThreadPluginFactory().fire(new Event(RTLPluginLoadedEventName));
|
|
124
|
+
|
|
125
|
+
expect(style.sourceCaches['raster'].reload).not.toHaveBeenCalled();
|
|
126
|
+
expect(style.sourceCaches['vector'].reload).toHaveBeenCalled();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('Style#loadURL', () => {
|
|
131
|
+
test('fires "dataloading"', () => {
|
|
132
|
+
const style = new Style(getStubMap());
|
|
133
|
+
const spy = jest.fn();
|
|
134
|
+
|
|
135
|
+
style.on('dataloading', spy);
|
|
136
|
+
style.loadURL('style.json');
|
|
137
|
+
|
|
138
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
139
|
+
expect(spy.mock.calls[0][0].target).toBe(style);
|
|
140
|
+
expect(spy.mock.calls[0][0].dataType).toBe('style');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test('transforms style URL before request', () => {
|
|
144
|
+
const map = getStubMap();
|
|
145
|
+
const spy = jest.spyOn(map._requestManager, 'transformRequest');
|
|
146
|
+
|
|
147
|
+
const style = new Style(map);
|
|
148
|
+
style.loadURL('style.json');
|
|
149
|
+
|
|
150
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
151
|
+
expect(spy.mock.calls[0][0]).toBe('style.json');
|
|
152
|
+
expect(spy.mock.calls[0][1]).toBe('Style');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('validates the style', () => new Promise<void>(done => {
|
|
156
|
+
const style = new Style(getStubMap());
|
|
157
|
+
|
|
158
|
+
style.on('error', ({error}) => {
|
|
159
|
+
expect(error).toBeTruthy();
|
|
160
|
+
expect(error.message).toMatch(/version/);
|
|
161
|
+
done();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
style.loadURL('style.json');
|
|
165
|
+
server.respondWith(JSON.stringify(createStyleJSON({version: 'invalid'})));
|
|
166
|
+
server.respond();
|
|
167
|
+
}));
|
|
168
|
+
|
|
169
|
+
test('cancels pending requests if removed', () => {
|
|
170
|
+
const style = new Style(getStubMap());
|
|
171
|
+
style.loadURL('style.json');
|
|
172
|
+
style._remove();
|
|
173
|
+
expect((server.lastRequest as any).aborted).toBe(true);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test('does not fire an error if removed', async () => {
|
|
177
|
+
const style = new Style(getStubMap());
|
|
178
|
+
const spy = jest.fn();
|
|
179
|
+
|
|
180
|
+
style.on('error', spy);
|
|
181
|
+
style.loadURL('style.json');
|
|
182
|
+
style._remove();
|
|
183
|
+
await sleep(0);
|
|
184
|
+
|
|
185
|
+
expect(spy).not.toHaveBeenCalled();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test('fires an error if the request fails', async () => {
|
|
189
|
+
const style = new Style(getStubMap());
|
|
190
|
+
const errorStatus = 400;
|
|
191
|
+
|
|
192
|
+
const promise = style.once('error');
|
|
193
|
+
style.loadURL('style.json');
|
|
194
|
+
server.respondWith(request => request.respond(errorStatus));
|
|
195
|
+
server.respond();
|
|
196
|
+
const {error} = await promise;
|
|
197
|
+
|
|
198
|
+
expect(error).toBeTruthy();
|
|
199
|
+
expect(error.status).toBe(errorStatus);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('Style#loadJSON', () => {
|
|
204
|
+
test('serialize() returns undefined until style is loaded', async () => {
|
|
205
|
+
const style = new Style(getStubMap());
|
|
206
|
+
style.loadJSON(createStyleJSON());
|
|
207
|
+
expect(style.serialize()).toBeUndefined();
|
|
208
|
+
await style.once('style.load');
|
|
209
|
+
expect(style.serialize()).toEqual(createStyleJSON());
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test('fires "dataloading" (synchronously)', () => {
|
|
213
|
+
const style = new Style(getStubMap());
|
|
214
|
+
const spy = jest.fn();
|
|
215
|
+
|
|
216
|
+
style.on('dataloading', spy);
|
|
217
|
+
style.loadJSON(createStyleJSON());
|
|
218
|
+
|
|
219
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
220
|
+
expect(spy.mock.calls[0][0].target).toBe(style);
|
|
221
|
+
expect(spy.mock.calls[0][0].dataType).toBe('style');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test('fires "data" (asynchronously)', async () => {
|
|
225
|
+
const style = new Style(getStubMap());
|
|
226
|
+
|
|
227
|
+
style.loadJSON(createStyleJSON());
|
|
228
|
+
|
|
229
|
+
const e = await style.once('data');
|
|
230
|
+
expect(e.target).toBe(style);
|
|
231
|
+
expect(e.dataType).toBe('style');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('fires "data" when the sprite finishes loading', async () => {
|
|
235
|
+
// Stubbing to bypass Web APIs that supported by jsdom:
|
|
236
|
+
// * `URL.createObjectURL` in ajax.getImage (https://github.com/tmpvar/jsdom/issues/1721)
|
|
237
|
+
// * `canvas.getContext('2d')` in browser.getImageData
|
|
238
|
+
jest.spyOn(browser, 'getImageData');
|
|
239
|
+
// stub Image so we can invoke 'onload'
|
|
240
|
+
// https://github.com/jsdom/jsdom/commit/58a7028d0d5b6aacc5b435daee9fd8f9eacbb14c
|
|
241
|
+
|
|
242
|
+
server.respondWith('GET', 'http://example.com/sprite.png', new ArrayBuffer(8));
|
|
243
|
+
server.respondWith('GET', 'http://example.com/sprite.json', '{}');
|
|
244
|
+
|
|
245
|
+
const style = new Style(getStubMap());
|
|
246
|
+
|
|
247
|
+
style.loadJSON({
|
|
248
|
+
'version': 8,
|
|
249
|
+
'sources': {},
|
|
250
|
+
'layers': [],
|
|
251
|
+
'sprite': 'http://example.com/sprite'
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
style.once('error', (e) => expect(e).toBeFalsy());
|
|
255
|
+
|
|
256
|
+
const e = await style.once('data');
|
|
257
|
+
expect(e.target).toBe(style);
|
|
258
|
+
expect(e.dataType).toBe('style');
|
|
259
|
+
|
|
260
|
+
const promise = style.once('data');
|
|
261
|
+
server.respond();
|
|
262
|
+
|
|
263
|
+
await promise;
|
|
264
|
+
expect(e.target).toBe(style);
|
|
265
|
+
expect(e.dataType).toBe('style');
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test('Validate sprite image extraction', async () => {
|
|
269
|
+
// Stubbing to bypass Web APIs that supported by jsdom:
|
|
270
|
+
// * `URL.createObjectURL` in ajax.getImage (https://github.com/tmpvar/jsdom/issues/1721)
|
|
271
|
+
// * `canvas.getContext('2d')` in browser.getImageData
|
|
272
|
+
jest.spyOn(browser, 'getImageData');
|
|
273
|
+
// stub Image so we can invoke 'onload'
|
|
274
|
+
// https://github.com/jsdom/jsdom/commit/58a7028d0d5b6aacc5b435daee9fd8f9eacbb14c
|
|
275
|
+
|
|
276
|
+
server.respondWith('GET', 'http://example.com/sprite.png', new ArrayBuffer(8));
|
|
277
|
+
server.respondWith('GET', 'http://example.com/sprite.json', '{"image1": {"width": 1, "height": 1, "x": 0, "y": 0, "pixelRatio": 1.0}}');
|
|
278
|
+
|
|
279
|
+
const style = new Style(getStubMap());
|
|
280
|
+
|
|
281
|
+
style.loadJSON({
|
|
282
|
+
'version': 8,
|
|
283
|
+
'sources': {},
|
|
284
|
+
'layers': [],
|
|
285
|
+
'sprite': 'http://example.com/sprite'
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const firstDataEvent = await style.once('data');
|
|
289
|
+
expect(firstDataEvent.target).toBe(style);
|
|
290
|
+
expect(firstDataEvent.dataType).toBe('style');
|
|
291
|
+
|
|
292
|
+
const secondDataPromise = style.once('data');
|
|
293
|
+
|
|
294
|
+
server.respond();
|
|
295
|
+
|
|
296
|
+
const secondDateEvent = await secondDataPromise;
|
|
297
|
+
expect(secondDateEvent.target).toBe(style);
|
|
298
|
+
expect(secondDateEvent.dataType).toBe('style');
|
|
299
|
+
const response = await style.imageManager.getImages(['image1']);
|
|
300
|
+
const image = response['image1'];
|
|
301
|
+
expect(image.data).toBeInstanceOf(RGBAImage);
|
|
302
|
+
expect(image.data.width).toBe(1);
|
|
303
|
+
expect(image.data.height).toBe(1);
|
|
304
|
+
expect(image.pixelRatio).toBe(1);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test('validates the style', async () => {
|
|
308
|
+
const style = new Style(getStubMap());
|
|
309
|
+
|
|
310
|
+
const promise = style.once('error');
|
|
311
|
+
style.loadJSON(createStyleJSON({version: 'invalid'}));
|
|
312
|
+
const {error} = await promise;
|
|
313
|
+
|
|
314
|
+
expect(error).toBeTruthy();
|
|
315
|
+
expect(error.message).toMatch(/version/);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test('creates sources', async () => {
|
|
319
|
+
const style = createStyle();
|
|
320
|
+
|
|
321
|
+
style.loadJSON(extend(createStyleJSON(), {
|
|
322
|
+
'sources': {
|
|
323
|
+
'mapLibre': {
|
|
324
|
+
'type': 'vector',
|
|
325
|
+
'tiles': []
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}));
|
|
329
|
+
|
|
330
|
+
await style.once('style.load');
|
|
331
|
+
expect(style.sourceCaches['mapLibre'] instanceof SourceCache).toBeTruthy();
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
test('creates layers', async () => {
|
|
335
|
+
const style = createStyle();
|
|
336
|
+
|
|
337
|
+
style.loadJSON({
|
|
338
|
+
'version': 8,
|
|
339
|
+
'sources': {
|
|
340
|
+
'foo': {
|
|
341
|
+
'type': 'vector'
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
'layers': [{
|
|
345
|
+
'id': 'fill',
|
|
346
|
+
'source': 'foo',
|
|
347
|
+
'source-layer': 'source-layer',
|
|
348
|
+
'type': 'fill'
|
|
349
|
+
}]
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
await style.once('style.load');
|
|
353
|
+
expect(style.getLayer('fill') instanceof StyleLayer).toBeTruthy();
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test('transforms sprite json and image URLs before request', async () => {
|
|
357
|
+
const map = getStubMap();
|
|
358
|
+
const transformSpy = jest.spyOn(map._requestManager, 'transformRequest');
|
|
359
|
+
const style = createStyle(map);
|
|
360
|
+
|
|
361
|
+
style.loadJSON(extend(createStyleJSON(), {
|
|
362
|
+
'sprite': 'http://example.com/sprites/bright-v8'
|
|
363
|
+
}));
|
|
364
|
+
|
|
365
|
+
await style.once('style.load');
|
|
366
|
+
|
|
367
|
+
expect(transformSpy).toHaveBeenCalledTimes(2);
|
|
368
|
+
expect(transformSpy.mock.calls[0][0]).toBe('http://example.com/sprites/bright-v8.json');
|
|
369
|
+
expect(transformSpy.mock.calls[0][1]).toBe('SpriteJSON');
|
|
370
|
+
expect(transformSpy.mock.calls[1][0]).toBe('http://example.com/sprites/bright-v8.png');
|
|
371
|
+
expect(transformSpy.mock.calls[1][1]).toBe('SpriteImage');
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
test('emits an error on non-existant vector source layer', () => new Promise<void>(done => {
|
|
375
|
+
const style = createStyle();
|
|
376
|
+
style.loadJSON(createStyleJSON({
|
|
377
|
+
sources: {
|
|
378
|
+
'-source-id-': {type: 'vector', tiles: []}
|
|
379
|
+
},
|
|
380
|
+
layers: []
|
|
381
|
+
}));
|
|
382
|
+
|
|
383
|
+
style.on('style.load', () => {
|
|
384
|
+
style.removeSource('-source-id-');
|
|
385
|
+
|
|
386
|
+
const source = createSource();
|
|
387
|
+
source['vector_layers'] = [{id: 'green'}];
|
|
388
|
+
style.addSource('-source-id-', source);
|
|
389
|
+
style.addLayer({
|
|
390
|
+
'id': '-layer-id-',
|
|
391
|
+
'type': 'circle',
|
|
392
|
+
'source': '-source-id-',
|
|
393
|
+
'source-layer': '-source-layer-'
|
|
394
|
+
});
|
|
395
|
+
style.update({} as EvaluationParameters);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
style.on('error', (event) => {
|
|
399
|
+
const err = event.error;
|
|
400
|
+
expect(err).toBeTruthy();
|
|
401
|
+
expect(err.toString().indexOf('-source-layer-') !== -1).toBeTruthy();
|
|
402
|
+
expect(err.toString().indexOf('-source-id-') !== -1).toBeTruthy();
|
|
403
|
+
expect(err.toString().indexOf('-layer-id-') !== -1).toBeTruthy();
|
|
404
|
+
|
|
405
|
+
done();
|
|
406
|
+
});
|
|
407
|
+
}));
|
|
408
|
+
|
|
409
|
+
test('sets up layer event forwarding', () => new Promise<void>(done => {
|
|
410
|
+
const style = new Style(getStubMap());
|
|
411
|
+
style.loadJSON(createStyleJSON({
|
|
412
|
+
layers: [{
|
|
413
|
+
id: 'background',
|
|
414
|
+
type: 'background'
|
|
415
|
+
}]
|
|
416
|
+
}));
|
|
417
|
+
|
|
418
|
+
style.on('error', (e) => {
|
|
419
|
+
expect(e.layer).toEqual({id: 'background'});
|
|
420
|
+
expect(e.mapLibre).toBeTruthy();
|
|
421
|
+
done();
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
style.on('style.load', () => {
|
|
425
|
+
style._layers.background.fire(new Event('error', {mapLibre: true}));
|
|
426
|
+
});
|
|
427
|
+
}));
|
|
428
|
+
|
|
429
|
+
test('sets terrain if defined', async () => {
|
|
430
|
+
const map = getStubMap();
|
|
431
|
+
const style = new Style(map);
|
|
432
|
+
map.setTerrain = jest.fn();
|
|
433
|
+
style.loadJSON(createStyleJSON({
|
|
434
|
+
sources: {'source-id': createGeoJSONSource()},
|
|
435
|
+
terrain: {source: 'source-id', exaggeration: 0.33}
|
|
436
|
+
}));
|
|
437
|
+
|
|
438
|
+
await style.once('style.load');
|
|
439
|
+
|
|
440
|
+
expect(style.map.setTerrain).toHaveBeenCalled();
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
test('applies transformStyle function', async () => {
|
|
444
|
+
const previousStyle = createStyleJSON({
|
|
445
|
+
sources: {
|
|
446
|
+
base: {
|
|
447
|
+
type: 'geojson',
|
|
448
|
+
data: {type: 'FeatureCollection', features: []}
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
layers: [{
|
|
452
|
+
id: 'layerId0',
|
|
453
|
+
type: 'circle',
|
|
454
|
+
source: 'base'
|
|
455
|
+
}, {
|
|
456
|
+
id: 'layerId1',
|
|
457
|
+
type: 'circle',
|
|
458
|
+
source: 'base'
|
|
459
|
+
}]
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
const style = new Style(getStubMap());
|
|
463
|
+
style.loadJSON(createStyleJSON(), {
|
|
464
|
+
transformStyle: (prevStyle, nextStyle) => ({
|
|
465
|
+
...nextStyle,
|
|
466
|
+
sources: {
|
|
467
|
+
...nextStyle.sources,
|
|
468
|
+
base: prevStyle.sources.base
|
|
469
|
+
},
|
|
470
|
+
layers: [
|
|
471
|
+
...nextStyle.layers,
|
|
472
|
+
prevStyle.layers[0]
|
|
473
|
+
]
|
|
474
|
+
})
|
|
475
|
+
}, previousStyle);
|
|
476
|
+
|
|
477
|
+
await style.once('style.load');
|
|
478
|
+
|
|
479
|
+
expect('base' in style.stylesheet.sources).toBeTruthy();
|
|
480
|
+
expect(style.stylesheet.layers[0].id).toBe(previousStyle.layers[0].id);
|
|
481
|
+
expect(style.stylesheet.layers).toHaveLength(1);
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
describe('Style#_load', () => {
|
|
486
|
+
test('initiates sprite loading when it\'s present', () => {
|
|
487
|
+
const style = new Style(getStubMap());
|
|
488
|
+
|
|
489
|
+
const prevStyleSpec = createStyleJSON({
|
|
490
|
+
sprite: 'https://example.com/test1'
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
const nextStyleSpec = createStyleJSON({
|
|
494
|
+
sprite: 'https://example.com/test2'
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
const _loadSpriteSpyOn = jest.spyOn(style, '_loadSprite');
|
|
498
|
+
style._load(nextStyleSpec, {}, prevStyleSpec);
|
|
499
|
+
|
|
500
|
+
expect(_loadSpriteSpyOn).toHaveBeenCalledTimes(1);
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
test('does not initiate sprite loading when it\'s absent (undefined)', () => {
|
|
504
|
+
const style = new Style(getStubMap());
|
|
505
|
+
|
|
506
|
+
const prevStyleSpec = createStyleJSON({
|
|
507
|
+
sprite: 'https://example.com/test1'
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
const nextStyleSpec = createStyleJSON({sprite: undefined});
|
|
511
|
+
|
|
512
|
+
const _loadSpriteSpyOn = jest.spyOn(style, '_loadSprite');
|
|
513
|
+
style._load(nextStyleSpec, {}, prevStyleSpec);
|
|
514
|
+
|
|
515
|
+
expect(_loadSpriteSpyOn).not.toHaveBeenCalled();
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
test('layers are broadcasted to worker', () => {
|
|
519
|
+
const style = new Style(getStubMap());
|
|
520
|
+
let dispatchType: MessageType;
|
|
521
|
+
let dispatchData;
|
|
522
|
+
const styleSpec = createStyleJSON({
|
|
523
|
+
layers: [{
|
|
524
|
+
id: 'background',
|
|
525
|
+
type: 'background'
|
|
526
|
+
}]
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
const _broadcastSpyOn = jest.spyOn(style.dispatcher, 'broadcast')
|
|
530
|
+
.mockImplementation((type, data) => {
|
|
531
|
+
dispatchType = type;
|
|
532
|
+
dispatchData = data;
|
|
533
|
+
return Promise.resolve({} as any);
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
style._load(styleSpec, {});
|
|
537
|
+
|
|
538
|
+
expect(_broadcastSpyOn).toHaveBeenCalled();
|
|
539
|
+
expect(dispatchType).toBe(MessageType.setLayers);
|
|
540
|
+
|
|
541
|
+
expect(dispatchData).toHaveLength(1);
|
|
542
|
+
expect(dispatchData[0].id).toBe('background');
|
|
543
|
+
|
|
544
|
+
// cleanup
|
|
545
|
+
_broadcastSpyOn.mockRestore();
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
test('validate style when validate option is true', () => {
|
|
549
|
+
const style = new Style(getStubMap());
|
|
550
|
+
const styleSpec = createStyleJSON({
|
|
551
|
+
layers: [{
|
|
552
|
+
id: 'background',
|
|
553
|
+
type: 'background'
|
|
554
|
+
}, {
|
|
555
|
+
id: 'custom',
|
|
556
|
+
type: 'custom'
|
|
557
|
+
}]
|
|
558
|
+
});
|
|
559
|
+
const stub = jest.spyOn(console, 'error');
|
|
560
|
+
|
|
561
|
+
style._load(styleSpec, {validate: true});
|
|
562
|
+
|
|
563
|
+
// 1. layers[1]: missing required property "source"
|
|
564
|
+
// 2. layers[1].type: expected one of [fill, line, symbol, circle, heatmap, fill-extrusion, raster, hillshade, background], "custom" found
|
|
565
|
+
expect(stub).toHaveBeenCalledTimes(2);
|
|
566
|
+
|
|
567
|
+
// cleanup
|
|
568
|
+
stub.mockReset();
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
test('layers are NOT serialized immediately after creation', () => {
|
|
572
|
+
const style = new Style(getStubMap());
|
|
573
|
+
const styleSpec = createStyleJSON({
|
|
574
|
+
layers: [{
|
|
575
|
+
id: 'background',
|
|
576
|
+
type: 'background'
|
|
577
|
+
}, {
|
|
578
|
+
id: 'custom',
|
|
579
|
+
type: 'custom'
|
|
580
|
+
}]
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
style._load(styleSpec, {validate: false});
|
|
584
|
+
expect(style._serializedLayers).toBeNull();
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
describe('Style#_remove', () => {
|
|
589
|
+
test('removes cache sources and clears their tiles', async () => {
|
|
590
|
+
const style = new Style(getStubMap());
|
|
591
|
+
style.loadJSON(createStyleJSON({
|
|
592
|
+
sources: {'source-id': createGeoJSONSource()}
|
|
593
|
+
}));
|
|
594
|
+
|
|
595
|
+
await style.once('style.load');
|
|
596
|
+
const sourceCache = style.sourceCaches['source-id'];
|
|
597
|
+
jest.spyOn(sourceCache, 'setEventedParent');
|
|
598
|
+
jest.spyOn(sourceCache, 'onRemove');
|
|
599
|
+
jest.spyOn(sourceCache, 'clearTiles');
|
|
600
|
+
|
|
601
|
+
style._remove();
|
|
602
|
+
|
|
603
|
+
expect(sourceCache.setEventedParent).toHaveBeenCalledWith(null);
|
|
604
|
+
expect(sourceCache.onRemove).toHaveBeenCalledWith(style.map);
|
|
605
|
+
expect(sourceCache.clearTiles).toHaveBeenCalled();
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
test('deregisters plugin listener', async () => {
|
|
609
|
+
const style = new Style(getStubMap());
|
|
610
|
+
style.loadJSON(createStyleJSON());
|
|
611
|
+
jest.spyOn(rtlMainThreadPluginFactory(), 'off');
|
|
612
|
+
|
|
613
|
+
await style.once('style.load');
|
|
614
|
+
style._remove();
|
|
615
|
+
|
|
616
|
+
expect(rtlMainThreadPluginFactory().off).toHaveBeenCalled();
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
describe('Style#update', () => {
|
|
621
|
+
test('on error', () => new Promise<void>(done => {
|
|
622
|
+
const style = createStyle();
|
|
623
|
+
style.loadJSON({
|
|
624
|
+
'version': 8,
|
|
625
|
+
'sources': {
|
|
626
|
+
'source': {
|
|
627
|
+
'type': 'vector'
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
'layers': [{
|
|
631
|
+
'id': 'second',
|
|
632
|
+
'source': 'source',
|
|
633
|
+
'source-layer': 'source-layer',
|
|
634
|
+
'type': 'fill'
|
|
635
|
+
}]
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
style.on('error', (error) => { expect(error).toBeFalsy(); });
|
|
639
|
+
|
|
640
|
+
style.on('style.load', () => {
|
|
641
|
+
style.addLayer({id: 'first', source: 'source', type: 'fill', 'source-layer': 'source-layer'}, 'second');
|
|
642
|
+
style.addLayer({id: 'third', source: 'source', type: 'fill', 'source-layer': 'source-layer'});
|
|
643
|
+
style.removeLayer('second');
|
|
644
|
+
|
|
645
|
+
style.dispatcher.broadcast = (key, value) => {
|
|
646
|
+
expect(key).toBe(MessageType.updateLayers);
|
|
647
|
+
expect(value['layers'].map((layer) => { return layer.id; })).toEqual(['first', 'third']);
|
|
648
|
+
expect(value['removedIds']).toEqual(['second']);
|
|
649
|
+
done();
|
|
650
|
+
return Promise.resolve({} as any);
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
style.update({} as EvaluationParameters);
|
|
654
|
+
});
|
|
655
|
+
}));
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
describe('Style#setState', () => {
|
|
659
|
+
test('throw before loaded', () => {
|
|
660
|
+
const style = new Style(getStubMap());
|
|
661
|
+
expect(() => style.setState(createStyleJSON())).toThrow(/load/i);
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
test('do nothing if there are no changes', async () => {
|
|
665
|
+
const style = createStyle();
|
|
666
|
+
style.loadJSON(createStyleJSON());
|
|
667
|
+
const spys = [];
|
|
668
|
+
spys.push(jest.spyOn(style, 'addLayer').mockImplementation((() => {}) as any));
|
|
669
|
+
spys.push(jest.spyOn(style, 'removeLayer').mockImplementation((() => {}) as any));
|
|
670
|
+
spys.push(jest.spyOn(style, 'setPaintProperty').mockImplementation((() => {}) as any));
|
|
671
|
+
spys.push(jest.spyOn(style, 'setLayoutProperty').mockImplementation((() => {}) as any));
|
|
672
|
+
spys.push(jest.spyOn(style, 'setFilter').mockImplementation((() => {}) as any));
|
|
673
|
+
spys.push(jest.spyOn(style, 'addSource').mockImplementation((() => {}) as any));
|
|
674
|
+
spys.push(jest.spyOn(style, 'removeSource').mockImplementation((() => {}) as any));
|
|
675
|
+
spys.push(jest.spyOn(style, 'setGeoJSONSourceData').mockImplementation((() => {}) as any));
|
|
676
|
+
spys.push(jest.spyOn(style, 'setLayerZoomRange').mockImplementation((() => {}) as any));
|
|
677
|
+
spys.push(jest.spyOn(style, 'setLight').mockImplementation((() => {}) as any));
|
|
678
|
+
await style.once('style.load');
|
|
679
|
+
const didChange = style.setState(createStyleJSON());
|
|
680
|
+
expect(didChange).toBeFalsy();
|
|
681
|
+
for (const spy of spys) {
|
|
682
|
+
expect(spy).not.toHaveBeenCalled();
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
test('do operations if there are changes', async () => {
|
|
687
|
+
const style = createStyle();
|
|
688
|
+
const styleJson = createStyleJSON({
|
|
689
|
+
layers: [{
|
|
690
|
+
id: 'layerId0',
|
|
691
|
+
type: 'symbol',
|
|
692
|
+
source: 'sourceId0',
|
|
693
|
+
'source-layer': '123'
|
|
694
|
+
}, {
|
|
695
|
+
id: 'layerId1',
|
|
696
|
+
type: 'circle',
|
|
697
|
+
source: 'sourceId1',
|
|
698
|
+
'source-layer': ''
|
|
699
|
+
}],
|
|
700
|
+
sources: {
|
|
701
|
+
sourceId0: createGeoJSONSource(),
|
|
702
|
+
sourceId1: createGeoJSONSource(),
|
|
703
|
+
},
|
|
704
|
+
light: {
|
|
705
|
+
anchor: 'viewport'
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
style.loadJSON(styleJson);
|
|
709
|
+
|
|
710
|
+
await style.once('style.load');
|
|
711
|
+
const spys = [];
|
|
712
|
+
spys.push(jest.spyOn(style, 'addLayer').mockImplementation((() => {}) as any));
|
|
713
|
+
spys.push(jest.spyOn(style, 'removeLayer').mockImplementation((() => {}) as any));
|
|
714
|
+
spys.push(jest.spyOn(style, 'setPaintProperty').mockImplementation((() => {}) as any));
|
|
715
|
+
spys.push(jest.spyOn(style, 'setLayoutProperty').mockImplementation((() => {}) as any));
|
|
716
|
+
spys.push(jest.spyOn(style, 'setFilter').mockImplementation((() => {}) as any));
|
|
717
|
+
spys.push(jest.spyOn(style, 'addSource').mockImplementation((() => {}) as any));
|
|
718
|
+
spys.push(jest.spyOn(style, 'removeSource').mockImplementation((() => {}) as any));
|
|
719
|
+
spys.push(jest.spyOn(style, 'setLayerZoomRange').mockImplementation((() => {}) as any));
|
|
720
|
+
spys.push(jest.spyOn(style, 'setLight').mockImplementation((() => {}) as any));
|
|
721
|
+
spys.push(jest.spyOn(style, 'setGeoJSONSourceData').mockImplementation((() => {}) as any));
|
|
722
|
+
spys.push(jest.spyOn(style, 'setGlyphs').mockImplementation((() => {}) as any));
|
|
723
|
+
spys.push(jest.spyOn(style, 'setSprite').mockImplementation((() => {}) as any));
|
|
724
|
+
spys.push(jest.spyOn(style, 'setSky').mockImplementation((() => {}) as any));
|
|
725
|
+
spys.push(jest.spyOn(style.map, 'setTerrain').mockImplementation((() => {}) as any));
|
|
726
|
+
|
|
727
|
+
const newStyle = JSON.parse(JSON.stringify(styleJson)) as StyleSpecification;
|
|
728
|
+
newStyle.layers[0].paint = {'text-color': '#7F7F7F',};
|
|
729
|
+
newStyle.layers[0].layout = {'text-size': 16,};
|
|
730
|
+
newStyle.layers[0].minzoom = 2;
|
|
731
|
+
(newStyle.layers[0] as SymbolLayerSpecification).filter = ['==', 'id', 1];
|
|
732
|
+
newStyle.layers.splice(1, 1);
|
|
733
|
+
newStyle.sources['foo'] = createSource();
|
|
734
|
+
delete newStyle.sources['sourceId1'];
|
|
735
|
+
newStyle.light = {
|
|
736
|
+
anchor: 'map'
|
|
737
|
+
};
|
|
738
|
+
newStyle.layers.push({
|
|
739
|
+
id: 'layerId2',
|
|
740
|
+
type: 'circle',
|
|
741
|
+
source: 'sourceId0'
|
|
742
|
+
});
|
|
743
|
+
((newStyle.sources.sourceId0 as GeoJSONSourceSpecification).data as GeoJSON.FeatureCollection).features.push({} as any);
|
|
744
|
+
|
|
745
|
+
newStyle.glyphs = 'https://example.com/{fontstack}/{range}.pbf';
|
|
746
|
+
newStyle.sprite = 'https://example.com';
|
|
747
|
+
|
|
748
|
+
newStyle.terrain = {
|
|
749
|
+
source: 'foo',
|
|
750
|
+
exaggeration: 0.5
|
|
751
|
+
};
|
|
752
|
+
newStyle.zoom = 2;
|
|
753
|
+
newStyle.sky = {
|
|
754
|
+
'fog-color': '#000001',
|
|
755
|
+
'sky-color': '#000002',
|
|
756
|
+
'horizon-fog-blend': 0.5,
|
|
757
|
+
};
|
|
758
|
+
const didChange = style.setState(newStyle);
|
|
759
|
+
expect(didChange).toBeTruthy();
|
|
760
|
+
for (const spy of spys) {
|
|
761
|
+
expect(spy).toHaveBeenCalled();
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
test('change transition doesn\'t change the style, but is considered a change', async () => {
|
|
766
|
+
const style = createStyle();
|
|
767
|
+
const styleJson = createStyleJSON();
|
|
768
|
+
style.loadJSON(styleJson);
|
|
769
|
+
|
|
770
|
+
await style.once('style.load');
|
|
771
|
+
const spys = [];
|
|
772
|
+
spys.push(jest.spyOn(style, 'addLayer').mockImplementation((() => {}) as any));
|
|
773
|
+
spys.push(jest.spyOn(style, 'removeLayer').mockImplementation((() => {}) as any));
|
|
774
|
+
spys.push(jest.spyOn(style, 'setPaintProperty').mockImplementation((() => {}) as any));
|
|
775
|
+
spys.push(jest.spyOn(style, 'setLayoutProperty').mockImplementation((() => {}) as any));
|
|
776
|
+
spys.push(jest.spyOn(style, 'setFilter').mockImplementation((() => {}) as any));
|
|
777
|
+
spys.push(jest.spyOn(style, 'addSource').mockImplementation((() => {}) as any));
|
|
778
|
+
spys.push(jest.spyOn(style, 'removeSource').mockImplementation((() => {}) as any));
|
|
779
|
+
spys.push(jest.spyOn(style, 'setLayerZoomRange').mockImplementation((() => {}) as any));
|
|
780
|
+
spys.push(jest.spyOn(style, 'setLight').mockImplementation((() => {}) as any));
|
|
781
|
+
spys.push(jest.spyOn(style, 'setGeoJSONSourceData').mockImplementation((() => {}) as any));
|
|
782
|
+
spys.push(jest.spyOn(style, 'setGlyphs').mockImplementation((() => {}) as any));
|
|
783
|
+
spys.push(jest.spyOn(style, 'setSprite').mockImplementation((() => {}) as any));
|
|
784
|
+
spys.push(jest.spyOn(style.map, 'setTerrain').mockImplementation((() => {}) as any));
|
|
785
|
+
|
|
786
|
+
const newStyleJson = createStyleJSON();
|
|
787
|
+
newStyleJson.transition = {duration: 5};
|
|
788
|
+
const didChange = style.setState(newStyleJson);
|
|
789
|
+
expect(didChange).toBeTruthy();
|
|
790
|
+
for (const spy of spys) {
|
|
791
|
+
expect(spy).not.toHaveBeenCalled();
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
test('Issue #3893: compare new source options against originally provided options rather than normalized properties', async () => {
|
|
796
|
+
server.respondWith('/tilejson.json', JSON.stringify({
|
|
797
|
+
tiles: ['http://tiles.server']
|
|
798
|
+
}));
|
|
799
|
+
const initial = createStyleJSON();
|
|
800
|
+
initial.sources.mySource = {
|
|
801
|
+
type: 'raster',
|
|
802
|
+
url: '/tilejson.json'
|
|
803
|
+
};
|
|
804
|
+
const style = new Style(getStubMap());
|
|
805
|
+
style.loadJSON(initial);
|
|
806
|
+
const promise = style.once('style.load');
|
|
807
|
+
server.respond();
|
|
808
|
+
await promise;
|
|
809
|
+
const spyRemove = jest.spyOn(style, 'removeSource').mockImplementation((() => {}) as any);
|
|
810
|
+
const spyAdd = jest.spyOn(style, 'addSource').mockImplementation((() => {}) as any);
|
|
811
|
+
style.setState(initial);
|
|
812
|
+
expect(spyRemove).not.toHaveBeenCalled();
|
|
813
|
+
expect(spyAdd).not.toHaveBeenCalled();
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
test('return true if there is a change', async () => {
|
|
817
|
+
const initialState = createStyleJSON();
|
|
818
|
+
const nextState = createStyleJSON({
|
|
819
|
+
sources: {
|
|
820
|
+
foo: {
|
|
821
|
+
type: 'geojson',
|
|
822
|
+
data: {type: 'FeatureCollection', features: []}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
const style = new Style(getStubMap());
|
|
828
|
+
style.loadJSON(initialState);
|
|
829
|
+
await style.once('style.load');
|
|
830
|
+
const didChange = style.setState(nextState);
|
|
831
|
+
expect(didChange).toBeTruthy();
|
|
832
|
+
expect(style.stylesheet).toEqual(nextState);
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
test('sets GeoJSON source data if different', async () => {
|
|
836
|
+
const initialState = createStyleJSON({
|
|
837
|
+
'sources': {'source-id': createGeoJSONSource()}
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
const geoJSONSourceData = {
|
|
841
|
+
'type': 'FeatureCollection',
|
|
842
|
+
'features': [
|
|
843
|
+
{
|
|
844
|
+
'type': 'Feature',
|
|
845
|
+
'geometry': {
|
|
846
|
+
'type': 'Point',
|
|
847
|
+
'coordinates': [125.6, 10.1]
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
]
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
const nextState = createStyleJSON({
|
|
854
|
+
'sources': {
|
|
855
|
+
'source-id': {
|
|
856
|
+
'type': 'geojson',
|
|
857
|
+
'data': geoJSONSourceData
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
const style = new Style(getStubMap());
|
|
863
|
+
style.loadJSON(initialState);
|
|
864
|
+
|
|
865
|
+
await style.once('style.load');
|
|
866
|
+
const geoJSONSource = style.sourceCaches['source-id'].getSource() as GeoJSONSource;
|
|
867
|
+
const mockStyleSetGeoJSONSourceDate = jest.spyOn(style, 'setGeoJSONSourceData');
|
|
868
|
+
const mockGeoJSONSourceSetData = jest.spyOn(geoJSONSource, 'setData');
|
|
869
|
+
const didChange = style.setState(nextState);
|
|
870
|
+
|
|
871
|
+
expect(mockStyleSetGeoJSONSourceDate).toHaveBeenCalledWith('source-id', geoJSONSourceData);
|
|
872
|
+
expect(mockGeoJSONSourceSetData).toHaveBeenCalledWith(geoJSONSourceData);
|
|
873
|
+
expect(didChange).toBeTruthy();
|
|
874
|
+
expect(style.stylesheet).toEqual(nextState);
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
test('updates stylesheet according to applied transformStyle function', async () => {
|
|
878
|
+
const initialState = createStyleJSON({
|
|
879
|
+
sources: {
|
|
880
|
+
base: {
|
|
881
|
+
type: 'geojson',
|
|
882
|
+
data: {type: 'FeatureCollection', features: []}
|
|
883
|
+
}
|
|
884
|
+
},
|
|
885
|
+
layers: [{
|
|
886
|
+
id: 'layerId0',
|
|
887
|
+
type: 'circle',
|
|
888
|
+
source: 'base'
|
|
889
|
+
}, {
|
|
890
|
+
id: 'layerId1',
|
|
891
|
+
type: 'circle',
|
|
892
|
+
source: 'base'
|
|
893
|
+
}]
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
const nextState = createStyleJSON();
|
|
897
|
+
const style = new Style(getStubMap());
|
|
898
|
+
style.loadJSON(initialState);
|
|
899
|
+
|
|
900
|
+
await style.once('style.load');
|
|
901
|
+
const didChange = style.setState(nextState, {
|
|
902
|
+
transformStyle: (prevStyle, nextStyle) => ({
|
|
903
|
+
...nextStyle,
|
|
904
|
+
sources: {
|
|
905
|
+
...nextStyle.sources,
|
|
906
|
+
base: prevStyle.sources.base
|
|
907
|
+
},
|
|
908
|
+
layers: [
|
|
909
|
+
...nextStyle.layers,
|
|
910
|
+
prevStyle.layers[0]
|
|
911
|
+
]
|
|
912
|
+
})
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
expect(didChange).toBeTruthy();
|
|
916
|
+
expect('base' in style.stylesheet.sources).toBeTruthy();
|
|
917
|
+
expect(style.stylesheet.layers[0].id).toBe(initialState.layers[0].id);
|
|
918
|
+
expect(style.stylesheet.layers).toHaveLength(1);
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
test('Style#setState skips validateStyle when validate false', async () => {
|
|
922
|
+
const style = new Style(getStubMap());
|
|
923
|
+
const styleSpec = createStyleJSON();
|
|
924
|
+
style.loadJSON(styleSpec);
|
|
925
|
+
|
|
926
|
+
await style.once('style.load');
|
|
927
|
+
|
|
928
|
+
style.addSource('abc', createSource());
|
|
929
|
+
const nextState = {...styleSpec};
|
|
930
|
+
nextState.sources['def'] = {type: 'geojson'} as GeoJSONSourceSpecification;
|
|
931
|
+
|
|
932
|
+
const didChange = style.setState(nextState, {validate: false});
|
|
933
|
+
|
|
934
|
+
expect(didChange).toBeTruthy();
|
|
935
|
+
});
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
describe('Style#addSource', () => {
|
|
939
|
+
test('throw before loaded', () => {
|
|
940
|
+
const style = new Style(getStubMap());
|
|
941
|
+
expect(() => style.addSource('source-id', createSource())).toThrow(/load/i);
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
test('throw if missing source type', async () => {
|
|
945
|
+
const style = new Style(getStubMap());
|
|
946
|
+
style.loadJSON(createStyleJSON());
|
|
947
|
+
|
|
948
|
+
const source = createSource();
|
|
949
|
+
delete source.type;
|
|
950
|
+
|
|
951
|
+
await style.once('style.load');
|
|
952
|
+
|
|
953
|
+
expect(() => style.addSource('source-id', source)).toThrow(/type/i);
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
test('fires "data" event', async () => {
|
|
957
|
+
const style = createStyle();
|
|
958
|
+
style.loadJSON(createStyleJSON());
|
|
959
|
+
const source = createSource();
|
|
960
|
+
const dataPromise = style.once('data');
|
|
961
|
+
style.on('style.load', () => {
|
|
962
|
+
style.addSource('source-id', source);
|
|
963
|
+
style.update({} as EvaluationParameters);
|
|
964
|
+
});
|
|
965
|
+
await dataPromise;
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
test('throws on duplicates', async () => {
|
|
969
|
+
const style = createStyle();
|
|
970
|
+
style.loadJSON(createStyleJSON());
|
|
971
|
+
const source = createSource();
|
|
972
|
+
await style.once('style.load');
|
|
973
|
+
style.addSource('source-id', source);
|
|
974
|
+
expect(() => {
|
|
975
|
+
style.addSource('source-id', source);
|
|
976
|
+
}).toThrow(/Source "source-id" already exists./);
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
test('sets up source event forwarding', async () => {
|
|
980
|
+
const promisesResolve = {} as any;
|
|
981
|
+
const promises = [
|
|
982
|
+
new Promise((resolve) => { promisesResolve.error = resolve; }),
|
|
983
|
+
new Promise((resolve) => { promisesResolve.metadata = resolve; }),
|
|
984
|
+
new Promise((resolve) => { promisesResolve.content = resolve; }),
|
|
985
|
+
new Promise((resolve) => { promisesResolve.other = resolve; }),
|
|
986
|
+
];
|
|
987
|
+
|
|
988
|
+
const style = createStyle();
|
|
989
|
+
style.loadJSON(createStyleJSON({
|
|
990
|
+
layers: [{
|
|
991
|
+
id: 'background',
|
|
992
|
+
type: 'background'
|
|
993
|
+
}]
|
|
994
|
+
}));
|
|
995
|
+
const source = createSource();
|
|
996
|
+
|
|
997
|
+
await style.once('style.load');
|
|
998
|
+
style.on('error', () => {
|
|
999
|
+
promisesResolve.error();
|
|
1000
|
+
});
|
|
1001
|
+
style.on('data', (e) => {
|
|
1002
|
+
if (e.sourceDataType === 'metadata' && e.dataType === 'source') {
|
|
1003
|
+
promisesResolve.metadata();
|
|
1004
|
+
} else if (e.sourceDataType === 'content' && e.dataType === 'source') {
|
|
1005
|
+
promisesResolve.content();
|
|
1006
|
+
} else {
|
|
1007
|
+
promisesResolve.other();
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
|
|
1011
|
+
style.addSource('source-id', source); // fires data twice
|
|
1012
|
+
style.sourceCaches['source-id'].fire(new Event('error'));
|
|
1013
|
+
style.sourceCaches['source-id'].fire(new Event('data'));
|
|
1014
|
+
|
|
1015
|
+
await expect(Promise.all(promises)).resolves.toBeDefined();
|
|
1016
|
+
});
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
describe('Style#removeSource', () => {
|
|
1020
|
+
test('throw before loaded', () => {
|
|
1021
|
+
const style = new Style(getStubMap());
|
|
1022
|
+
expect(() => style.removeSource('source-id')).toThrow(/load/i);
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
test('fires "data" event', async () => {
|
|
1026
|
+
const style = new Style(getStubMap());
|
|
1027
|
+
style.loadJSON(createStyleJSON());
|
|
1028
|
+
const source = createSource();
|
|
1029
|
+
const dataPromise = style.once('data');
|
|
1030
|
+
style.on('style.load', () => {
|
|
1031
|
+
style.addSource('source-id', source);
|
|
1032
|
+
style.removeSource('source-id');
|
|
1033
|
+
style.update({} as EvaluationParameters);
|
|
1034
|
+
});
|
|
1035
|
+
await dataPromise;
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
test('clears tiles', async () => {
|
|
1039
|
+
const style = new Style(getStubMap());
|
|
1040
|
+
style.loadJSON(createStyleJSON({
|
|
1041
|
+
sources: {'source-id': createGeoJSONSource()}
|
|
1042
|
+
}));
|
|
1043
|
+
|
|
1044
|
+
await style.once('style.load');
|
|
1045
|
+
const sourceCache = style.sourceCaches['source-id'];
|
|
1046
|
+
jest.spyOn(sourceCache, 'clearTiles');
|
|
1047
|
+
style.removeSource('source-id');
|
|
1048
|
+
expect(sourceCache.clearTiles).toHaveBeenCalledTimes(1);
|
|
1049
|
+
});
|
|
1050
|
+
|
|
1051
|
+
test('throws on non-existence', async () => {
|
|
1052
|
+
const style = new Style(getStubMap());
|
|
1053
|
+
style.loadJSON(createStyleJSON());
|
|
1054
|
+
await style.once('style.load');
|
|
1055
|
+
expect(() => {
|
|
1056
|
+
style.removeSource('source-id');
|
|
1057
|
+
}).toThrow(/There is no source with this ID/);
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1060
|
+
async function createStyleAndLoad(): Promise<Style> {
|
|
1061
|
+
const style = new Style(getStubMap());
|
|
1062
|
+
style.loadJSON(createStyleJSON({
|
|
1063
|
+
'sources': {
|
|
1064
|
+
'mapLibre-source': createGeoJSONSource()
|
|
1065
|
+
},
|
|
1066
|
+
'layers': [{
|
|
1067
|
+
'id': 'mapLibre-layer',
|
|
1068
|
+
'type': 'circle',
|
|
1069
|
+
'source': 'mapLibre-source',
|
|
1070
|
+
'source-layer': 'whatever'
|
|
1071
|
+
}]
|
|
1072
|
+
}));
|
|
1073
|
+
await style.once('style.load');
|
|
1074
|
+
style.update(1 as any as EvaluationParameters);
|
|
1075
|
+
return style;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
test('throws if source is in use', async () => {
|
|
1079
|
+
const style = await createStyleAndLoad();
|
|
1080
|
+
const promise = style.once('error');
|
|
1081
|
+
style.removeSource('mapLibre-source');
|
|
1082
|
+
const event = await promise;
|
|
1083
|
+
expect(event.error.message.includes('"mapLibre-source"')).toBeTruthy();
|
|
1084
|
+
expect(event.error.message.includes('"mapLibre-layer"')).toBeTruthy();
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
test('does not throw if source is not in use', async () => {
|
|
1088
|
+
const style = await createStyleAndLoad();
|
|
1089
|
+
const promise = style.once('error');
|
|
1090
|
+
style.removeLayer('mapLibre-layer');
|
|
1091
|
+
style.removeSource('mapLibre-source');
|
|
1092
|
+
await expect(Promise.any([promise, sleep(100)])).resolves.toBeUndefined();
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
test('tears down source event forwarding', async () => {
|
|
1096
|
+
const style = new Style(getStubMap());
|
|
1097
|
+
style.loadJSON(createStyleJSON());
|
|
1098
|
+
const source = createSource();
|
|
1099
|
+
|
|
1100
|
+
await style.once('style.load');
|
|
1101
|
+
style.addSource('source-id', source);
|
|
1102
|
+
const sourceCache = style.sourceCaches['source-id'];
|
|
1103
|
+
|
|
1104
|
+
style.removeSource('source-id');
|
|
1105
|
+
|
|
1106
|
+
// Suppress error reporting
|
|
1107
|
+
sourceCache.on('error', () => {});
|
|
1108
|
+
|
|
1109
|
+
style.on('data', () => { expect(false).toBeTruthy(); });
|
|
1110
|
+
style.on('error', () => { expect(false).toBeTruthy(); });
|
|
1111
|
+
sourceCache.fire(new Event('data'));
|
|
1112
|
+
sourceCache.fire(new Event('error'));
|
|
1113
|
+
});
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
describe('Style#addSprite', () => {
|
|
1117
|
+
test('throw before loaded', () => {
|
|
1118
|
+
const style = new Style(getStubMap());
|
|
1119
|
+
expect(() => style.addSprite('test', 'https://example.com/sprite')).toThrow(/load/i);
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
test('validates input and fires an error if there\'s already an existing sprite with the same id', async () => {
|
|
1123
|
+
const style = new Style(getStubMap());
|
|
1124
|
+
style.loadJSON(createStyleJSON());
|
|
1125
|
+
await style.once('style.load');
|
|
1126
|
+
const promise = style.once('error');
|
|
1127
|
+
style.addSprite('test', 'https://example.com/sprite');
|
|
1128
|
+
style.addSprite('test', 'https://example.com/sprite2');
|
|
1129
|
+
const error = await promise;
|
|
1130
|
+
expect(error.error.message).toMatch(/sprite: all the sprites' ids must be unique, but test is duplicated/);
|
|
1131
|
+
});
|
|
1132
|
+
|
|
1133
|
+
test('adds a new sprite to the stylesheet when there\'s no sprite at all', async () => {
|
|
1134
|
+
const style = new Style(getStubMap());
|
|
1135
|
+
style.loadJSON(createStyleJSON());
|
|
1136
|
+
await style.once('style.load');
|
|
1137
|
+
style.addSprite('test', 'https://example.com/sprite');
|
|
1138
|
+
expect(style.stylesheet.sprite).toStrictEqual([{id: 'test', url: 'https://example.com/sprite'}]);
|
|
1139
|
+
});
|
|
1140
|
+
|
|
1141
|
+
test('adds a new sprite to the stylesheet when there\'s a stringy sprite existing', async () => {
|
|
1142
|
+
const style = new Style(getStubMap());
|
|
1143
|
+
style.loadJSON(createStyleJSON({sprite: 'https://example.com/default'}));
|
|
1144
|
+
await style.once('style.load');
|
|
1145
|
+
style.addSprite('test', 'https://example.com/sprite');
|
|
1146
|
+
expect(style.stylesheet.sprite).toStrictEqual([
|
|
1147
|
+
{id: 'default', url: 'https://example.com/default'},
|
|
1148
|
+
{id: 'test', url: 'https://example.com/sprite'}
|
|
1149
|
+
]);
|
|
1150
|
+
});
|
|
1151
|
+
|
|
1152
|
+
test('adds a new sprite to the stylesheet when there\'s an array-sprite existing', async () => {
|
|
1153
|
+
const style = new Style(getStubMap());
|
|
1154
|
+
style.loadJSON(createStyleJSON({sprite: [{id: 'default', url: 'https://example.com/default'}]}));
|
|
1155
|
+
await style.once('style.load');
|
|
1156
|
+
style.addSprite('test', 'https://example.com/sprite');
|
|
1157
|
+
expect(style.stylesheet.sprite).toStrictEqual([
|
|
1158
|
+
{id: 'default', url: 'https://example.com/default'},
|
|
1159
|
+
{id: 'test', url: 'https://example.com/sprite'}
|
|
1160
|
+
]);
|
|
1161
|
+
});
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
describe('Style#removeSprite', () => {
|
|
1165
|
+
test('throw before loaded', () => {
|
|
1166
|
+
const style = new Style(getStubMap());
|
|
1167
|
+
expect(() => style.removeSprite('test')).toThrow(/load/i);
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
test('fires an error when trying to delete an non-existing sprite (sprite: undefined)', () => new Promise<void>(done => {
|
|
1171
|
+
const style = new Style(getStubMap());
|
|
1172
|
+
style.loadJSON(createStyleJSON());
|
|
1173
|
+
style.on('style.load', () => {
|
|
1174
|
+
style.on('error', (error) => {
|
|
1175
|
+
expect(error.error.message).toMatch(/Sprite \"test\" doesn't exists on this map./);
|
|
1176
|
+
done();
|
|
1177
|
+
});
|
|
1178
|
+
|
|
1179
|
+
style.removeSprite('test');
|
|
1180
|
+
});
|
|
1181
|
+
}));
|
|
1182
|
+
|
|
1183
|
+
test('fires an error when trying to delete an non-existing sprite (sprite: single url)', () => new Promise<void>(done => {
|
|
1184
|
+
const style = new Style(getStubMap());
|
|
1185
|
+
style.loadJSON(createStyleJSON({sprite: 'https://example.com/sprite'}));
|
|
1186
|
+
style.on('style.load', () => {
|
|
1187
|
+
style.on('error', (error) => {
|
|
1188
|
+
expect(error.error.message).toMatch(/Sprite \"test\" doesn't exists on this map./);
|
|
1189
|
+
done();
|
|
1190
|
+
});
|
|
1191
|
+
|
|
1192
|
+
style.removeSprite('test');
|
|
1193
|
+
});
|
|
1194
|
+
}));
|
|
1195
|
+
|
|
1196
|
+
test('fires an error when trying to delete an non-existing sprite (sprite: array)', () => new Promise<void>(done => {
|
|
1197
|
+
const style = new Style(getStubMap());
|
|
1198
|
+
style.loadJSON(createStyleJSON({sprite: [{id: 'default', url: 'https://example.com/sprite'}]}));
|
|
1199
|
+
style.on('style.load', () => {
|
|
1200
|
+
style.on('error', (error) => {
|
|
1201
|
+
expect(error.error.message).toMatch(/Sprite \"test\" doesn't exists on this map./);
|
|
1202
|
+
done();
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
style.removeSprite('test');
|
|
1206
|
+
});
|
|
1207
|
+
}));
|
|
1208
|
+
|
|
1209
|
+
test('removes the sprite when it\'s a single URL', async () => {
|
|
1210
|
+
const style = new Style(getStubMap());
|
|
1211
|
+
style.loadJSON(createStyleJSON({sprite: 'https://example.com/test'}));
|
|
1212
|
+
await style.once('style.load');
|
|
1213
|
+
style.removeSprite('default');
|
|
1214
|
+
expect(style.stylesheet.sprite).toBeUndefined();
|
|
1215
|
+
});
|
|
1216
|
+
|
|
1217
|
+
test('removes the sprite when it\'s an array', async () => {
|
|
1218
|
+
const style = new Style(getStubMap());
|
|
1219
|
+
style.loadJSON(createStyleJSON([{id: 'default', url: 'https://example.com/sprite'}]));
|
|
1220
|
+
await style.once('style.load');
|
|
1221
|
+
style.removeSprite('default');
|
|
1222
|
+
expect(style.stylesheet.sprite).toBeUndefined();
|
|
1223
|
+
});
|
|
1224
|
+
});
|
|
1225
|
+
|
|
1226
|
+
describe('Style#setGeoJSONSourceData', () => {
|
|
1227
|
+
const geoJSON = {type: 'FeatureCollection', features: []} as GeoJSON.GeoJSON;
|
|
1228
|
+
|
|
1229
|
+
test('throws before loaded', () => {
|
|
1230
|
+
const style = new Style(getStubMap());
|
|
1231
|
+
expect(() => style.setGeoJSONSourceData('source-id', geoJSON)).toThrow(/load/i);
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
test('throws on non-existence', async () => {
|
|
1235
|
+
const style = new Style(getStubMap());
|
|
1236
|
+
style.loadJSON(createStyleJSON());
|
|
1237
|
+
await style.once('style.load');
|
|
1238
|
+
expect(() => style.setGeoJSONSourceData('source-id', geoJSON)).toThrow(/There is no source with this ID/);
|
|
1239
|
+
});
|
|
1240
|
+
});
|
|
1241
|
+
|
|
1242
|
+
describe('Style#addLayer', () => {
|
|
1243
|
+
test('throw before loaded', () => {
|
|
1244
|
+
const style = new Style(getStubMap());
|
|
1245
|
+
expect(() => style.addLayer({id: 'background', type: 'background'})).toThrow(/load/i);
|
|
1246
|
+
});
|
|
1247
|
+
|
|
1248
|
+
test('sets up layer event forwarding', () => new Promise<void>(done => {
|
|
1249
|
+
const style = new Style(getStubMap());
|
|
1250
|
+
style.loadJSON(createStyleJSON());
|
|
1251
|
+
|
|
1252
|
+
style.on('error', (e) => {
|
|
1253
|
+
expect(e.layer).toEqual({id: 'background'});
|
|
1254
|
+
expect(e.mapLibre).toBeTruthy();
|
|
1255
|
+
done();
|
|
1256
|
+
});
|
|
1257
|
+
|
|
1258
|
+
style.on('style.load', () => {
|
|
1259
|
+
style.addLayer({
|
|
1260
|
+
id: 'background',
|
|
1261
|
+
type: 'background'
|
|
1262
|
+
});
|
|
1263
|
+
style._layers.background.fire(new Event('error', {mapLibre: true}));
|
|
1264
|
+
});
|
|
1265
|
+
}));
|
|
1266
|
+
|
|
1267
|
+
test('throws on non-existant vector source layer', () => new Promise<void>(done => {
|
|
1268
|
+
const style = createStyle();
|
|
1269
|
+
style.loadJSON(createStyleJSON({
|
|
1270
|
+
sources: {
|
|
1271
|
+
// At least one source must be added to trigger the load event
|
|
1272
|
+
dummy: {type: 'vector', tiles: []}
|
|
1273
|
+
}
|
|
1274
|
+
}));
|
|
1275
|
+
|
|
1276
|
+
style.on('style.load', () => {
|
|
1277
|
+
const source = createSource();
|
|
1278
|
+
source['vector_layers'] = [{id: 'green'}];
|
|
1279
|
+
style.addSource('-source-id-', source);
|
|
1280
|
+
style.addLayer({
|
|
1281
|
+
'id': '-layer-id-',
|
|
1282
|
+
'type': 'circle',
|
|
1283
|
+
'source': '-source-id-',
|
|
1284
|
+
'source-layer': '-source-layer-'
|
|
1285
|
+
});
|
|
1286
|
+
});
|
|
1287
|
+
|
|
1288
|
+
style.on('error', (event) => {
|
|
1289
|
+
const err = event.error;
|
|
1290
|
+
|
|
1291
|
+
expect(err).toBeTruthy();
|
|
1292
|
+
expect(err.toString().indexOf('-source-layer-') !== -1).toBeTruthy();
|
|
1293
|
+
expect(err.toString().indexOf('-source-id-') !== -1).toBeTruthy();
|
|
1294
|
+
expect(err.toString().indexOf('-layer-id-') !== -1).toBeTruthy();
|
|
1295
|
+
|
|
1296
|
+
done();
|
|
1297
|
+
});
|
|
1298
|
+
}));
|
|
1299
|
+
|
|
1300
|
+
test('emits error on invalid layer', () => new Promise<void>(done => {
|
|
1301
|
+
const style = new Style(getStubMap());
|
|
1302
|
+
style.loadJSON(createStyleJSON());
|
|
1303
|
+
style.on('style.load', () => {
|
|
1304
|
+
style.on('error', () => {
|
|
1305
|
+
expect(style.getLayer('background')).toBeFalsy();
|
|
1306
|
+
done();
|
|
1307
|
+
});
|
|
1308
|
+
style.addLayer({
|
|
1309
|
+
id: 'background',
|
|
1310
|
+
type: 'background',
|
|
1311
|
+
paint: {
|
|
1312
|
+
'background-opacity': 5
|
|
1313
|
+
}
|
|
1314
|
+
});
|
|
1315
|
+
});
|
|
1316
|
+
}));
|
|
1317
|
+
|
|
1318
|
+
test('#4040 does not mutate source property when provided inline', async () => {
|
|
1319
|
+
const style = new Style(getStubMap());
|
|
1320
|
+
style.loadJSON(createStyleJSON());
|
|
1321
|
+
await style.once('style.load');
|
|
1322
|
+
const source = {
|
|
1323
|
+
'type': 'geojson',
|
|
1324
|
+
'data': {
|
|
1325
|
+
'type': 'Point',
|
|
1326
|
+
'coordinates': [0, 0]
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
const layer = {id: 'inline-source-layer', type: 'circle', source} as any as LayerSpecification;
|
|
1330
|
+
style.addLayer(layer);
|
|
1331
|
+
expect((layer as any).source).toEqual(source);
|
|
1332
|
+
});
|
|
1333
|
+
|
|
1334
|
+
test('reloads source', () => new Promise<void>(done => {
|
|
1335
|
+
const style = createStyle();
|
|
1336
|
+
style.loadJSON(extend(createStyleJSON(), {
|
|
1337
|
+
'sources': {
|
|
1338
|
+
'mapLibre': {
|
|
1339
|
+
'type': 'vector',
|
|
1340
|
+
'tiles': []
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}));
|
|
1344
|
+
const layer = {
|
|
1345
|
+
'id': 'symbol',
|
|
1346
|
+
'type': 'symbol',
|
|
1347
|
+
'source': 'mapLibre',
|
|
1348
|
+
'source-layer': 'libremap',
|
|
1349
|
+
'filter': ['==', 'id', 0]
|
|
1350
|
+
} as LayerSpecification;
|
|
1351
|
+
|
|
1352
|
+
style.on('data', (e) => {
|
|
1353
|
+
if (e.dataType === 'source' && e.sourceDataType === 'content') {
|
|
1354
|
+
style.sourceCaches['mapLibre'].reload = () => { done(); };
|
|
1355
|
+
style.addLayer(layer);
|
|
1356
|
+
style.update({} as EvaluationParameters);
|
|
1357
|
+
}
|
|
1358
|
+
});
|
|
1359
|
+
}));
|
|
1360
|
+
|
|
1361
|
+
test('#3895 reloads source (instead of clearing) if adding this layer with the same type, immediately after removing it', () => new Promise<void>((done) => {
|
|
1362
|
+
const style = createStyle();
|
|
1363
|
+
style.loadJSON(extend(createStyleJSON(), {
|
|
1364
|
+
'sources': {
|
|
1365
|
+
'mapLibre': {
|
|
1366
|
+
'type': 'vector',
|
|
1367
|
+
'tiles': []
|
|
1368
|
+
}
|
|
1369
|
+
},
|
|
1370
|
+
layers: [{
|
|
1371
|
+
'id': 'my-layer',
|
|
1372
|
+
'type': 'symbol',
|
|
1373
|
+
'source': 'mapLibre',
|
|
1374
|
+
'source-layer': 'libremap',
|
|
1375
|
+
'filter': ['==', 'id', 0]
|
|
1376
|
+
}]
|
|
1377
|
+
}));
|
|
1378
|
+
|
|
1379
|
+
const layer = {
|
|
1380
|
+
'id': 'my-layer',
|
|
1381
|
+
'type': 'symbol',
|
|
1382
|
+
'source': 'mapLibre',
|
|
1383
|
+
'source-layer': 'libremap'
|
|
1384
|
+
}as LayerSpecification;
|
|
1385
|
+
|
|
1386
|
+
style.on('data', (e) => {
|
|
1387
|
+
if (e.dataType === 'source' && e.sourceDataType === 'content') {
|
|
1388
|
+
style.sourceCaches['mapLibre'].reload = () => { done(); };
|
|
1389
|
+
style.sourceCaches['mapLibre'].clearTiles = () => { throw new Error('test failed'); };
|
|
1390
|
+
style.removeLayer('my-layer');
|
|
1391
|
+
style.addLayer(layer);
|
|
1392
|
+
style.update({} as EvaluationParameters);
|
|
1393
|
+
}
|
|
1394
|
+
});
|
|
1395
|
+
|
|
1396
|
+
}));
|
|
1397
|
+
|
|
1398
|
+
test('clears source (instead of reloading) if adding this layer with a different type, immediately after removing it', () => new Promise<void>((done) => {
|
|
1399
|
+
const style = createStyle();
|
|
1400
|
+
style.loadJSON(extend(createStyleJSON(), {
|
|
1401
|
+
'sources': {
|
|
1402
|
+
'mapLibre': {
|
|
1403
|
+
'type': 'vector',
|
|
1404
|
+
'tiles': []
|
|
1405
|
+
}
|
|
1406
|
+
},
|
|
1407
|
+
layers: [{
|
|
1408
|
+
'id': 'my-layer',
|
|
1409
|
+
'type': 'symbol',
|
|
1410
|
+
'source': 'mapLibre',
|
|
1411
|
+
'source-layer': 'libremap',
|
|
1412
|
+
'filter': ['==', 'id', 0]
|
|
1413
|
+
}]
|
|
1414
|
+
}));
|
|
1415
|
+
|
|
1416
|
+
const layer = {
|
|
1417
|
+
'id': 'my-layer',
|
|
1418
|
+
'type': 'circle',
|
|
1419
|
+
'source': 'mapLibre',
|
|
1420
|
+
'source-layer': 'libremap'
|
|
1421
|
+
}as LayerSpecification;
|
|
1422
|
+
style.on('data', (e) => {
|
|
1423
|
+
if (e.dataType === 'source' && e.sourceDataType === 'content') {
|
|
1424
|
+
style.sourceCaches['mapLibre'].reload = () => { throw new Error('test failed'); };
|
|
1425
|
+
style.sourceCaches['mapLibre'].clearTiles = () => { done(); };
|
|
1426
|
+
style.removeLayer('my-layer');
|
|
1427
|
+
style.addLayer(layer);
|
|
1428
|
+
style.update({} as EvaluationParameters);
|
|
1429
|
+
}
|
|
1430
|
+
});
|
|
1431
|
+
|
|
1432
|
+
}));
|
|
1433
|
+
|
|
1434
|
+
test('fires "data" event', async () => {
|
|
1435
|
+
const style = new Style(getStubMap());
|
|
1436
|
+
style.loadJSON(createStyleJSON());
|
|
1437
|
+
const layer = {id: 'background', type: 'background'} as LayerSpecification;
|
|
1438
|
+
|
|
1439
|
+
const dataPromise = style.once('data');
|
|
1440
|
+
|
|
1441
|
+
style.on('style.load', () => {
|
|
1442
|
+
style.addLayer(layer);
|
|
1443
|
+
style.update({} as EvaluationParameters);
|
|
1444
|
+
});
|
|
1445
|
+
await dataPromise;
|
|
1446
|
+
});
|
|
1447
|
+
|
|
1448
|
+
test('emits error on duplicates', () => new Promise<void>(done => {
|
|
1449
|
+
const style = new Style(getStubMap());
|
|
1450
|
+
style.loadJSON(createStyleJSON());
|
|
1451
|
+
const layer = {id: 'background', type: 'background'} as LayerSpecification;
|
|
1452
|
+
|
|
1453
|
+
style.on('error', (e) => {
|
|
1454
|
+
expect(e.error.message).toMatch(/already exists/);
|
|
1455
|
+
done();
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1458
|
+
style.on('style.load', () => {
|
|
1459
|
+
style.addLayer(layer);
|
|
1460
|
+
style.addLayer(layer);
|
|
1461
|
+
});
|
|
1462
|
+
}));
|
|
1463
|
+
|
|
1464
|
+
test('adds to the end by default', async () => {
|
|
1465
|
+
const style = new Style(getStubMap());
|
|
1466
|
+
style.loadJSON(createStyleJSON({
|
|
1467
|
+
layers: [{
|
|
1468
|
+
id: 'a',
|
|
1469
|
+
type: 'background'
|
|
1470
|
+
}, {
|
|
1471
|
+
id: 'b',
|
|
1472
|
+
type: 'background'
|
|
1473
|
+
}]
|
|
1474
|
+
}));
|
|
1475
|
+
const layer = {id: 'c', type: 'background'} as LayerSpecification;
|
|
1476
|
+
|
|
1477
|
+
await style.once('style.load');
|
|
1478
|
+
style.addLayer(layer);
|
|
1479
|
+
expect(style._order).toEqual(['a', 'b', 'c']);
|
|
1480
|
+
});
|
|
1481
|
+
|
|
1482
|
+
test('adds before the given layer', async () => {
|
|
1483
|
+
const style = new Style(getStubMap());
|
|
1484
|
+
style.loadJSON(createStyleJSON({
|
|
1485
|
+
layers: [{
|
|
1486
|
+
id: 'a',
|
|
1487
|
+
type: 'background'
|
|
1488
|
+
}, {
|
|
1489
|
+
id: 'b',
|
|
1490
|
+
type: 'background'
|
|
1491
|
+
}]
|
|
1492
|
+
}));
|
|
1493
|
+
const layer = {id: 'c', type: 'background'} as LayerSpecification;
|
|
1494
|
+
|
|
1495
|
+
await style.once('style.load');
|
|
1496
|
+
style.addLayer(layer, 'a');
|
|
1497
|
+
expect(style._order).toEqual(['c', 'a', 'b']);
|
|
1498
|
+
});
|
|
1499
|
+
|
|
1500
|
+
test('fire error if before layer does not exist', () => new Promise<void>(done => {
|
|
1501
|
+
const style = new Style(getStubMap());
|
|
1502
|
+
style.loadJSON(createStyleJSON({
|
|
1503
|
+
layers: [{
|
|
1504
|
+
id: 'a',
|
|
1505
|
+
type: 'background'
|
|
1506
|
+
}, {
|
|
1507
|
+
id: 'b',
|
|
1508
|
+
type: 'background'
|
|
1509
|
+
}]
|
|
1510
|
+
}));
|
|
1511
|
+
const layer = {id: 'c', type: 'background'} as LayerSpecification;
|
|
1512
|
+
|
|
1513
|
+
style.on('style.load', () => {
|
|
1514
|
+
style.on('error', (error) => {
|
|
1515
|
+
expect(error.error.message).toMatch(/Cannot add layer "c" before non-existing layer "z"./);
|
|
1516
|
+
done();
|
|
1517
|
+
});
|
|
1518
|
+
style.addLayer(layer, 'z');
|
|
1519
|
+
});
|
|
1520
|
+
}));
|
|
1521
|
+
|
|
1522
|
+
test('fires an error on non-existant source layer', () => new Promise<void>(done => {
|
|
1523
|
+
const style = new Style(getStubMap());
|
|
1524
|
+
style.loadJSON(extend(createStyleJSON(), {
|
|
1525
|
+
sources: {
|
|
1526
|
+
dummy: {
|
|
1527
|
+
type: 'geojson',
|
|
1528
|
+
data: {type: 'FeatureCollection', features: []}
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
}));
|
|
1532
|
+
|
|
1533
|
+
const layer = {
|
|
1534
|
+
id: 'dummy',
|
|
1535
|
+
type: 'fill',
|
|
1536
|
+
source: 'dummy',
|
|
1537
|
+
'source-layer': 'dummy'
|
|
1538
|
+
}as LayerSpecification;
|
|
1539
|
+
|
|
1540
|
+
style.on('style.load', () => {
|
|
1541
|
+
style.on('error', ({error}) => {
|
|
1542
|
+
expect(error.message).toMatch(/does not exist on source/);
|
|
1543
|
+
done();
|
|
1544
|
+
});
|
|
1545
|
+
style.addLayer(layer);
|
|
1546
|
+
});
|
|
1547
|
+
|
|
1548
|
+
}));
|
|
1549
|
+
});
|
|
1550
|
+
|
|
1551
|
+
describe('Style#removeLayer', () => {
|
|
1552
|
+
test('throw before loaded', () => {
|
|
1553
|
+
const style = new Style(getStubMap());
|
|
1554
|
+
expect(() => style.removeLayer('background')).toThrow(/load/i);
|
|
1555
|
+
});
|
|
1556
|
+
|
|
1557
|
+
test('fires "data" event', async () => {
|
|
1558
|
+
const style = new Style(getStubMap());
|
|
1559
|
+
style.loadJSON(createStyleJSON());
|
|
1560
|
+
const layer = {id: 'background', type: 'background'} as LayerSpecification;
|
|
1561
|
+
|
|
1562
|
+
const dataPromise = style.once('data');
|
|
1563
|
+
|
|
1564
|
+
style.on('style.load', () => {
|
|
1565
|
+
style.addLayer(layer);
|
|
1566
|
+
style.removeLayer('background');
|
|
1567
|
+
style.update({} as EvaluationParameters);
|
|
1568
|
+
});
|
|
1569
|
+
|
|
1570
|
+
await dataPromise;
|
|
1571
|
+
});
|
|
1572
|
+
|
|
1573
|
+
test('tears down layer event forwarding', () => new Promise<void>((done) => {
|
|
1574
|
+
const style = new Style(getStubMap());
|
|
1575
|
+
style.loadJSON(createStyleJSON({
|
|
1576
|
+
layers: [{
|
|
1577
|
+
id: 'background',
|
|
1578
|
+
type: 'background'
|
|
1579
|
+
}]
|
|
1580
|
+
}));
|
|
1581
|
+
|
|
1582
|
+
style.on('error', () => {
|
|
1583
|
+
throw new Error('test failed');
|
|
1584
|
+
});
|
|
1585
|
+
|
|
1586
|
+
style.on('style.load', () => {
|
|
1587
|
+
const layer = style._layers.background;
|
|
1588
|
+
style.removeLayer('background');
|
|
1589
|
+
|
|
1590
|
+
// Bind a listener to prevent fallback Evented error reporting.
|
|
1591
|
+
layer.on('error', () => {});
|
|
1592
|
+
|
|
1593
|
+
layer.fire(new Event('error', {mapLibre: true}));
|
|
1594
|
+
done();
|
|
1595
|
+
});
|
|
1596
|
+
}));
|
|
1597
|
+
|
|
1598
|
+
test('fires an error on non-existence', async () => {
|
|
1599
|
+
const style = new Style(getStubMap());
|
|
1600
|
+
style.loadJSON(createStyleJSON());
|
|
1601
|
+
|
|
1602
|
+
await style.once('style.load');
|
|
1603
|
+
const promise = style.once('error');
|
|
1604
|
+
style.removeLayer('background');
|
|
1605
|
+
const {error} = await promise;
|
|
1606
|
+
expect(error.message).toMatch(/Cannot remove non-existing layer "background"./);
|
|
1607
|
+
});
|
|
1608
|
+
|
|
1609
|
+
test('removes from the order', async () => {
|
|
1610
|
+
const style = new Style(getStubMap());
|
|
1611
|
+
style.loadJSON(createStyleJSON({
|
|
1612
|
+
layers: [{
|
|
1613
|
+
id: 'a',
|
|
1614
|
+
type: 'background'
|
|
1615
|
+
}, {
|
|
1616
|
+
id: 'b',
|
|
1617
|
+
type: 'background'
|
|
1618
|
+
}]
|
|
1619
|
+
}));
|
|
1620
|
+
|
|
1621
|
+
await style.once('style.load');
|
|
1622
|
+
style.removeLayer('a');
|
|
1623
|
+
expect(style._order).toEqual(['b']);
|
|
1624
|
+
});
|
|
1625
|
+
|
|
1626
|
+
test('does not remove dereffed layers', async () => {
|
|
1627
|
+
const style = new Style(getStubMap());
|
|
1628
|
+
style.loadJSON(createStyleJSON({
|
|
1629
|
+
layers: [{
|
|
1630
|
+
id: 'a',
|
|
1631
|
+
type: 'background'
|
|
1632
|
+
}, {
|
|
1633
|
+
id: 'b',
|
|
1634
|
+
ref: 'a'
|
|
1635
|
+
}]
|
|
1636
|
+
}));
|
|
1637
|
+
|
|
1638
|
+
await style.once('style.load');
|
|
1639
|
+
style.removeLayer('a');
|
|
1640
|
+
expect(style.getLayer('a')).toBeUndefined();
|
|
1641
|
+
expect(style.getLayer('b')).toBeDefined();
|
|
1642
|
+
});
|
|
1643
|
+
});
|
|
1644
|
+
|
|
1645
|
+
describe('Style#moveLayer', () => {
|
|
1646
|
+
test('throw before loaded', () => {
|
|
1647
|
+
const style = new Style(getStubMap());
|
|
1648
|
+
expect(() => style.moveLayer('background')).toThrow(/load/i);
|
|
1649
|
+
});
|
|
1650
|
+
|
|
1651
|
+
test('fires "data" event', async () => {
|
|
1652
|
+
const style = new Style(getStubMap());
|
|
1653
|
+
style.loadJSON(createStyleJSON());
|
|
1654
|
+
const layer = {id: 'background', type: 'background'} as LayerSpecification;
|
|
1655
|
+
|
|
1656
|
+
const dataPromise = style.once('data');
|
|
1657
|
+
style.on('style.load', () => {
|
|
1658
|
+
style.addLayer(layer);
|
|
1659
|
+
style.moveLayer('background');
|
|
1660
|
+
style.update({} as EvaluationParameters);
|
|
1661
|
+
});
|
|
1662
|
+
await dataPromise;
|
|
1663
|
+
});
|
|
1664
|
+
|
|
1665
|
+
test('fires an error on non-existence', async () => {
|
|
1666
|
+
const style = new Style(getStubMap());
|
|
1667
|
+
style.loadJSON(createStyleJSON());
|
|
1668
|
+
|
|
1669
|
+
await style.once('style.load');
|
|
1670
|
+
const promise = style.once('error');
|
|
1671
|
+
style.moveLayer('background');
|
|
1672
|
+
const {error} = await promise;
|
|
1673
|
+
expect(error.message).toMatch(/does not exist in the map\'s style and cannot be moved/);
|
|
1674
|
+
});
|
|
1675
|
+
|
|
1676
|
+
test('changes the order', async () => {
|
|
1677
|
+
const style = new Style(getStubMap());
|
|
1678
|
+
style.loadJSON(createStyleJSON({
|
|
1679
|
+
layers: [
|
|
1680
|
+
{id: 'a', type: 'background'},
|
|
1681
|
+
{id: 'b', type: 'background'},
|
|
1682
|
+
{id: 'c', type: 'background'}
|
|
1683
|
+
]
|
|
1684
|
+
}));
|
|
1685
|
+
|
|
1686
|
+
await style.once('style.load');
|
|
1687
|
+
style.moveLayer('a', 'c');
|
|
1688
|
+
expect(style._order).toEqual(['b', 'a', 'c']);
|
|
1689
|
+
});
|
|
1690
|
+
|
|
1691
|
+
test('moves to existing location', async () => {
|
|
1692
|
+
const style = new Style(getStubMap());
|
|
1693
|
+
style.loadJSON(createStyleJSON({
|
|
1694
|
+
layers: [
|
|
1695
|
+
{id: 'a', type: 'background'},
|
|
1696
|
+
{id: 'b', type: 'background'},
|
|
1697
|
+
{id: 'c', type: 'background'}
|
|
1698
|
+
]
|
|
1699
|
+
}));
|
|
1700
|
+
|
|
1701
|
+
await style.once('style.load');
|
|
1702
|
+
style.moveLayer('b', 'b');
|
|
1703
|
+
expect(style._order).toEqual(['a', 'b', 'c']);
|
|
1704
|
+
});
|
|
1705
|
+
});
|
|
1706
|
+
|
|
1707
|
+
describe('Style#setPaintProperty', () => {
|
|
1708
|
+
test('#4738 postpones source reload until layers have been broadcast to workers', () => new Promise<void>(done => {
|
|
1709
|
+
const style = new Style(getStubMap());
|
|
1710
|
+
style.loadJSON(extend(createStyleJSON(), {
|
|
1711
|
+
'sources': {
|
|
1712
|
+
'geojson': {
|
|
1713
|
+
'type': 'geojson',
|
|
1714
|
+
'data': {'type': 'FeatureCollection', 'features': []}
|
|
1715
|
+
}
|
|
1716
|
+
},
|
|
1717
|
+
'layers': [
|
|
1718
|
+
{
|
|
1719
|
+
'id': 'circle',
|
|
1720
|
+
'type': 'circle',
|
|
1721
|
+
'source': 'geojson'
|
|
1722
|
+
}
|
|
1723
|
+
]
|
|
1724
|
+
}));
|
|
1725
|
+
|
|
1726
|
+
const tr = new Transform();
|
|
1727
|
+
tr.resize(512, 512);
|
|
1728
|
+
|
|
1729
|
+
style.once('style.load', () => {
|
|
1730
|
+
style.update(tr.zoom as any as EvaluationParameters);
|
|
1731
|
+
const sourceCache = style.sourceCaches['geojson'];
|
|
1732
|
+
const source = style.getSource('geojson');
|
|
1733
|
+
|
|
1734
|
+
let begun = false;
|
|
1735
|
+
let styleUpdateCalled = false;
|
|
1736
|
+
|
|
1737
|
+
(source as any).on('data', (e) => setTimeout(() => {
|
|
1738
|
+
if (!begun) {
|
|
1739
|
+
begun = true;
|
|
1740
|
+
jest.spyOn(sourceCache, 'reload').mockImplementation(() => {
|
|
1741
|
+
expect(styleUpdateCalled).toBeTruthy();
|
|
1742
|
+
done();
|
|
1743
|
+
});
|
|
1744
|
+
|
|
1745
|
+
(source as any).setData({'type': 'FeatureCollection', 'features': []});
|
|
1746
|
+
style.setPaintProperty('circle', 'circle-color', {type: 'identity', property: 'foo'});
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
if (begun && e.sourceDataType === 'content') {
|
|
1750
|
+
// setData() worker-side work is complete; simulate an
|
|
1751
|
+
// animation frame a few ms later, so that this test can
|
|
1752
|
+
// confirm that SourceCache#reload() isn't called until
|
|
1753
|
+
// after the next Style#update()
|
|
1754
|
+
setTimeout(() => {
|
|
1755
|
+
styleUpdateCalled = true;
|
|
1756
|
+
style.update({} as EvaluationParameters);
|
|
1757
|
+
}, 50);
|
|
1758
|
+
}
|
|
1759
|
+
}));
|
|
1760
|
+
});
|
|
1761
|
+
}));
|
|
1762
|
+
|
|
1763
|
+
test('#5802 clones the input', async () => {
|
|
1764
|
+
const style = new Style(getStubMap());
|
|
1765
|
+
style.loadJSON({
|
|
1766
|
+
'version': 8,
|
|
1767
|
+
'sources': {},
|
|
1768
|
+
'layers': [
|
|
1769
|
+
{
|
|
1770
|
+
'id': 'background',
|
|
1771
|
+
'type': 'background'
|
|
1772
|
+
}
|
|
1773
|
+
]
|
|
1774
|
+
});
|
|
1775
|
+
|
|
1776
|
+
await style.once('style.load');
|
|
1777
|
+
const value = {stops: [[0, 'red'], [10, 'blue']]};
|
|
1778
|
+
style.setPaintProperty('background', 'background-color', value);
|
|
1779
|
+
expect(style.getPaintProperty('background', 'background-color')).not.toBe(value);
|
|
1780
|
+
expect(style._changed).toBeTruthy();
|
|
1781
|
+
|
|
1782
|
+
style.update({} as EvaluationParameters);
|
|
1783
|
+
expect(style._changed).toBeFalsy();
|
|
1784
|
+
|
|
1785
|
+
value.stops[0][0] = 1;
|
|
1786
|
+
style.setPaintProperty('background', 'background-color', value);
|
|
1787
|
+
expect(style._changed).toBeTruthy();
|
|
1788
|
+
});
|
|
1789
|
+
|
|
1790
|
+
test('respects validate option', async () => {
|
|
1791
|
+
const style = new Style(getStubMap());
|
|
1792
|
+
style.loadJSON({
|
|
1793
|
+
'version': 8,
|
|
1794
|
+
'sources': {},
|
|
1795
|
+
'layers': [
|
|
1796
|
+
{
|
|
1797
|
+
'id': 'background',
|
|
1798
|
+
'type': 'background'
|
|
1799
|
+
}
|
|
1800
|
+
]
|
|
1801
|
+
});
|
|
1802
|
+
|
|
1803
|
+
await style.once('style.load');
|
|
1804
|
+
const backgroundLayer = style.getLayer('background');
|
|
1805
|
+
const validate = jest.spyOn(backgroundLayer, '_validate');
|
|
1806
|
+
|
|
1807
|
+
style.setPaintProperty('background', 'background-color', 'notacolor', {validate: false});
|
|
1808
|
+
expect(validate.mock.calls[0][4]).toEqual({validate: false});
|
|
1809
|
+
expect(mockConsoleError).not.toHaveBeenCalled();
|
|
1810
|
+
|
|
1811
|
+
expect(style._changed).toBeTruthy();
|
|
1812
|
+
style.update({} as EvaluationParameters);
|
|
1813
|
+
|
|
1814
|
+
style.setPaintProperty('background', 'background-color', 'alsonotacolor');
|
|
1815
|
+
expect(mockConsoleError).toHaveBeenCalledTimes(1);
|
|
1816
|
+
expect(validate.mock.calls[1][4]).toEqual({});
|
|
1817
|
+
});
|
|
1818
|
+
});
|
|
1819
|
+
|
|
1820
|
+
describe('Style#getPaintProperty', () => {
|
|
1821
|
+
test('#5802 clones the output', async () => {
|
|
1822
|
+
const style = new Style(getStubMap());
|
|
1823
|
+
style.loadJSON({
|
|
1824
|
+
'version': 8,
|
|
1825
|
+
'sources': {},
|
|
1826
|
+
'layers': [
|
|
1827
|
+
{
|
|
1828
|
+
'id': 'background',
|
|
1829
|
+
'type': 'background'
|
|
1830
|
+
}
|
|
1831
|
+
]
|
|
1832
|
+
});
|
|
1833
|
+
|
|
1834
|
+
await style.once('style.load');
|
|
1835
|
+
style.setPaintProperty('background', 'background-color', {stops: [[0, 'red'], [10, 'blue']]});
|
|
1836
|
+
style.update({} as EvaluationParameters);
|
|
1837
|
+
expect(style._changed).toBeFalsy();
|
|
1838
|
+
|
|
1839
|
+
const value = style.getPaintProperty('background', 'background-color');
|
|
1840
|
+
value['stops'][0][0] = 1;
|
|
1841
|
+
style.setPaintProperty('background', 'background-color', value);
|
|
1842
|
+
expect(style._changed).toBeTruthy();
|
|
1843
|
+
});
|
|
1844
|
+
});
|
|
1845
|
+
|
|
1846
|
+
describe('Style#setLayoutProperty', () => {
|
|
1847
|
+
test('#5802 clones the input', async () => {
|
|
1848
|
+
const style = new Style(getStubMap());
|
|
1849
|
+
style.loadJSON({
|
|
1850
|
+
'version': 8,
|
|
1851
|
+
'sources': {
|
|
1852
|
+
'geojson': {
|
|
1853
|
+
'type': 'geojson',
|
|
1854
|
+
'data': {
|
|
1855
|
+
'type': 'FeatureCollection',
|
|
1856
|
+
'features': []
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
},
|
|
1860
|
+
'layers': [
|
|
1861
|
+
{
|
|
1862
|
+
'id': 'line',
|
|
1863
|
+
'type': 'line',
|
|
1864
|
+
'source': 'geojson'
|
|
1865
|
+
}
|
|
1866
|
+
]
|
|
1867
|
+
});
|
|
1868
|
+
|
|
1869
|
+
await style.once('style.load');
|
|
1870
|
+
const value = {stops: [[0, 'butt'], [10, 'round']]};
|
|
1871
|
+
style.setLayoutProperty('line', 'line-cap', value);
|
|
1872
|
+
expect(style.getLayoutProperty('line', 'line-cap')).not.toBe(value);
|
|
1873
|
+
expect(style._changed).toBeTruthy();
|
|
1874
|
+
|
|
1875
|
+
style.update({} as EvaluationParameters);
|
|
1876
|
+
expect(style._changed).toBeFalsy();
|
|
1877
|
+
|
|
1878
|
+
value.stops[0][0] = 1;
|
|
1879
|
+
style.setLayoutProperty('line', 'line-cap', value);
|
|
1880
|
+
expect(style._changed).toBeTruthy();
|
|
1881
|
+
});
|
|
1882
|
+
|
|
1883
|
+
test('respects validate option', async () => {
|
|
1884
|
+
const style = new Style(getStubMap());
|
|
1885
|
+
style.loadJSON({
|
|
1886
|
+
'version': 8,
|
|
1887
|
+
'sources': {
|
|
1888
|
+
'geojson': {
|
|
1889
|
+
'type': 'geojson',
|
|
1890
|
+
'data': {
|
|
1891
|
+
'type': 'FeatureCollection',
|
|
1892
|
+
'features': []
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
},
|
|
1896
|
+
'layers': [
|
|
1897
|
+
{
|
|
1898
|
+
'id': 'line',
|
|
1899
|
+
'type': 'line',
|
|
1900
|
+
'source': 'geojson'
|
|
1901
|
+
}
|
|
1902
|
+
]
|
|
1903
|
+
});
|
|
1904
|
+
|
|
1905
|
+
await style.once('style.load');
|
|
1906
|
+
const lineLayer = style.getLayer('line');
|
|
1907
|
+
const validate = jest.spyOn(lineLayer, '_validate');
|
|
1908
|
+
|
|
1909
|
+
style.setLayoutProperty('line', 'line-cap', 'invalidcap', {validate: false});
|
|
1910
|
+
expect(validate.mock.calls[0][4]).toEqual({validate: false});
|
|
1911
|
+
expect(mockConsoleError).not.toHaveBeenCalled();
|
|
1912
|
+
expect(style._changed).toBeTruthy();
|
|
1913
|
+
style.update({} as EvaluationParameters);
|
|
1914
|
+
|
|
1915
|
+
style.setLayoutProperty('line', 'line-cap', 'differentinvalidcap');
|
|
1916
|
+
expect(mockConsoleError).toHaveBeenCalledTimes(1);
|
|
1917
|
+
expect(validate.mock.calls[1][4]).toEqual({});
|
|
1918
|
+
});
|
|
1919
|
+
});
|
|
1920
|
+
|
|
1921
|
+
describe('Style#getLayoutProperty', () => {
|
|
1922
|
+
test('#5802 clones the output', async () => {
|
|
1923
|
+
const style = new Style(getStubMap());
|
|
1924
|
+
style.loadJSON({
|
|
1925
|
+
'version': 8,
|
|
1926
|
+
'sources': {
|
|
1927
|
+
'geojson': {
|
|
1928
|
+
'type': 'geojson',
|
|
1929
|
+
'data': {
|
|
1930
|
+
'type': 'FeatureCollection',
|
|
1931
|
+
'features': []
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
},
|
|
1935
|
+
'layers': [
|
|
1936
|
+
{
|
|
1937
|
+
'id': 'line',
|
|
1938
|
+
'type': 'line',
|
|
1939
|
+
'source': 'geojson'
|
|
1940
|
+
}
|
|
1941
|
+
]
|
|
1942
|
+
});
|
|
1943
|
+
|
|
1944
|
+
await style.once('style.load');
|
|
1945
|
+
style.setLayoutProperty('line', 'line-cap', {stops: [[0, 'butt'], [10, 'round']]});
|
|
1946
|
+
style.update({} as EvaluationParameters);
|
|
1947
|
+
expect(style._changed).toBeFalsy();
|
|
1948
|
+
|
|
1949
|
+
const value = style.getLayoutProperty('line', 'line-cap');
|
|
1950
|
+
value.stops[0][0] = 1;
|
|
1951
|
+
style.setLayoutProperty('line', 'line-cap', value);
|
|
1952
|
+
expect(style._changed).toBeTruthy();
|
|
1953
|
+
});
|
|
1954
|
+
});
|
|
1955
|
+
|
|
1956
|
+
describe('Style#setFilter', () => {
|
|
1957
|
+
test('throws if style is not loaded', () => {
|
|
1958
|
+
const style = new Style(getStubMap());
|
|
1959
|
+
expect(() => style.setFilter('symbol', ['==', 'id', 1])).toThrow(/load/i);
|
|
1960
|
+
});
|
|
1961
|
+
|
|
1962
|
+
function createStyle() {
|
|
1963
|
+
const style = new Style(getStubMap());
|
|
1964
|
+
style.loadJSON({
|
|
1965
|
+
version: 8,
|
|
1966
|
+
sources: {
|
|
1967
|
+
geojson: createGeoJSONSource() as GeoJSONSourceSpecification
|
|
1968
|
+
},
|
|
1969
|
+
layers: [
|
|
1970
|
+
{id: 'symbol', type: 'symbol', source: 'geojson', filter: ['==', 'id', 0]}
|
|
1971
|
+
]
|
|
1972
|
+
});
|
|
1973
|
+
return style;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
test('sets filter', () => new Promise<void>(done => {
|
|
1977
|
+
const style = createStyle();
|
|
1978
|
+
|
|
1979
|
+
style.on('style.load', () => {
|
|
1980
|
+
style.dispatcher.broadcast = (key, value) => {
|
|
1981
|
+
expect(key).toBe(MessageType.updateLayers);
|
|
1982
|
+
expect(value['layers'][0].id).toBe('symbol');
|
|
1983
|
+
expect(value['layers'][0].filter).toEqual(['==', 'id', 1]);
|
|
1984
|
+
done();
|
|
1985
|
+
return Promise.resolve({} as any);
|
|
1986
|
+
};
|
|
1987
|
+
|
|
1988
|
+
style.setFilter('symbol', ['==', 'id', 1]);
|
|
1989
|
+
expect(style.getFilter('symbol')).toEqual(['==', 'id', 1]);
|
|
1990
|
+
style.update({} as EvaluationParameters); // trigger dispatcher broadcast
|
|
1991
|
+
});
|
|
1992
|
+
}));
|
|
1993
|
+
|
|
1994
|
+
test('gets a clone of the filter', async () => {
|
|
1995
|
+
const style = createStyle();
|
|
1996
|
+
|
|
1997
|
+
await style.once('style.load');
|
|
1998
|
+
const filter1 = ['==', 'id', 1] as FilterSpecification;
|
|
1999
|
+
style.setFilter('symbol', filter1);
|
|
2000
|
+
const filter2 = style.getFilter('symbol');
|
|
2001
|
+
const filter3 = style.getLayer('symbol').filter;
|
|
2002
|
+
|
|
2003
|
+
expect(filter1).not.toBe(filter2);
|
|
2004
|
+
expect(filter1).not.toBe(filter3);
|
|
2005
|
+
expect(filter2).not.toBe(filter3);
|
|
2006
|
+
});
|
|
2007
|
+
|
|
2008
|
+
test('sets again mutated filter', () => new Promise<void>(done => {
|
|
2009
|
+
const style = createStyle();
|
|
2010
|
+
|
|
2011
|
+
style.on('style.load', () => {
|
|
2012
|
+
const filter = ['==', 'id', 1] as FilterSpecification;
|
|
2013
|
+
style.setFilter('symbol', filter);
|
|
2014
|
+
style.update({} as EvaluationParameters); // flush pending operations
|
|
2015
|
+
|
|
2016
|
+
style.dispatcher.broadcast = (key, value) => {
|
|
2017
|
+
expect(key).toBe(MessageType.updateLayers);
|
|
2018
|
+
expect(value['layers'][0].id).toBe('symbol');
|
|
2019
|
+
expect(value['layers'][0].filter).toEqual(['==', 'id', 2]);
|
|
2020
|
+
done();
|
|
2021
|
+
return Promise.resolve({} as any);
|
|
2022
|
+
};
|
|
2023
|
+
filter[2] = 2;
|
|
2024
|
+
style.setFilter('symbol', filter);
|
|
2025
|
+
style.update({} as EvaluationParameters); // trigger dispatcher broadcast
|
|
2026
|
+
});
|
|
2027
|
+
}));
|
|
2028
|
+
|
|
2029
|
+
test('unsets filter', async () => {
|
|
2030
|
+
const style = createStyle();
|
|
2031
|
+
await style.once('style.load');
|
|
2032
|
+
style.setFilter('symbol', null);
|
|
2033
|
+
expect(style.getLayer('symbol').serialize()['filter']).toBeUndefined();
|
|
2034
|
+
});
|
|
2035
|
+
|
|
2036
|
+
test('emits if invalid', async () => {
|
|
2037
|
+
const style = createStyle();
|
|
2038
|
+
await style.once('style.load');
|
|
2039
|
+
const promise = style.once('error');
|
|
2040
|
+
style.setFilter('symbol', ['==', '$type', 1]);
|
|
2041
|
+
await promise;
|
|
2042
|
+
expect(style.getLayer('symbol').serialize()['filter']).toEqual(['==', 'id', 0]);
|
|
2043
|
+
});
|
|
2044
|
+
|
|
2045
|
+
test('fires an error if layer not found', async () => {
|
|
2046
|
+
const style = createStyle();
|
|
2047
|
+
|
|
2048
|
+
await style.once('style.load');
|
|
2049
|
+
const promise = style.once('error');
|
|
2050
|
+
style.setFilter('non-existant', ['==', 'id', 1]);
|
|
2051
|
+
const {error} = await promise;
|
|
2052
|
+
expect(error.message).toMatch(/Cannot filter non-existing layer "non-existant"./);
|
|
2053
|
+
});
|
|
2054
|
+
|
|
2055
|
+
test('validates filter by default', async () => {
|
|
2056
|
+
const style = createStyle();
|
|
2057
|
+
await style.once('style.load');
|
|
2058
|
+
style.setFilter('symbol', 'notafilter' as any as FilterSpecification);
|
|
2059
|
+
expect(style.getFilter('symbol')).toEqual(['==', 'id', 0]);
|
|
2060
|
+
expect(mockConsoleError).toHaveBeenCalledTimes(1);
|
|
2061
|
+
style.update({} as EvaluationParameters); // trigger dispatcher broadcast
|
|
2062
|
+
});
|
|
2063
|
+
|
|
2064
|
+
test('respects validate option', () => new Promise<void>(done => {
|
|
2065
|
+
const style = createStyle();
|
|
2066
|
+
|
|
2067
|
+
style.on('style.load', () => {
|
|
2068
|
+
style.dispatcher.broadcast = (key, value) => {
|
|
2069
|
+
expect(key).toBe(MessageType.updateLayers);
|
|
2070
|
+
expect(value['layers'][0].id).toBe('symbol');
|
|
2071
|
+
expect(value['layers'][0].filter).toBe('notafilter');
|
|
2072
|
+
done();
|
|
2073
|
+
return Promise.resolve({} as any);
|
|
2074
|
+
};
|
|
2075
|
+
|
|
2076
|
+
style.setFilter('symbol', 'notafilter' as any as FilterSpecification, {validate: false});
|
|
2077
|
+
expect(style.getFilter('symbol')).toBe('notafilter');
|
|
2078
|
+
style.update({} as EvaluationParameters); // trigger dispatcher broadcast
|
|
2079
|
+
});
|
|
2080
|
+
}));
|
|
2081
|
+
});
|
|
2082
|
+
|
|
2083
|
+
describe('Style#setLayerZoomRange', () => {
|
|
2084
|
+
test('throw before loaded', () => {
|
|
2085
|
+
const style = new Style(getStubMap());
|
|
2086
|
+
expect(() => style.setLayerZoomRange('symbol', 5, 12)).toThrow(/load/i);
|
|
2087
|
+
});
|
|
2088
|
+
|
|
2089
|
+
function createStyle() {
|
|
2090
|
+
const style = new Style(getStubMap());
|
|
2091
|
+
style.loadJSON({
|
|
2092
|
+
'version': 8,
|
|
2093
|
+
'sources': {
|
|
2094
|
+
'geojson': createGeoJSONSource() as GeoJSONSourceSpecification
|
|
2095
|
+
},
|
|
2096
|
+
'layers': [{
|
|
2097
|
+
'id': 'symbol',
|
|
2098
|
+
'type': 'symbol',
|
|
2099
|
+
'source': 'geojson'
|
|
2100
|
+
}]
|
|
2101
|
+
});
|
|
2102
|
+
return style;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
test('sets zoom range', () => new Promise<void>(done => {
|
|
2106
|
+
const style = createStyle();
|
|
2107
|
+
|
|
2108
|
+
style.on('style.load', () => {
|
|
2109
|
+
style.dispatcher.broadcast = (key, value) => {
|
|
2110
|
+
expect(key).toBe(MessageType.updateLayers);
|
|
2111
|
+
expect(value['layers'].map((layer) => { return layer.id; })).toEqual(['symbol']);
|
|
2112
|
+
done();
|
|
2113
|
+
return Promise.resolve({} as any);
|
|
2114
|
+
};
|
|
2115
|
+
style.setLayerZoomRange('symbol', 5, 12);
|
|
2116
|
+
expect(style.getLayer('symbol').minzoom).toBe(5);
|
|
2117
|
+
expect(style.getLayer('symbol').maxzoom).toBe(12);
|
|
2118
|
+
style.update({} as EvaluationParameters); // trigger dispatcher broadcast
|
|
2119
|
+
});
|
|
2120
|
+
}));
|
|
2121
|
+
|
|
2122
|
+
test('fires an error if layer not found', async () => {
|
|
2123
|
+
const style = createStyle();
|
|
2124
|
+
await style.once('style.load');
|
|
2125
|
+
const promise = style.once('error');
|
|
2126
|
+
style.setLayerZoomRange('non-existant', 5, 12);
|
|
2127
|
+
const {error} = await promise;
|
|
2128
|
+
expect(error.message).toMatch(/Cannot set the zoom range of non-existing layer "non-existant"./);
|
|
2129
|
+
});
|
|
2130
|
+
|
|
2131
|
+
test('does not reload raster source', async () => {
|
|
2132
|
+
const style = new Style(getStubMap());
|
|
2133
|
+
style.loadJSON({
|
|
2134
|
+
'version': 8,
|
|
2135
|
+
'sources': {
|
|
2136
|
+
'raster': {
|
|
2137
|
+
type: 'raster',
|
|
2138
|
+
tiles: ['http://tiles.server']
|
|
2139
|
+
}
|
|
2140
|
+
},
|
|
2141
|
+
'layers': [{
|
|
2142
|
+
'id': 'raster',
|
|
2143
|
+
'type': 'raster',
|
|
2144
|
+
'source': 'raster'
|
|
2145
|
+
}]
|
|
2146
|
+
});
|
|
2147
|
+
|
|
2148
|
+
await style.once('style.load');
|
|
2149
|
+
jest.spyOn(style, '_reloadSource');
|
|
2150
|
+
|
|
2151
|
+
style.setLayerZoomRange('raster', 5, 12);
|
|
2152
|
+
style.update(0 as any as EvaluationParameters);
|
|
2153
|
+
expect(style._reloadSource).not.toHaveBeenCalled();
|
|
2154
|
+
});
|
|
2155
|
+
});
|
|
2156
|
+
|
|
2157
|
+
describe('Style#getLayersOrder', () => {
|
|
2158
|
+
test('returns ids of layers in the correct order', async () => {
|
|
2159
|
+
const style = new Style(getStubMap());
|
|
2160
|
+
style.loadJSON({
|
|
2161
|
+
'version': 8,
|
|
2162
|
+
'sources': {
|
|
2163
|
+
'raster': {
|
|
2164
|
+
type: 'raster',
|
|
2165
|
+
tiles: ['http://tiles.server']
|
|
2166
|
+
}
|
|
2167
|
+
},
|
|
2168
|
+
'layers': [{
|
|
2169
|
+
'id': 'raster',
|
|
2170
|
+
'type': 'raster',
|
|
2171
|
+
'source': 'raster'
|
|
2172
|
+
}]
|
|
2173
|
+
});
|
|
2174
|
+
|
|
2175
|
+
await style.once('style.load');
|
|
2176
|
+
style.addLayer({
|
|
2177
|
+
id: 'custom',
|
|
2178
|
+
type: 'custom',
|
|
2179
|
+
render() {}
|
|
2180
|
+
}, 'raster');
|
|
2181
|
+
expect(style.getLayersOrder()).toEqual(['custom', 'raster']);
|
|
2182
|
+
});
|
|
2183
|
+
});
|
|
2184
|
+
|
|
2185
|
+
describe('Style#queryRenderedFeatures', () => {
|
|
2186
|
+
|
|
2187
|
+
let style;
|
|
2188
|
+
let transform;
|
|
2189
|
+
|
|
2190
|
+
beforeEach(() => new Promise<void>(callback => {
|
|
2191
|
+
style = new Style(getStubMap());
|
|
2192
|
+
transform = new Transform();
|
|
2193
|
+
transform.resize(512, 512);
|
|
2194
|
+
function queryMapLibreFeatures(layers, serializedLayers, getFeatureState, queryGeom, cameraQueryGeom, scale, params) {
|
|
2195
|
+
const features = {
|
|
2196
|
+
'land': [{
|
|
2197
|
+
type: 'Feature',
|
|
2198
|
+
layer: style._layers.land.serialize(),
|
|
2199
|
+
geometry: {
|
|
2200
|
+
type: 'Polygon'
|
|
2201
|
+
}
|
|
2202
|
+
}, {
|
|
2203
|
+
type: 'Feature',
|
|
2204
|
+
layer: style._layers.land.serialize(),
|
|
2205
|
+
geometry: {
|
|
2206
|
+
type: 'Point'
|
|
2207
|
+
}
|
|
2208
|
+
}],
|
|
2209
|
+
'landref': [{
|
|
2210
|
+
type: 'Feature',
|
|
2211
|
+
layer: style._layers.landref.serialize(),
|
|
2212
|
+
geometry: {
|
|
2213
|
+
type: 'Line'
|
|
2214
|
+
}
|
|
2215
|
+
}]
|
|
2216
|
+
};
|
|
2217
|
+
|
|
2218
|
+
// format result to shape of tile.queryRenderedFeatures result
|
|
2219
|
+
for (const layer in features) {
|
|
2220
|
+
features[layer] = features[layer].map((feature, featureIndex) =>
|
|
2221
|
+
({feature, featureIndex}));
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
if (params.layers) {
|
|
2225
|
+
for (const l in features) {
|
|
2226
|
+
if (params.layers.indexOf(l) < 0) {
|
|
2227
|
+
delete features[l];
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
return features;
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
style.loadJSON({
|
|
2236
|
+
'version': 8,
|
|
2237
|
+
'sources': {
|
|
2238
|
+
'mapLibre': {
|
|
2239
|
+
'type': 'geojson',
|
|
2240
|
+
'data': {type: 'FeatureCollection', features: []}
|
|
2241
|
+
},
|
|
2242
|
+
'other': {
|
|
2243
|
+
'type': 'geojson',
|
|
2244
|
+
'data': {type: 'FeatureCollection', features: []}
|
|
2245
|
+
}
|
|
2246
|
+
},
|
|
2247
|
+
'layers': [{
|
|
2248
|
+
'id': 'land',
|
|
2249
|
+
'type': 'line',
|
|
2250
|
+
'source': 'mapLibre',
|
|
2251
|
+
'source-layer': 'water',
|
|
2252
|
+
'layout': {
|
|
2253
|
+
'line-cap': 'round'
|
|
2254
|
+
},
|
|
2255
|
+
'paint': {
|
|
2256
|
+
'line-color': 'red'
|
|
2257
|
+
},
|
|
2258
|
+
'metadata': {
|
|
2259
|
+
'something': 'else'
|
|
2260
|
+
}
|
|
2261
|
+
}, {
|
|
2262
|
+
'id': 'landref',
|
|
2263
|
+
'ref': 'land',
|
|
2264
|
+
'paint': {
|
|
2265
|
+
'line-color': 'blue'
|
|
2266
|
+
}
|
|
2267
|
+
} as any as LayerSpecification, {
|
|
2268
|
+
'id': 'land--other',
|
|
2269
|
+
'type': 'line',
|
|
2270
|
+
'source': 'other',
|
|
2271
|
+
'source-layer': 'water',
|
|
2272
|
+
'layout': {
|
|
2273
|
+
'line-cap': 'round'
|
|
2274
|
+
},
|
|
2275
|
+
'paint': {
|
|
2276
|
+
'line-color': 'red'
|
|
2277
|
+
},
|
|
2278
|
+
'metadata': {
|
|
2279
|
+
'something': 'else'
|
|
2280
|
+
}
|
|
2281
|
+
}]
|
|
2282
|
+
});
|
|
2283
|
+
|
|
2284
|
+
style.on('style.load', () => {
|
|
2285
|
+
style.sourceCaches.mapLibre.tilesIn = () => {
|
|
2286
|
+
return [{
|
|
2287
|
+
tile: {queryRenderedFeatures: queryMapLibreFeatures},
|
|
2288
|
+
tileID: new OverscaledTileID(0, 0, 0, 0, 0),
|
|
2289
|
+
queryGeometry: [],
|
|
2290
|
+
scale: 1
|
|
2291
|
+
}];
|
|
2292
|
+
};
|
|
2293
|
+
style.sourceCaches.other.tilesIn = () => {
|
|
2294
|
+
return [];
|
|
2295
|
+
};
|
|
2296
|
+
|
|
2297
|
+
style.sourceCaches.mapLibre.transform = transform;
|
|
2298
|
+
style.sourceCaches.other.transform = transform;
|
|
2299
|
+
|
|
2300
|
+
style.update(0 as any as EvaluationParameters);
|
|
2301
|
+
style._updateSources(transform);
|
|
2302
|
+
callback();
|
|
2303
|
+
});
|
|
2304
|
+
}));
|
|
2305
|
+
|
|
2306
|
+
afterEach(() => {
|
|
2307
|
+
style = undefined;
|
|
2308
|
+
transform = undefined;
|
|
2309
|
+
});
|
|
2310
|
+
|
|
2311
|
+
test('returns feature type', () => {
|
|
2312
|
+
const results = style.queryRenderedFeatures([{x: 0, y: 0}], {}, transform);
|
|
2313
|
+
expect(results[0].geometry.type).toBe('Line');
|
|
2314
|
+
});
|
|
2315
|
+
|
|
2316
|
+
test('filters by `layers` option', () => {
|
|
2317
|
+
const results = style.queryRenderedFeatures([{x: 0, y: 0}], {layers: ['land']}, transform);
|
|
2318
|
+
expect(results).toHaveLength(2);
|
|
2319
|
+
});
|
|
2320
|
+
|
|
2321
|
+
test('checks type of `layers` option', () => {
|
|
2322
|
+
let errors = 0;
|
|
2323
|
+
jest.spyOn(style, 'fire').mockImplementation((event) => {
|
|
2324
|
+
if (event['error'] && event['error'].message.includes('parameters.layers must be an Array.')) {
|
|
2325
|
+
errors++;
|
|
2326
|
+
}
|
|
2327
|
+
});
|
|
2328
|
+
style.queryRenderedFeatures([{x: 0, y: 0}], {layers: 'string'}, transform);
|
|
2329
|
+
expect(errors).toBe(1);
|
|
2330
|
+
});
|
|
2331
|
+
|
|
2332
|
+
test('includes layout properties', () => {
|
|
2333
|
+
const results = style.queryRenderedFeatures([{x: 0, y: 0}], {}, transform);
|
|
2334
|
+
const layout = results[0].layer.layout;
|
|
2335
|
+
expect(layout['line-cap']).toBe('round');
|
|
2336
|
+
});
|
|
2337
|
+
|
|
2338
|
+
test('includes paint properties', () => {
|
|
2339
|
+
const results = style.queryRenderedFeatures([{x: 0, y: 0}], {}, transform);
|
|
2340
|
+
expect(results[2].layer.paint['line-color']).toBe('red');
|
|
2341
|
+
});
|
|
2342
|
+
|
|
2343
|
+
test('includes metadata', () => {
|
|
2344
|
+
const results = style.queryRenderedFeatures([{x: 0, y: 0}], {}, transform);
|
|
2345
|
+
|
|
2346
|
+
const layer = results[1].layer;
|
|
2347
|
+
expect(layer.metadata.something).toBe('else');
|
|
2348
|
+
|
|
2349
|
+
});
|
|
2350
|
+
|
|
2351
|
+
test('include multiple layers', () => {
|
|
2352
|
+
const results = style.queryRenderedFeatures([{x: 0, y: 0}], {layers: ['land', 'landref']}, transform);
|
|
2353
|
+
expect(results).toHaveLength(3);
|
|
2354
|
+
});
|
|
2355
|
+
|
|
2356
|
+
test('does not query sources not implicated by `layers` parameter', () => {
|
|
2357
|
+
style.sourceCaches.mapLibre.queryRenderedFeatures = () => { expect(true).toBe(false); };
|
|
2358
|
+
style.queryRenderedFeatures([{x: 0, y: 0}], {layers: ['land--other']}, transform);
|
|
2359
|
+
});
|
|
2360
|
+
|
|
2361
|
+
test('fires an error if layer included in params does not exist on the style', () => {
|
|
2362
|
+
let errors = 0;
|
|
2363
|
+
jest.spyOn(style, 'fire').mockImplementation((event) => {
|
|
2364
|
+
if (event['error'] && event['error'].message.includes('does not exist in the map\'s style and cannot be queried for features.')) errors++;
|
|
2365
|
+
});
|
|
2366
|
+
const results = style.queryRenderedFeatures([{x: 0, y: 0}], {layers: ['merp']}, transform);
|
|
2367
|
+
expect(errors).toBe(1);
|
|
2368
|
+
expect(results).toHaveLength(0);
|
|
2369
|
+
});
|
|
2370
|
+
});
|
|
2371
|
+
|
|
2372
|
+
describe('Style defers ...', () => {
|
|
2373
|
+
test('... expensive methods', async () => {
|
|
2374
|
+
const style = new Style(getStubMap());
|
|
2375
|
+
style.loadJSON(createStyleJSON({
|
|
2376
|
+
'sources': {
|
|
2377
|
+
'streets': createGeoJSONSource(),
|
|
2378
|
+
'terrain': createGeoJSONSource()
|
|
2379
|
+
}
|
|
2380
|
+
}));
|
|
2381
|
+
|
|
2382
|
+
await style.once('style.load');
|
|
2383
|
+
style.update({} as EvaluationParameters);
|
|
2384
|
+
|
|
2385
|
+
// spies to track deferred methods
|
|
2386
|
+
const mockStyleFire = jest.spyOn(style, 'fire');
|
|
2387
|
+
jest.spyOn(style, '_reloadSource');
|
|
2388
|
+
jest.spyOn(style, '_updateWorkerLayers');
|
|
2389
|
+
|
|
2390
|
+
style.addLayer({id: 'first', type: 'symbol', source: 'streets'});
|
|
2391
|
+
style.addLayer({id: 'second', type: 'symbol', source: 'streets'});
|
|
2392
|
+
style.addLayer({id: 'third', type: 'symbol', source: 'terrain'});
|
|
2393
|
+
|
|
2394
|
+
style.setPaintProperty('first', 'text-color', 'black');
|
|
2395
|
+
style.setPaintProperty('first', 'text-halo-color', 'white');
|
|
2396
|
+
|
|
2397
|
+
expect(style.fire).not.toHaveBeenCalled();
|
|
2398
|
+
expect(style._reloadSource).not.toHaveBeenCalled();
|
|
2399
|
+
expect(style._updateWorkerLayers).not.toHaveBeenCalled();
|
|
2400
|
+
|
|
2401
|
+
style.update({} as EvaluationParameters);
|
|
2402
|
+
|
|
2403
|
+
expect(mockStyleFire.mock.calls[0][0]['type']).toBe('data');
|
|
2404
|
+
|
|
2405
|
+
// called per source
|
|
2406
|
+
expect(style._reloadSource).toHaveBeenCalledTimes(2);
|
|
2407
|
+
expect(style._reloadSource).toHaveBeenCalledWith('streets');
|
|
2408
|
+
expect(style._reloadSource).toHaveBeenCalledWith('terrain');
|
|
2409
|
+
|
|
2410
|
+
// called once
|
|
2411
|
+
expect(style._updateWorkerLayers).toHaveBeenCalledTimes(1);
|
|
2412
|
+
});
|
|
2413
|
+
});
|
|
2414
|
+
|
|
2415
|
+
describe('Style#query*Features', () => {
|
|
2416
|
+
|
|
2417
|
+
// These tests only cover filter validation. Most tests for these methods
|
|
2418
|
+
// live in the integration tests.
|
|
2419
|
+
|
|
2420
|
+
let style;
|
|
2421
|
+
let onError;
|
|
2422
|
+
let transform;
|
|
2423
|
+
|
|
2424
|
+
beforeEach(() => new Promise<void>(callback => {
|
|
2425
|
+
transform = new Transform();
|
|
2426
|
+
transform.resize(100, 100);
|
|
2427
|
+
style = new Style(getStubMap());
|
|
2428
|
+
style.loadJSON({
|
|
2429
|
+
'version': 8,
|
|
2430
|
+
'sources': {
|
|
2431
|
+
'geojson': createGeoJSONSource()
|
|
2432
|
+
},
|
|
2433
|
+
'layers': [{
|
|
2434
|
+
'id': 'symbol',
|
|
2435
|
+
'type': 'symbol',
|
|
2436
|
+
'source': 'geojson'
|
|
2437
|
+
}]
|
|
2438
|
+
});
|
|
2439
|
+
|
|
2440
|
+
onError = jest.fn();
|
|
2441
|
+
|
|
2442
|
+
style.on('error', onError)
|
|
2443
|
+
.on('style.load', () => {
|
|
2444
|
+
callback();
|
|
2445
|
+
});
|
|
2446
|
+
}));
|
|
2447
|
+
|
|
2448
|
+
test('querySourceFeatures emits an error on incorrect filter', () => {
|
|
2449
|
+
expect(style.querySourceFeatures([10, 100], {filter: 7}, transform)).toEqual([]);
|
|
2450
|
+
expect(onError.mock.calls[0][0].error.message).toMatch(/querySourceFeatures\.filter/);
|
|
2451
|
+
});
|
|
2452
|
+
|
|
2453
|
+
test('queryRenderedFeatures emits an error on incorrect filter', () => {
|
|
2454
|
+
expect(style.queryRenderedFeatures([{x: 0, y: 0}], {filter: 7}, transform)).toEqual([]);
|
|
2455
|
+
expect(onError.mock.calls[0][0].error.message).toMatch(/queryRenderedFeatures\.filter/);
|
|
2456
|
+
});
|
|
2457
|
+
|
|
2458
|
+
test('querySourceFeatures not raise validation errors if validation was disabled', () => {
|
|
2459
|
+
let errors = 0;
|
|
2460
|
+
jest.spyOn(style, 'fire').mockImplementation((event) => {
|
|
2461
|
+
if (event['error']) {
|
|
2462
|
+
errors++;
|
|
2463
|
+
}
|
|
2464
|
+
});
|
|
2465
|
+
style.queryRenderedFeatures([{x: 0, y: 0}], {filter: 'invalidFilter', validate: false}, transform);
|
|
2466
|
+
expect(errors).toBe(0);
|
|
2467
|
+
});
|
|
2468
|
+
|
|
2469
|
+
test('querySourceFeatures not raise validation errors if validation was disabled', () => {
|
|
2470
|
+
let errors = 0;
|
|
2471
|
+
jest.spyOn(style, 'fire').mockImplementation((event) => {
|
|
2472
|
+
if (event['error']) errors++;
|
|
2473
|
+
});
|
|
2474
|
+
style.querySourceFeatures([{x: 0, y: 0}], {filter: 'invalidFilter', validate: false}, transform);
|
|
2475
|
+
expect(errors).toBe(0);
|
|
2476
|
+
});
|
|
2477
|
+
|
|
2478
|
+
test('serialized layers should be correctly updated after adding/removing layers', () => {
|
|
2479
|
+
|
|
2480
|
+
let serializedStyle = style.serialize();
|
|
2481
|
+
expect(serializedStyle.layers).toHaveLength(1);
|
|
2482
|
+
expect(serializedStyle.layers[0].id).toBe('symbol');
|
|
2483
|
+
|
|
2484
|
+
const layer = {
|
|
2485
|
+
id: 'background',
|
|
2486
|
+
type: 'background'
|
|
2487
|
+
} as LayerSpecification;
|
|
2488
|
+
style.addLayer(layer);
|
|
2489
|
+
|
|
2490
|
+
// serialize again
|
|
2491
|
+
serializedStyle = style.serialize();
|
|
2492
|
+
expect(serializedStyle.layers).toHaveLength(2);
|
|
2493
|
+
expect(serializedStyle.layers[1].id).toBe('background');
|
|
2494
|
+
|
|
2495
|
+
// remove and serialize
|
|
2496
|
+
style.removeLayer('background');
|
|
2497
|
+
serializedStyle = style.serialize();
|
|
2498
|
+
expect(serializedStyle.layers).toHaveLength(1);
|
|
2499
|
+
|
|
2500
|
+
});
|
|
2501
|
+
});
|
|
2502
|
+
|
|
2503
|
+
describe('Style#hasTransitions', () => {
|
|
2504
|
+
test('returns false when the style is loading', () => {
|
|
2505
|
+
const style = new Style(getStubMap());
|
|
2506
|
+
expect(style.hasTransitions()).toBe(false);
|
|
2507
|
+
});
|
|
2508
|
+
|
|
2509
|
+
test('returns true when a property is transitioning', async () => {
|
|
2510
|
+
const style = new Style(getStubMap());
|
|
2511
|
+
style.loadJSON({
|
|
2512
|
+
'version': 8,
|
|
2513
|
+
'sources': {},
|
|
2514
|
+
'layers': [{
|
|
2515
|
+
'id': 'background',
|
|
2516
|
+
'type': 'background'
|
|
2517
|
+
}]
|
|
2518
|
+
});
|
|
2519
|
+
|
|
2520
|
+
await style.once('style.load');
|
|
2521
|
+
style.setPaintProperty('background', 'background-color', 'blue');
|
|
2522
|
+
style.update({transition: {duration: 300, delay: 0}} as EvaluationParameters);
|
|
2523
|
+
expect(style.hasTransitions()).toBe(true);
|
|
2524
|
+
});
|
|
2525
|
+
|
|
2526
|
+
test('returns false when a property is not transitioning', async () => {
|
|
2527
|
+
const style = new Style(getStubMap());
|
|
2528
|
+
style.loadJSON({
|
|
2529
|
+
'version': 8,
|
|
2530
|
+
'sources': {},
|
|
2531
|
+
'layers': [{
|
|
2532
|
+
'id': 'background',
|
|
2533
|
+
'type': 'background'
|
|
2534
|
+
}]
|
|
2535
|
+
});
|
|
2536
|
+
|
|
2537
|
+
await style.once('style.load');
|
|
2538
|
+
style.setPaintProperty('background', 'background-color', 'blue');
|
|
2539
|
+
style.update({transition: {duration: 0, delay: 0}} as EvaluationParameters);
|
|
2540
|
+
expect(style.hasTransitions()).toBe(false);
|
|
2541
|
+
});
|
|
2542
|
+
});
|
|
2543
|
+
|
|
2544
|
+
describe('Style#serialize', () => {
|
|
2545
|
+
test('include terrain property when map has 3D terrain', async () => {
|
|
2546
|
+
const terrain = {
|
|
2547
|
+
source: 'terrainSource',
|
|
2548
|
+
exaggeration: 1
|
|
2549
|
+
};
|
|
2550
|
+
const styleJson = createStyleJSON({terrain});
|
|
2551
|
+
const style = new Style(getStubMap());
|
|
2552
|
+
style.loadJSON(styleJson);
|
|
2553
|
+
|
|
2554
|
+
await style.once('style.load');
|
|
2555
|
+
expect(style.serialize().terrain).toBe(terrain);
|
|
2556
|
+
});
|
|
2557
|
+
|
|
2558
|
+
test('do not include terrain property when map does not have 3D terrain', async () => {
|
|
2559
|
+
const style = new Style(getStubMap());
|
|
2560
|
+
style.loadJSON(createStyleJSON());
|
|
2561
|
+
|
|
2562
|
+
await style.once('style.load');
|
|
2563
|
+
expect(style.serialize().terrain).toBeUndefined();
|
|
2564
|
+
});
|
|
2565
|
+
|
|
2566
|
+
test('include sky property when map has sky', async () => {
|
|
2567
|
+
const sky: SkySpecification = {
|
|
2568
|
+
'horizon-fog-blend': 0.5,
|
|
2569
|
+
'fog-color': '#fff'
|
|
2570
|
+
};
|
|
2571
|
+
const styleJson = createStyleJSON({sky});
|
|
2572
|
+
const style = new Style(getStubMap());
|
|
2573
|
+
style.loadJSON(styleJson);
|
|
2574
|
+
|
|
2575
|
+
await style.once('style.load');
|
|
2576
|
+
expect(style.serialize().sky).toStrictEqual(sky);
|
|
2577
|
+
});
|
|
2578
|
+
|
|
2579
|
+
test('do not include sky property when map does not have sky', async () => {
|
|
2580
|
+
const style = new Style(getStubMap());
|
|
2581
|
+
style.loadJSON(createStyleJSON());
|
|
2582
|
+
|
|
2583
|
+
await style.once('style.load');
|
|
2584
|
+
expect(style.serialize().sky).toBeUndefined();
|
|
2585
|
+
});
|
|
2586
|
+
|
|
2587
|
+
test('sky should be undefined when map does not have sky', async () => {
|
|
2588
|
+
const style = new Style(getStubMap());
|
|
2589
|
+
style.loadJSON(createStyleJSON());
|
|
2590
|
+
|
|
2591
|
+
await style.once('style.load');
|
|
2592
|
+
expect(style.getSky()).toBeUndefined();
|
|
2593
|
+
});
|
|
2594
|
+
|
|
2595
|
+
test('sky should be defined even after setting it to undefined and back', async () => {
|
|
2596
|
+
const sky: SkySpecification = {
|
|
2597
|
+
'horizon-fog-blend': 0.5,
|
|
2598
|
+
'fog-color': '#fff'
|
|
2599
|
+
};
|
|
2600
|
+
const styleJson = createStyleJSON({sky});
|
|
2601
|
+
const style = new Style(getStubMap());
|
|
2602
|
+
style.loadJSON(styleJson);
|
|
2603
|
+
|
|
2604
|
+
await style.once('style.load');
|
|
2605
|
+
style.setSky(undefined);
|
|
2606
|
+
expect(style.serialize().sky).toBeUndefined();
|
|
2607
|
+
style.setSky(sky);
|
|
2608
|
+
expect(style.serialize().sky).toBeDefined();
|
|
2609
|
+
style.setSky(undefined);
|
|
2610
|
+
expect(style.serialize().sky).toBeUndefined();
|
|
2611
|
+
});
|
|
2612
|
+
|
|
2613
|
+
test('do not include sky property after removing sky from the map', async () => {
|
|
2614
|
+
const sky: SkySpecification = {
|
|
2615
|
+
'horizon-fog-blend': 0.5,
|
|
2616
|
+
'fog-color': '#fff'
|
|
2617
|
+
};
|
|
2618
|
+
const styleJson = createStyleJSON({sky});
|
|
2619
|
+
const style = new Style(getStubMap());
|
|
2620
|
+
style.loadJSON(styleJson);
|
|
2621
|
+
|
|
2622
|
+
await style.once('style.load');
|
|
2623
|
+
style.setSky(undefined);
|
|
2624
|
+
expect(style.serialize().sky).toBeUndefined();
|
|
2625
|
+
});
|
|
2626
|
+
|
|
2627
|
+
test('include sky property when setting it after map loads', async () => {
|
|
2628
|
+
const style = new Style(getStubMap());
|
|
2629
|
+
style.loadJSON(createStyleJSON());
|
|
2630
|
+
|
|
2631
|
+
await style.once('style.load');
|
|
2632
|
+
style.setSky({
|
|
2633
|
+
'horizon-fog-blend': 0.5,
|
|
2634
|
+
'fog-color': '#fff'
|
|
2635
|
+
});
|
|
2636
|
+
expect(style.serialize().sky).toBeDefined();
|
|
2637
|
+
});
|
|
2638
|
+
|
|
2639
|
+
test('update sky properties after setting the sky on initial load', async () => {
|
|
2640
|
+
const sky: SkySpecification = {
|
|
2641
|
+
'fog-color': '#FF0000'
|
|
2642
|
+
};
|
|
2643
|
+
const style = new Style(getStubMap());
|
|
2644
|
+
style.loadJSON(createStyleJSON({sky, transition: {duration: 0, delay: 0}}));
|
|
2645
|
+
|
|
2646
|
+
await style.once('style.load');
|
|
2647
|
+
style.setSky({
|
|
2648
|
+
'fog-color': '#00FF00'
|
|
2649
|
+
});
|
|
2650
|
+
style.update({transition: {duration: 0, delay: 0}} as EvaluationParameters);
|
|
2651
|
+
expect(style.sky.properties.get('fog-color').g).toBe(1);
|
|
2652
|
+
expect(style.sky.properties.get('fog-color').r).toBe(0);
|
|
2653
|
+
});
|
|
2654
|
+
});
|