@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,399 @@
|
|
|
1
|
+
import {GeoJSONWorkerSource, LoadGeoJSONParameters} from './geojson_worker_source';
|
|
2
|
+
import {StyleLayerIndex} from '../style/style_layer_index';
|
|
3
|
+
import {OverscaledTileID} from './tile_id';
|
|
4
|
+
import perf from '../util/performance';
|
|
5
|
+
import {LayerSpecification} from '@maplibre/maplibre-gl-style-spec';
|
|
6
|
+
import {Actor} from '../util/actor';
|
|
7
|
+
import {WorkerTileParameters} from './worker_source';
|
|
8
|
+
import {setPerformance, sleep} from '../util/test/util';
|
|
9
|
+
import {type FakeServer, fakeServer} from 'nise';
|
|
10
|
+
|
|
11
|
+
const actor = {send: () => {}} as any as Actor;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
setPerformance();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('reloadTile', () => {
|
|
18
|
+
test('does not rebuild vector data unless data has changed', async () => {
|
|
19
|
+
const layers = [
|
|
20
|
+
{
|
|
21
|
+
id: 'mylayer',
|
|
22
|
+
source: 'sourceId',
|
|
23
|
+
type: 'symbol',
|
|
24
|
+
}
|
|
25
|
+
] as LayerSpecification[];
|
|
26
|
+
const layerIndex = new StyleLayerIndex(layers);
|
|
27
|
+
const source = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
28
|
+
const spy = jest.spyOn(source, 'loadVectorTile');
|
|
29
|
+
const geoJson = {
|
|
30
|
+
'type': 'Feature',
|
|
31
|
+
'geometry': {
|
|
32
|
+
'type': 'Point',
|
|
33
|
+
'coordinates': [0, 0]
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const tileParams = {
|
|
37
|
+
source: 'sourceId',
|
|
38
|
+
uid: 0,
|
|
39
|
+
tileID: new OverscaledTileID(0, 0, 0, 0, 0),
|
|
40
|
+
maxZoom: 10
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
await source.loadData({source: 'sourceId', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters);
|
|
44
|
+
|
|
45
|
+
// first call should load vector data from geojson
|
|
46
|
+
const firstData = await source.reloadTile(tileParams as any as WorkerTileParameters);
|
|
47
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
48
|
+
|
|
49
|
+
// second call won't give us new rawTileData
|
|
50
|
+
let data = await source.reloadTile(tileParams as any as WorkerTileParameters);
|
|
51
|
+
expect('rawTileData' in data).toBeFalsy();
|
|
52
|
+
data.rawTileData = firstData.rawTileData;
|
|
53
|
+
expect(data).toEqual(firstData);
|
|
54
|
+
|
|
55
|
+
// also shouldn't call loadVectorData again
|
|
56
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
57
|
+
|
|
58
|
+
// replace geojson data
|
|
59
|
+
await source.loadData({source: 'sourceId', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters);
|
|
60
|
+
|
|
61
|
+
// should call loadVectorData again after changing geojson data
|
|
62
|
+
data = await source.reloadTile(tileParams as any as WorkerTileParameters);
|
|
63
|
+
expect('rawTileData' in data).toBeTruthy();
|
|
64
|
+
expect(data).toEqual(firstData);
|
|
65
|
+
expect(spy).toHaveBeenCalledTimes(2);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('resourceTiming', () => {
|
|
71
|
+
|
|
72
|
+
const layers = [
|
|
73
|
+
{
|
|
74
|
+
id: 'mylayer',
|
|
75
|
+
source: 'sourceId',
|
|
76
|
+
type: 'symbol',
|
|
77
|
+
}
|
|
78
|
+
] as LayerSpecification[];
|
|
79
|
+
const geoJson = {
|
|
80
|
+
'type': 'Feature',
|
|
81
|
+
'geometry': {
|
|
82
|
+
'type': 'Point',
|
|
83
|
+
'coordinates': [0, 0]
|
|
84
|
+
}
|
|
85
|
+
} as GeoJSON.GeoJSON;
|
|
86
|
+
|
|
87
|
+
test('loadData - url', async () => {
|
|
88
|
+
const exampleResourceTiming = {
|
|
89
|
+
connectEnd: 473,
|
|
90
|
+
connectStart: 473,
|
|
91
|
+
decodedBodySize: 86494,
|
|
92
|
+
domainLookupEnd: 473,
|
|
93
|
+
domainLookupStart: 473,
|
|
94
|
+
duration: 341,
|
|
95
|
+
encodedBodySize: 52528,
|
|
96
|
+
entryType: 'resource',
|
|
97
|
+
fetchStart: 473.5,
|
|
98
|
+
initiatorType: 'xmlhttprequest',
|
|
99
|
+
name: 'http://localhost:2900/fake.geojson',
|
|
100
|
+
nextHopProtocol: 'http/1.1',
|
|
101
|
+
redirectEnd: 0,
|
|
102
|
+
redirectStart: 0,
|
|
103
|
+
requestStart: 477,
|
|
104
|
+
responseEnd: 815,
|
|
105
|
+
responseStart: 672,
|
|
106
|
+
secureConnectionStart: 0
|
|
107
|
+
} as any as PerformanceEntry;
|
|
108
|
+
|
|
109
|
+
window.performance.getEntriesByName = jest.fn().mockReturnValue([exampleResourceTiming]);
|
|
110
|
+
|
|
111
|
+
const layerIndex = new StyleLayerIndex(layers);
|
|
112
|
+
const source = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
113
|
+
source.loadGeoJSON = () => Promise.resolve(geoJson);
|
|
114
|
+
|
|
115
|
+
const result = await source.loadData({source: 'testSource', request: {url: 'http://localhost/nonexistent', collectResourceTiming: true}} as LoadGeoJSONParameters);
|
|
116
|
+
|
|
117
|
+
expect(result.resourceTiming.testSource).toEqual([exampleResourceTiming]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('loadData - url (resourceTiming fallback method)', async () => {
|
|
121
|
+
const sampleMarks = [100, 350];
|
|
122
|
+
const marks = {};
|
|
123
|
+
const measures = {};
|
|
124
|
+
window.performance.getEntriesByName = jest.fn().mockImplementation((name) => { return measures[name] || []; });
|
|
125
|
+
jest.spyOn(perf, 'mark').mockImplementation((name) => {
|
|
126
|
+
marks[name] = sampleMarks.shift();
|
|
127
|
+
return null;
|
|
128
|
+
});
|
|
129
|
+
window.performance.measure = jest.fn().mockImplementation((name, start, end) => {
|
|
130
|
+
measures[name] = measures[name] || [];
|
|
131
|
+
measures[name].push({
|
|
132
|
+
duration: marks[end] - marks[start],
|
|
133
|
+
entryType: 'measure',
|
|
134
|
+
name,
|
|
135
|
+
startTime: marks[start]
|
|
136
|
+
});
|
|
137
|
+
return null;
|
|
138
|
+
});
|
|
139
|
+
jest.spyOn(perf, 'clearMarks').mockImplementation(() => { return null; });
|
|
140
|
+
jest.spyOn(perf, 'clearMeasures').mockImplementation(() => { return null; });
|
|
141
|
+
|
|
142
|
+
const layerIndex = new StyleLayerIndex(layers);
|
|
143
|
+
const source = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
144
|
+
source.loadGeoJSON = () => Promise.resolve(geoJson);
|
|
145
|
+
|
|
146
|
+
const result = await source.loadData({source: 'testSource', request: {url: 'http://localhost/nonexistent', collectResourceTiming: true}} as LoadGeoJSONParameters);
|
|
147
|
+
|
|
148
|
+
expect(result.resourceTiming.testSource).toEqual(
|
|
149
|
+
[{'duration': 250, 'entryType': 'measure', 'name': 'http://localhost/nonexistent', 'startTime': 100}]
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('loadData - data', async () => {
|
|
154
|
+
const layerIndex = new StyleLayerIndex(layers);
|
|
155
|
+
const source = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
156
|
+
|
|
157
|
+
const result = await source.loadData({source: 'testSource', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters);
|
|
158
|
+
expect(result.resourceTiming).toBeUndefined();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe('loadData', () => {
|
|
164
|
+
let server: FakeServer;
|
|
165
|
+
beforeEach(() => {
|
|
166
|
+
global.fetch = null;
|
|
167
|
+
server = fakeServer.create();
|
|
168
|
+
});
|
|
169
|
+
afterEach(() => {
|
|
170
|
+
server.restore();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const layers = [
|
|
174
|
+
{
|
|
175
|
+
id: 'layer1',
|
|
176
|
+
source: 'source1',
|
|
177
|
+
type: 'symbol',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: 'layer2',
|
|
181
|
+
source: 'source2',
|
|
182
|
+
type: 'symbol',
|
|
183
|
+
}
|
|
184
|
+
] as LayerSpecification[];
|
|
185
|
+
|
|
186
|
+
const geoJson = {
|
|
187
|
+
'type': 'Feature',
|
|
188
|
+
'geometry': {
|
|
189
|
+
'type': 'Point',
|
|
190
|
+
'coordinates': [0, 0]
|
|
191
|
+
}
|
|
192
|
+
} as GeoJSON.GeoJSON;
|
|
193
|
+
|
|
194
|
+
const updateableGeoJson = {
|
|
195
|
+
type: 'Feature',
|
|
196
|
+
id: 'point',
|
|
197
|
+
geometry: {
|
|
198
|
+
type: 'Point',
|
|
199
|
+
coordinates: [0, 0],
|
|
200
|
+
},
|
|
201
|
+
properties: {},
|
|
202
|
+
} as GeoJSON.GeoJSON;
|
|
203
|
+
|
|
204
|
+
const layerIndex = new StyleLayerIndex(layers);
|
|
205
|
+
function createWorker() {
|
|
206
|
+
return new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
test('abandons previous requests', async () => {
|
|
210
|
+
const worker = createWorker();
|
|
211
|
+
|
|
212
|
+
server.respondWith(request => {
|
|
213
|
+
request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(geoJson));
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const p1 = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters);
|
|
217
|
+
await sleep(0);
|
|
218
|
+
|
|
219
|
+
const p2 = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters);
|
|
220
|
+
|
|
221
|
+
await sleep(0);
|
|
222
|
+
|
|
223
|
+
server.respond();
|
|
224
|
+
|
|
225
|
+
const firstCallResult = await p1;
|
|
226
|
+
expect(firstCallResult && firstCallResult.abandoned).toBeTruthy();
|
|
227
|
+
const result = await p2;
|
|
228
|
+
expect(result && result.abandoned).toBeFalsy();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('removeSource aborts requests', async () => {
|
|
232
|
+
const worker = createWorker();
|
|
233
|
+
|
|
234
|
+
server.respondWith(request => {
|
|
235
|
+
request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(geoJson));
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const loadPromise = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters);
|
|
239
|
+
await sleep(0);
|
|
240
|
+
const removePromise = worker.removeSource({source: 'source1', type: 'type'});
|
|
241
|
+
await sleep(0);
|
|
242
|
+
|
|
243
|
+
server.respond();
|
|
244
|
+
|
|
245
|
+
const result = await loadPromise;
|
|
246
|
+
expect(result && result.abandoned).toBeTruthy();
|
|
247
|
+
await removePromise;
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test('loadData with geojson creates an non-updateable source', async () => {
|
|
251
|
+
const worker = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
252
|
+
|
|
253
|
+
await worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters);
|
|
254
|
+
await expect(worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters)).rejects.toBeDefined();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('loadData with geojson creates an updateable source', async () => {
|
|
258
|
+
const worker = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
259
|
+
|
|
260
|
+
await worker.loadData({source: 'source1', data: JSON.stringify(updateableGeoJson)} as LoadGeoJSONParameters);
|
|
261
|
+
await expect(worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters)).resolves.toBeDefined();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test('loadData with geojson network call creates an updateable source', async () => {
|
|
265
|
+
const worker = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
266
|
+
|
|
267
|
+
server.respondWith(request => {
|
|
268
|
+
request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(updateableGeoJson));
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const load1Promise = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters);
|
|
272
|
+
server.respond();
|
|
273
|
+
|
|
274
|
+
await load1Promise;
|
|
275
|
+
await expect(worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters)).resolves.toBeDefined();
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test('loadData with geojson network call creates a non-updateable source', async () => {
|
|
279
|
+
const worker = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
280
|
+
|
|
281
|
+
server.respondWith(request => {
|
|
282
|
+
request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(geoJson));
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const promise = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters);
|
|
286
|
+
|
|
287
|
+
server.respond();
|
|
288
|
+
|
|
289
|
+
await promise;
|
|
290
|
+
|
|
291
|
+
await expect(worker.loadData({source: 'source1', dataDiff: {removeAll: true}} as LoadGeoJSONParameters)).rejects.toBeDefined();
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test('loadData with diff updates', async () => {
|
|
295
|
+
const worker = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
296
|
+
|
|
297
|
+
await worker.loadData({source: 'source1', data: JSON.stringify(updateableGeoJson)} as LoadGeoJSONParameters);
|
|
298
|
+
await expect(worker.loadData({source: 'source1', dataDiff: {
|
|
299
|
+
add: [{
|
|
300
|
+
type: 'Feature',
|
|
301
|
+
id: 'update_point',
|
|
302
|
+
geometry: {type: 'Point', coordinates: [0, 0]},
|
|
303
|
+
properties: {}
|
|
304
|
+
}]
|
|
305
|
+
}} as LoadGeoJSONParameters)).resolves.toBeDefined();
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
describe('getData', () => {
|
|
310
|
+
let server: FakeServer;
|
|
311
|
+
beforeEach(() => {
|
|
312
|
+
global.fetch = null;
|
|
313
|
+
server = fakeServer.create();
|
|
314
|
+
});
|
|
315
|
+
afterEach(() => {
|
|
316
|
+
server.restore();
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const layers = [
|
|
320
|
+
{
|
|
321
|
+
id: 'layer1',
|
|
322
|
+
source: 'source1',
|
|
323
|
+
type: 'symbol',
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
id: 'layer2',
|
|
327
|
+
source: 'source2',
|
|
328
|
+
type: 'symbol',
|
|
329
|
+
}
|
|
330
|
+
] as LayerSpecification[];
|
|
331
|
+
|
|
332
|
+
const geoJson = {
|
|
333
|
+
'type': 'Feature',
|
|
334
|
+
'geometry': {
|
|
335
|
+
'type': 'Point',
|
|
336
|
+
'coordinates': [0, 0]
|
|
337
|
+
}
|
|
338
|
+
} as GeoJSON.GeoJSON;
|
|
339
|
+
|
|
340
|
+
const updateableGeoJson = {
|
|
341
|
+
type: 'Feature',
|
|
342
|
+
id: 'point',
|
|
343
|
+
geometry: {
|
|
344
|
+
type: 'Point',
|
|
345
|
+
coordinates: [0, 0],
|
|
346
|
+
},
|
|
347
|
+
properties: {},
|
|
348
|
+
} as GeoJSON.GeoJSON;
|
|
349
|
+
|
|
350
|
+
const layerIndex = new StyleLayerIndex(layers);
|
|
351
|
+
|
|
352
|
+
test('getData returns correct geojson when the source was loaded with geojson', async () => {
|
|
353
|
+
const worker = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
354
|
+
|
|
355
|
+
await worker.loadData({source: 'source1', data: JSON.stringify(geoJson)} as LoadGeoJSONParameters);
|
|
356
|
+
await expect(worker.getData()).resolves.toStrictEqual(geoJson);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
test('getData after a geojson network call returns actual loaded geojson', async () => {
|
|
360
|
+
const worker = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
361
|
+
|
|
362
|
+
server.respondWith(request => {
|
|
363
|
+
request.respond(200, {'Content-Type': 'application/json'}, JSON.stringify(updateableGeoJson));
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
const load1Promise = worker.loadData({source: 'source1', request: {url: ''}} as LoadGeoJSONParameters);
|
|
367
|
+
server.respond();
|
|
368
|
+
|
|
369
|
+
await load1Promise;
|
|
370
|
+
await expect(worker.getData()).resolves.toStrictEqual(updateableGeoJson);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
test('getData after diff updates returns updated geojson', async () => {
|
|
374
|
+
const worker = new GeoJSONWorkerSource(actor, layerIndex, []);
|
|
375
|
+
|
|
376
|
+
await worker.loadData({source: 'source1', data: JSON.stringify(updateableGeoJson)} as LoadGeoJSONParameters);
|
|
377
|
+
await expect(worker.loadData({source: 'source1', dataDiff: {
|
|
378
|
+
add: [{
|
|
379
|
+
type: 'Feature',
|
|
380
|
+
id: 'update_point',
|
|
381
|
+
geometry: {type: 'Point', coordinates: [0, 0]},
|
|
382
|
+
properties: {}
|
|
383
|
+
}]
|
|
384
|
+
}} as LoadGeoJSONParameters)).resolves.toBeDefined();
|
|
385
|
+
|
|
386
|
+
await expect(worker.getData()).resolves.toStrictEqual({
|
|
387
|
+
type: 'FeatureCollection',
|
|
388
|
+
features: [
|
|
389
|
+
{...updateableGeoJson},
|
|
390
|
+
{
|
|
391
|
+
type: 'Feature',
|
|
392
|
+
id: 'update_point',
|
|
393
|
+
geometry: {type: 'Point', coordinates: [0, 0]},
|
|
394
|
+
properties: {}
|
|
395
|
+
}
|
|
396
|
+
]
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
});
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import {getJSON} from '../util/ajax';
|
|
2
|
+
import {RequestPerformance} from '../util/performance';
|
|
3
|
+
import rewind from '@mapbox/geojson-rewind';
|
|
4
|
+
import {GeoJSONWrapper} from './geojson_wrapper';
|
|
5
|
+
import vtpbf from 'vt-pbf';
|
|
6
|
+
import Supercluster, {type Options as SuperclusterOptions, type ClusterProperties} from 'supercluster';
|
|
7
|
+
import geojsonvt, {type Options as GeoJSONVTOptions} from 'geojson-vt';
|
|
8
|
+
import {VectorTileWorkerSource} from './vector_tile_worker_source';
|
|
9
|
+
import {createExpression} from '@maplibre/maplibre-gl-style-spec';
|
|
10
|
+
import {isAbortError} from '../util/abort_error';
|
|
11
|
+
|
|
12
|
+
import type {
|
|
13
|
+
WorkerTileParameters,
|
|
14
|
+
WorkerTileResult,
|
|
15
|
+
} from '../source/worker_source';
|
|
16
|
+
|
|
17
|
+
import type {LoadVectorTileResult} from './vector_tile_worker_source';
|
|
18
|
+
import type {RequestParameters} from '../util/ajax';
|
|
19
|
+
import {isUpdateableGeoJSON, type GeoJSONSourceDiff, applySourceDiff, toUpdateable, GeoJSONFeatureId} from './geojson_source_diff';
|
|
20
|
+
import type {ClusterIDAndSource, GeoJSONWorkerSourceLoadDataResult, RemoveSourceParams} from '../util/actor_messages';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The geojson worker options that can be passed to the worker
|
|
24
|
+
*/
|
|
25
|
+
export type GeoJSONWorkerOptions = {
|
|
26
|
+
source?: string;
|
|
27
|
+
cluster?: boolean;
|
|
28
|
+
geojsonVtOptions?: GeoJSONVTOptions;
|
|
29
|
+
superclusterOptions?: SuperclusterOptions<any, any>;
|
|
30
|
+
clusterProperties?: ClusterProperties;
|
|
31
|
+
filter?: Array<unknown>;
|
|
32
|
+
promoteId?: string;
|
|
33
|
+
collectResourceTiming?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Parameters needed to load a geojson to the worker
|
|
38
|
+
*/
|
|
39
|
+
export type LoadGeoJSONParameters = GeoJSONWorkerOptions & {
|
|
40
|
+
type: 'geojson';
|
|
41
|
+
request?: RequestParameters;
|
|
42
|
+
/**
|
|
43
|
+
* Literal GeoJSON data. Must be provided if `request.url` is not.
|
|
44
|
+
*/
|
|
45
|
+
data?: string;
|
|
46
|
+
dataDiff?: GeoJSONSourceDiff;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type LoadGeoJSON = (params: LoadGeoJSONParameters, abortController: AbortController) => Promise<GeoJSON.GeoJSON>;
|
|
50
|
+
|
|
51
|
+
type GeoJSONIndex = ReturnType<typeof geojsonvt> | Supercluster;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The {@link WorkerSource} implementation that supports {@link GeoJSONSource}.
|
|
55
|
+
* This class is designed to be easily reused to support custom source types
|
|
56
|
+
* for data formats that can be parsed/converted into an in-memory GeoJSON
|
|
57
|
+
* representation. To do so, create it with
|
|
58
|
+
* `new GeoJSONWorkerSource(actor, layerIndex, customLoadGeoJSONFunction)`.
|
|
59
|
+
* For a full example, see [mapbox-gl-topojson](https://github.com/developmentseed/mapbox-gl-topojson).
|
|
60
|
+
*/
|
|
61
|
+
export class GeoJSONWorkerSource extends VectorTileWorkerSource {
|
|
62
|
+
/**
|
|
63
|
+
* The actual GeoJSON takes some time to load (as there may be a need to parse a diff, or to apply filters, or the
|
|
64
|
+
* data may even need to be loaded via a URL). This promise resolves with a ready-to-be-consumed GeoJSON which is
|
|
65
|
+
* ready to be returned by the `getData` method.
|
|
66
|
+
*/
|
|
67
|
+
_pendingData: Promise<GeoJSON.GeoJSON>;
|
|
68
|
+
_pendingRequest: AbortController;
|
|
69
|
+
_geoJSONIndex: GeoJSONIndex;
|
|
70
|
+
_dataUpdateable = new Map<GeoJSONFeatureId, GeoJSON.Feature>();
|
|
71
|
+
|
|
72
|
+
override async loadVectorTile(params: WorkerTileParameters, _abortController: AbortController): Promise<LoadVectorTileResult | null> {
|
|
73
|
+
const canonical = params.tileID.canonical;
|
|
74
|
+
|
|
75
|
+
if (!this._geoJSONIndex) {
|
|
76
|
+
throw new Error('Unable to parse the data into a cluster or geojson');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const geoJSONTile = this._geoJSONIndex.getTile(canonical.z, canonical.x, canonical.y);
|
|
80
|
+
if (!geoJSONTile) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const geojsonWrapper = new GeoJSONWrapper(geoJSONTile.features);
|
|
85
|
+
// Encode the geojson-vt tile into binary vector tile form. This
|
|
86
|
+
// is a convenience that allows `FeatureIndex` to operate the same way
|
|
87
|
+
// across `VectorTileSource` and `GeoJSONSource` data.
|
|
88
|
+
let pbf = vtpbf(geojsonWrapper);
|
|
89
|
+
if (pbf.byteOffset !== 0 || pbf.byteLength !== pbf.buffer.byteLength) {
|
|
90
|
+
// Compatibility with node Buffer (https://github.com/mapbox/pbf/issues/35)
|
|
91
|
+
pbf = new Uint8Array(pbf);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
vectorTile: geojsonWrapper,
|
|
96
|
+
rawData: pbf.buffer
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Fetches (if appropriate), parses, and index geojson data into tiles. This
|
|
102
|
+
* preparatory method must be called before {@link GeoJSONWorkerSource#loadTile}
|
|
103
|
+
* can correctly serve up tiles.
|
|
104
|
+
*
|
|
105
|
+
* Defers to {@link GeoJSONWorkerSource#loadAndProcessGeoJSON} for the pre-processing.
|
|
106
|
+
*
|
|
107
|
+
* When a `loadData` request comes in while a previous one is being processed,
|
|
108
|
+
* the previous one is aborted.
|
|
109
|
+
*
|
|
110
|
+
* @param params - the parameters
|
|
111
|
+
* @returns a promise that resolves when the data is loaded and parsed into a GeoJSON object
|
|
112
|
+
*/
|
|
113
|
+
async loadData(params: LoadGeoJSONParameters): Promise<GeoJSONWorkerSourceLoadDataResult> {
|
|
114
|
+
this._pendingRequest?.abort();
|
|
115
|
+
const perf = (params && params.request && params.request.collectResourceTiming) ?
|
|
116
|
+
new RequestPerformance(params.request) : false;
|
|
117
|
+
|
|
118
|
+
this._pendingRequest = new AbortController();
|
|
119
|
+
try {
|
|
120
|
+
this._pendingData = this.loadAndProcessGeoJSON(params, this._pendingRequest);
|
|
121
|
+
|
|
122
|
+
this._geoJSONIndex = params.cluster ?
|
|
123
|
+
new Supercluster(getSuperclusterOptions(params)).load((await this._pendingData as any).features) :
|
|
124
|
+
geojsonvt(await this._pendingData, params.geojsonVtOptions);
|
|
125
|
+
|
|
126
|
+
this.loaded = {};
|
|
127
|
+
|
|
128
|
+
const result = {} as GeoJSONWorkerSourceLoadDataResult;
|
|
129
|
+
if (perf) {
|
|
130
|
+
const resourceTimingData = perf.finish();
|
|
131
|
+
// it's necessary to eval the result of getEntriesByName() here via parse/stringify
|
|
132
|
+
// late evaluation in the main thread causes TypeError: illegal invocation
|
|
133
|
+
if (resourceTimingData) {
|
|
134
|
+
result.resourceTiming = {};
|
|
135
|
+
result.resourceTiming[params.source] = JSON.parse(JSON.stringify(resourceTimingData));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
} catch (err) {
|
|
140
|
+
delete this._pendingRequest;
|
|
141
|
+
if (isAbortError(err)) {
|
|
142
|
+
return {abandoned: true};
|
|
143
|
+
}
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Allows to get the source's actual GeoJSON.
|
|
150
|
+
*
|
|
151
|
+
* @returns a promise which is resolved with the source's actual GeoJSON
|
|
152
|
+
*/
|
|
153
|
+
async getData(): Promise<GeoJSON.GeoJSON> {
|
|
154
|
+
return this._pendingData;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Implements {@link WorkerSource#reloadTile}.
|
|
159
|
+
*
|
|
160
|
+
* If the tile is loaded, uses the implementation in VectorTileWorkerSource.
|
|
161
|
+
* Otherwise, such as after a setData() call, we load the tile fresh.
|
|
162
|
+
*
|
|
163
|
+
* @param params - the parameters
|
|
164
|
+
* @returns A promise that resolves when the tile is reloaded
|
|
165
|
+
*/
|
|
166
|
+
reloadTile(params: WorkerTileParameters): Promise<WorkerTileResult> {
|
|
167
|
+
const loaded = this.loaded,
|
|
168
|
+
uid = params.uid;
|
|
169
|
+
|
|
170
|
+
if (loaded && loaded[uid]) {
|
|
171
|
+
return super.reloadTile(params);
|
|
172
|
+
} else {
|
|
173
|
+
return this.loadTile(params);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Fetch, parse and process GeoJSON according to the given params.
|
|
179
|
+
*
|
|
180
|
+
* Defers to {@link GeoJSONWorkerSource#loadGeoJSON} for the fetching and parsing.
|
|
181
|
+
*
|
|
182
|
+
* @param params - the parameters
|
|
183
|
+
* @param abortController - the abort controller that allows aborting this operation
|
|
184
|
+
* @returns a promise that is resolved with the processes GeoJSON
|
|
185
|
+
*/
|
|
186
|
+
async loadAndProcessGeoJSON(params: LoadGeoJSONParameters, abortController: AbortController): Promise<GeoJSON.GeoJSON> {
|
|
187
|
+
let data = await this.loadGeoJSON(params, abortController);
|
|
188
|
+
|
|
189
|
+
delete this._pendingRequest;
|
|
190
|
+
if (typeof data !== 'object') {
|
|
191
|
+
throw new Error(`Input data given to '${params.source}' is not a valid GeoJSON object.`);
|
|
192
|
+
}
|
|
193
|
+
rewind(data, true);
|
|
194
|
+
|
|
195
|
+
if (params.filter) {
|
|
196
|
+
const compiled = createExpression(params.filter, {type: 'boolean', 'property-type': 'data-driven', overridable: false, transition: false} as any);
|
|
197
|
+
if (compiled.result === 'error')
|
|
198
|
+
throw new Error(compiled.value.map(err => `${err.key}: ${err.message}`).join(', '));
|
|
199
|
+
|
|
200
|
+
const features = (data as any).features.filter(feature => compiled.value.evaluate({zoom: 0}, feature));
|
|
201
|
+
data = {type: 'FeatureCollection', features};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return data;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Fetch and parse GeoJSON according to the given params.
|
|
209
|
+
*
|
|
210
|
+
* GeoJSON is loaded and parsed from `params.url` if it exists, or else
|
|
211
|
+
* expected as a literal (string or object) `params.data`.
|
|
212
|
+
*
|
|
213
|
+
* @param params - the parameters
|
|
214
|
+
* @param abortController - the abort controller that allows aborting this operation
|
|
215
|
+
* @returns a promise that resolves when the data is loaded
|
|
216
|
+
*/
|
|
217
|
+
async loadGeoJSON(params: LoadGeoJSONParameters, abortController: AbortController): Promise<GeoJSON.GeoJSON> {
|
|
218
|
+
const {promoteId} = params;
|
|
219
|
+
if (params.request) {
|
|
220
|
+
const response = await getJSON<GeoJSON.GeoJSON>(params.request, abortController);
|
|
221
|
+
this._dataUpdateable = isUpdateableGeoJSON(response.data, promoteId) ? toUpdateable(response.data, promoteId) : undefined;
|
|
222
|
+
return response.data;
|
|
223
|
+
}
|
|
224
|
+
if (typeof params.data === 'string') {
|
|
225
|
+
try {
|
|
226
|
+
const parsed = JSON.parse(params.data);
|
|
227
|
+
this._dataUpdateable = isUpdateableGeoJSON(parsed, promoteId) ? toUpdateable(parsed, promoteId) : undefined;
|
|
228
|
+
return parsed;
|
|
229
|
+
} catch (e) {
|
|
230
|
+
throw new Error(`Input data given to '${params.source}' is not a valid GeoJSON object.`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (!params.dataDiff) {
|
|
234
|
+
throw new Error(`Input data given to '${params.source}' is not a valid GeoJSON object.`);
|
|
235
|
+
}
|
|
236
|
+
if (!this._dataUpdateable) {
|
|
237
|
+
throw new Error(`Cannot update existing geojson data in ${params.source}`);
|
|
238
|
+
}
|
|
239
|
+
applySourceDiff(this._dataUpdateable, params.dataDiff, promoteId);
|
|
240
|
+
return {type: 'FeatureCollection', features: Array.from(this._dataUpdateable.values())};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async removeSource(_params: RemoveSourceParams): Promise<void> {
|
|
244
|
+
if (this._pendingRequest) {
|
|
245
|
+
this._pendingRequest.abort();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
getClusterExpansionZoom(params: ClusterIDAndSource): number {
|
|
250
|
+
return (this._geoJSONIndex as Supercluster).getClusterExpansionZoom(params.clusterId);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
getClusterChildren(params: ClusterIDAndSource): Array<GeoJSON.Feature> {
|
|
254
|
+
return (this._geoJSONIndex as Supercluster).getChildren(params.clusterId);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
getClusterLeaves(params: {
|
|
258
|
+
clusterId: number;
|
|
259
|
+
limit: number;
|
|
260
|
+
offset: number;
|
|
261
|
+
}): Array<GeoJSON.Feature> {
|
|
262
|
+
return (this._geoJSONIndex as Supercluster).getLeaves(params.clusterId, params.limit, params.offset);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function getSuperclusterOptions({superclusterOptions, clusterProperties}: LoadGeoJSONParameters) {
|
|
267
|
+
if (!clusterProperties || !superclusterOptions) return superclusterOptions;
|
|
268
|
+
|
|
269
|
+
const mapExpressions = {};
|
|
270
|
+
const reduceExpressions = {};
|
|
271
|
+
const globals = {accumulated: null, zoom: 0};
|
|
272
|
+
const feature = {properties: null};
|
|
273
|
+
const propertyNames = Object.keys(clusterProperties);
|
|
274
|
+
|
|
275
|
+
for (const key of propertyNames) {
|
|
276
|
+
const [operator, mapExpression] = clusterProperties[key];
|
|
277
|
+
|
|
278
|
+
const mapExpressionParsed = createExpression(mapExpression);
|
|
279
|
+
const reduceExpressionParsed = createExpression(
|
|
280
|
+
typeof operator === 'string' ? [operator, ['accumulated'], ['get', key]] : operator);
|
|
281
|
+
|
|
282
|
+
mapExpressions[key] = mapExpressionParsed.value;
|
|
283
|
+
reduceExpressions[key] = reduceExpressionParsed.value;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
superclusterOptions.map = (pointProperties) => {
|
|
287
|
+
feature.properties = pointProperties;
|
|
288
|
+
const properties = {};
|
|
289
|
+
for (const key of propertyNames) {
|
|
290
|
+
properties[key] = mapExpressions[key].evaluate(globals, feature);
|
|
291
|
+
}
|
|
292
|
+
return properties;
|
|
293
|
+
};
|
|
294
|
+
superclusterOptions.reduce = (accumulated, clusterProperties) => {
|
|
295
|
+
feature.properties = clusterProperties;
|
|
296
|
+
for (const key of propertyNames) {
|
|
297
|
+
globals.accumulated = accumulated[key];
|
|
298
|
+
accumulated[key] = reduceExpressions[key].evaluate(globals, feature);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
return superclusterOptions;
|
|
303
|
+
}
|