From 7196e5c815365dbbb60601fbfe2daa23ef0d610e Mon Sep 17 00:00:00 2001 From: Theo Patron Date: Mon, 11 Dec 2023 15:40:31 +0100 Subject: [PATCH 1/8] fix: actually remove the feature group when needed --- streamlit_folium/frontend/src/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/streamlit_folium/frontend/src/index.tsx b/streamlit_folium/frontend/src/index.tsx index 58ada95..c89bd78 100644 --- a/streamlit_folium/frontend/src/index.tsx +++ b/streamlit_folium/frontend/src/index.tsx @@ -263,6 +263,11 @@ function onRender(event: Event): void { layer.on("mouseover", onLayerClick) } } + } else if (feature_group !== window.__GLOBAL_DATA__.last_feature_group) { + if (window.feature_group) { + window.map.removeLayer(window.feature_group) + } + window.__GLOBAL_DATA__.last_feature_group = feature_group } if (zoom && zoom !== window.__GLOBAL_DATA__.last_zoom) { From 74c662957439426276b049425e828154b14aa880 Mon Sep 17 00:00:00 2001 From: Theo Patron Date: Mon, 11 Dec 2023 17:05:39 +0100 Subject: [PATCH 2/8] feat: possibility to provide the feature group as a list --- streamlit_folium/__init__.py | 28 +++++++++----- streamlit_folium/frontend/src/index.tsx | 49 +++++++++++++------------ 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/streamlit_folium/__init__.py b/streamlit_folium/__init__.py index 5e49763..c62d0bd 100644 --- a/streamlit_folium/__init__.py +++ b/streamlit_folium/__init__.py @@ -16,7 +16,7 @@ # Create a _RELEASE constant. We'll set this to False while we're developing # the component, and True when we're ready to package and distribute it. -_RELEASE = True +_RELEASE = False if not _RELEASE: _component_func = components.declare_component( @@ -154,23 +154,26 @@ def _get_map_string(fig: folium.Map) -> str: def _get_feature_group_string( feature_group_to_add: folium.FeatureGroup, map: folium.Map, + idx: int = 0, ) -> str: - feature_group_to_add._id = "feature_group" + feature_group_to_add._id = f"feature_group_{idx}" feature_group_to_add.add_to(map) feature_group_to_add.render() feature_group_string = generate_leaflet_string( - feature_group_to_add, base_id="feature_group" + feature_group_to_add, base_id=f"feature_group_{idx}" ) m_id = get_full_id(map) feature_group_string = feature_group_string.replace(m_id, "map_div") feature_group_string = dedent(feature_group_string) feature_group_string += dedent( - """ - map_div.addLayer(feature_group_feature_group); - window.feature_group = feature_group_feature_group; + f""" + map_div.addLayer(feature_group_feature_group_{idx}); + window.feature_group = window.feature_group || []; + window.feature_group.push(feature_group_feature_group_{idx}); """ ) + return feature_group_string @@ -302,10 +305,15 @@ def bounds_to_dict(bounds_list: List[List[float]]) -> Dict[str, Dict[str, float] # on the frontend. feature_group_string = None if feature_group_to_add is not None: - feature_group_string = _get_feature_group_string( - feature_group_to_add, - map=folium_map, - ) + if not isinstance(feature_group_to_add, list): + feature_group_to_add = [feature_group_to_add] + feature_group_string = "" + for idx, feature_group in enumerate(feature_group_to_add): + feature_group_string += _get_feature_group_string( + feature_group, + map=folium_map, + idx=idx, + ) if debug: with st.expander("Show generated code"): diff --git a/streamlit_folium/frontend/src/index.tsx b/streamlit_folium/frontend/src/index.tsx index c89bd78..4af47e6 100644 --- a/streamlit_folium/frontend/src/index.tsx +++ b/streamlit_folium/frontend/src/index.tsx @@ -1,6 +1,7 @@ import { RenderData, Streamlit } from "streamlit-component-lib" import { debounce } from "underscore" import { circleToPolygon } from "./circle-to-polygon" +import { Layer } from "leaflet" type GlobalData = { lat_lng_clicked: any @@ -240,35 +241,35 @@ function onRender(event: Event): void { } if ( - feature_group && feature_group !== window.__GLOBAL_DATA__.last_feature_group - ) { - if (window.feature_group) { - window.map.removeLayer(window.feature_group) + ) { + if (window.feature_group && window.feature_group.length > 0) { + window.feature_group.forEach((layer: Layer) => { + window.map.removeLayer(layer); + }); } - // Though using `eval` is generally a bad idea, we're using it here - // because we're evaluating code that we've generated ourselves on the - // Python side. This is safe because we're not evaluating user input, so this - // couldn't be used to execute arbitrary code. - - // eslint-disable-next-line - eval(feature_group) + window.__GLOBAL_DATA__.last_feature_group = feature_group - for (let key in window.map._layers) { - let layer = window.map._layers[key] - layer.off("click", onLayerClick) - layer.on("click", onLayerClick) - if (return_on_hover) { - layer.off("mouseover", onLayerClick) - layer.on("mouseover", onLayerClick) + + if (feature_group){ + // Though using `eval` is generally a bad idea, we're using it here + // because we're evaluating code that we've generated ourselves on the + // Python side. This is safe because we're not evaluating user input, so this + // couldn't be used to execute arbitrary code. + + // eslint-disable-next-line + eval(feature_group) + for (let key in window.map._layers) { + let layer = window.map._layers[key] + layer.off("click", onLayerClick) + layer.on("click", onLayerClick) + if (return_on_hover) { + layer.off("mouseover", onLayerClick) + layer.on("mouseover", onLayerClick) + } } } - } else if (feature_group !== window.__GLOBAL_DATA__.last_feature_group) { - if (window.feature_group) { - window.map.removeLayer(window.feature_group) - } - window.__GLOBAL_DATA__.last_feature_group = feature_group - } + } if (zoom && zoom !== window.__GLOBAL_DATA__.last_zoom) { window.map.setZoom(zoom) From 542818ff8275c9459e0dc243999796f1d70ec69d Mon Sep 17 00:00:00 2001 From: Theo Patron Date: Mon, 11 Dec 2023 17:10:01 +0100 Subject: [PATCH 3/8] fix: changed expected type and documentation --- streamlit_folium/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/streamlit_folium/__init__.py b/streamlit_folium/__init__.py index c62d0bd..476e5a5 100644 --- a/streamlit_folium/__init__.py +++ b/streamlit_folium/__init__.py @@ -185,7 +185,7 @@ def st_folium( returned_objects: Iterable[str] | None = None, zoom: int | None = None, center: tuple[float, float] | None = None, - feature_group_to_add: folium.FeatureGroup | None = None, + feature_group_to_add: List[folium.FeatureGroup] | folium.FeatureGroup | None = None, return_on_hover: bool = False, use_container_width: bool = False, debug: bool = False, @@ -215,7 +215,7 @@ def st_folium( The center of the map. If None, the center will be set to the default center of the map. NOTE that if this center is changed, it will *not* reload the map, but simply dynamically change the center. - feature_group_to_add: folium.FeatureGroup or None + feature_group_to_add: List[folium.FeatureGroup] or folium.FeatureGroup or None If you want to dynamically add features to a feature group, you can pass the feature group here. NOTE that if you add a feature to the map, it will *not* reload the map, but simply dynamically add the feature. @@ -305,7 +305,7 @@ def bounds_to_dict(bounds_list: List[List[float]]) -> Dict[str, Dict[str, float] # on the frontend. feature_group_string = None if feature_group_to_add is not None: - if not isinstance(feature_group_to_add, list): + if isinstance(feature_group_to_add, folium.FeatureGroup): feature_group_to_add = [feature_group_to_add] feature_group_string = "" for idx, feature_group in enumerate(feature_group_to_add): From 3fd5aacd2c790b685c62df09d9761ba48fafef67 Mon Sep 17 00:00:00 2001 From: Theo Patron Date: Mon, 11 Dec 2023 17:24:04 +0100 Subject: [PATCH 4/8] fix title --- examples/pages/dynamic_updates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/pages/dynamic_updates.py b/examples/pages/dynamic_updates.py index 8ed84e2..4f3ed72 100644 --- a/examples/pages/dynamic_updates.py +++ b/examples/pages/dynamic_updates.py @@ -19,7 +19,7 @@ "# Dynamic Updates -- Click on a marker" st.subheader( - """Use new arguments `center`, `zoom`, and `feature_group_to_add` to update the map + """Use new arguments `center`, `zoom`, and `feature_group_to_add` to update the map \ without re-rendering it.""" ) From 58124aeadb9c3ee42ba7c2cbfaaf2c046ae65a50 Mon Sep 17 00:00:00 2001 From: Theo Patron Date: Mon, 11 Dec 2023 18:29:38 +0100 Subject: [PATCH 5/8] added test to check that the feature groups are appearing and disappearing as requested --- examples/pages/dynamic_updates.py | 50 +++++++++++++++++++++++++++++++ tests/test_frontend.py | 21 +++++++++++++ 2 files changed, 71 insertions(+) diff --git a/examples/pages/dynamic_updates.py b/examples/pages/dynamic_updates.py index 4f3ed72..72cb61c 100644 --- a/examples/pages/dynamic_updates.py +++ b/examples/pages/dynamic_updates.py @@ -7,6 +7,8 @@ import pandas as pd import requests import streamlit as st +import geopandas as gpd +import shapely from streamlit_folium import st_folium @@ -106,5 +108,53 @@ def main(): st.experimental_rerun() + + st.write("## Dynamic feature group updates") + + START_LOCATION = [37.7944347109497, -122.398077892527] + START_ZOOM = 17 + + if not 'feature_group' in st.session_state: + st.session_state['feature_group'] = None + + wkt1 = "POLYGON ((-122.399077892527 37.7934347109497, -122.398922660838 37.7934544916178, -122.398980265018 37.7937266504805, -122.399133972495 37.7937070646238, -122.399077892527 37.7934347109497))" + wkt2 = "POLYGON ((-122.397416 37.795017, -122.397137 37.794712, -122.396332 37.794983, -122.396171 37.795483, -122.396858 37.795695, -122.397652 37.795466, -122.397759 37.79511, -122.397416 37.795017))" + + polygon_1 = shapely.wkt.loads(wkt1) + polygon_2 = shapely.wkt.loads(wkt2) + + gdf1 = gpd.GeoDataFrame(geometry=[polygon_1]).set_crs(epsg=4326) + gdf2 = gpd.GeoDataFrame(geometry=[polygon_2]).set_crs(epsg=4326) + + style_parcels = {'fillColor': '#1100f8', 'color': '#1100f8', 'fillOpacity': 0.13, 'weight': 2 } + style_buildings = {'color': '#ff3939', 'fillOpacity': 0, 'weight': 3, 'opacity': 1, 'dashArray': '5, 5'} + + polygon_folium1 = folium.GeoJson(data=gdf1, style_function=lambda x: style_parcels) + polygon_folium2 = folium.GeoJson(data=gdf2, style_function=lambda x: style_buildings) + + map = folium.Map( + location=START_LOCATION, zoom_start=START_ZOOM, tiles="OpenStreetMap", max_zoom=21 + ) + + fg1 = folium.FeatureGroup(name="Parcels") + fg1.add_child(polygon_folium1) + + fg2 = folium.FeatureGroup(name="Buildings") + fg2.add_child(polygon_folium2) + + fg_dict = {'Parcels': fg1, 'Buildings': fg2, 'None': None, 'Both': [fg1, fg2]} + + fg = st.radio("Feature Group", ['Parcels', 'Buildings', 'None', 'Both']) + + st_folium( + map, + width=800, + height=450, + returned_objects=[], + feature_group_to_add=fg_dict[fg], + debug=True, + ) + + if __name__ == "__main__": main() diff --git a/tests/test_frontend.py b/tests/test_frontend.py index 09a31ff..b3721bc 100644 --- a/tests/test_frontend.py +++ b/tests/test_frontend.py @@ -268,3 +268,24 @@ def test_grouped_layer_control(page: Page): page.frame_locator('iframe[title="streamlit_folium\\.st_folium"]').get_by_label( "g2" ).check() + + +def test_dynamic_feature_group_update(page: Page): + page.get_by_role("link", name="dynamic updates").click() + page.get_by_text("Show generated code").click() + + page.locator("label").filter(has_text="Buildings").locator("div").nth(1).click() + expect(page.get_by_text('"fillColor"')).to_be_hidden() # fillColor only present in parcel style + expect(page.get_by_text('"dashArray"')).to_be_visible() # dashArray only present in building style + + page.locator("label").filter(has_text="None").locator("div").nth(1).click() + expect(page.get_by_text("fillColor")).to_be_hidden() + expect(page.get_by_text("dashArray")).to_be_hidden() + + page.locator("label").filter(has_text="Parcels").locator("div").nth(1).click() + expect(page.get_by_text("fillColor")).to_be_visible() + expect(page.get_by_text("dashArray")).to_be_hidden() + + page.locator("label").filter(has_text="Both").locator("div").nth(1).click() + expect(page.get_by_text("fillColor")).to_be_visible() + expect(page.get_by_text("dashArray")).to_be_visible() \ No newline at end of file From 7fc318efaa093285afb8af586deeb417f3c84788 Mon Sep 17 00:00:00 2001 From: Zachary Blackwood Date: Mon, 11 Dec 2023 14:11:20 -0500 Subject: [PATCH 6/8] Linting and expand test a bit --- examples/pages/dynamic_updates.py | 56 ++++++++++++++++++--------- streamlit_folium/__init__.py | 6 +-- tests/test_frontend.py | 63 ++++++++++++++++++++++++++----- tests/test_package.py | 2 +- 4 files changed, 96 insertions(+), 31 deletions(-) diff --git a/examples/pages/dynamic_updates.py b/examples/pages/dynamic_updates.py index 72cb61c..5b78b07 100644 --- a/examples/pages/dynamic_updates.py +++ b/examples/pages/dynamic_updates.py @@ -4,11 +4,11 @@ import folium import folium.features +import geopandas as gpd import pandas as pd import requests -import streamlit as st -import geopandas as gpd import shapely +import streamlit as st from streamlit_folium import st_folium @@ -21,8 +21,8 @@ "# Dynamic Updates -- Click on a marker" st.subheader( - """Use new arguments `center`, `zoom`, and `feature_group_to_add` to update the map \ - without re-rendering it.""" + "Use new arguments `center`, `zoom`, and `feature_group_to_add` to update the map " + "without re-rendering it." ) @@ -107,18 +107,24 @@ def main(): st.session_state["selected_state"] = state st.experimental_rerun() - - st.write("## Dynamic feature group updates") - + START_LOCATION = [37.7944347109497, -122.398077892527] START_ZOOM = 17 - if not 'feature_group' in st.session_state: - st.session_state['feature_group'] = None + if "feature_group" not in st.session_state: + st.session_state["feature_group"] = None - wkt1 = "POLYGON ((-122.399077892527 37.7934347109497, -122.398922660838 37.7934544916178, -122.398980265018 37.7937266504805, -122.399133972495 37.7937070646238, -122.399077892527 37.7934347109497))" - wkt2 = "POLYGON ((-122.397416 37.795017, -122.397137 37.794712, -122.396332 37.794983, -122.396171 37.795483, -122.396858 37.795695, -122.397652 37.795466, -122.397759 37.79511, -122.397416 37.795017))" + wkt1 = ( + "POLYGON ((-122.399077892527 37.7934347109497, -122.398922660838 " + "37.7934544916178, -122.398980265018 37.7937266504805, -122.399133972495 " + "37.7937070646238, -122.399077892527 37.7934347109497))" + ) + wkt2 = ( + "POLYGON ((-122.397416 37.795017, -122.397137 37.794712, -122.396332 37.794983," + " -122.396171 37.795483, -122.396858 37.795695, -122.397652 37.795466, " + "-122.397759 37.79511, -122.397416 37.795017))" + ) polygon_1 = shapely.wkt.loads(wkt1) polygon_2 = shapely.wkt.loads(wkt2) @@ -126,14 +132,30 @@ def main(): gdf1 = gpd.GeoDataFrame(geometry=[polygon_1]).set_crs(epsg=4326) gdf2 = gpd.GeoDataFrame(geometry=[polygon_2]).set_crs(epsg=4326) - style_parcels = {'fillColor': '#1100f8', 'color': '#1100f8', 'fillOpacity': 0.13, 'weight': 2 } - style_buildings = {'color': '#ff3939', 'fillOpacity': 0, 'weight': 3, 'opacity': 1, 'dashArray': '5, 5'} + style_parcels = { + "fillColor": "#1100f8", + "color": "#1100f8", + "fillOpacity": 0.13, + "weight": 2, + } + style_buildings = { + "color": "#ff3939", + "fillOpacity": 0, + "weight": 3, + "opacity": 1, + "dashArray": "5, 5", + } polygon_folium1 = folium.GeoJson(data=gdf1, style_function=lambda x: style_parcels) - polygon_folium2 = folium.GeoJson(data=gdf2, style_function=lambda x: style_buildings) + polygon_folium2 = folium.GeoJson( + data=gdf2, style_function=lambda x: style_buildings + ) map = folium.Map( - location=START_LOCATION, zoom_start=START_ZOOM, tiles="OpenStreetMap", max_zoom=21 + location=START_LOCATION, + zoom_start=START_ZOOM, + tiles="OpenStreetMap", + max_zoom=21, ) fg1 = folium.FeatureGroup(name="Parcels") @@ -142,9 +164,9 @@ def main(): fg2 = folium.FeatureGroup(name="Buildings") fg2.add_child(polygon_folium2) - fg_dict = {'Parcels': fg1, 'Buildings': fg2, 'None': None, 'Both': [fg1, fg2]} + fg_dict = {"Parcels": fg1, "Buildings": fg2, "None": None, "Both": [fg1, fg2]} - fg = st.radio("Feature Group", ['Parcels', 'Buildings', 'None', 'Both']) + fg = st.radio("Feature Group", ["Parcels", "Buildings", "None", "Both"]) st_folium( map, diff --git a/streamlit_folium/__init__.py b/streamlit_folium/__init__.py index 476e5a5..d4695e9 100644 --- a/streamlit_folium/__init__.py +++ b/streamlit_folium/__init__.py @@ -5,7 +5,7 @@ import re import warnings from textwrap import dedent -from typing import Dict, Iterable, List +from typing import Iterable import branca import folium @@ -185,7 +185,7 @@ def st_folium( returned_objects: Iterable[str] | None = None, zoom: int | None = None, center: tuple[float, float] | None = None, - feature_group_to_add: List[folium.FeatureGroup] | folium.FeatureGroup | None = None, + feature_group_to_add: list[folium.FeatureGroup] | folium.FeatureGroup | None = None, return_on_hover: bool = False, use_container_width: bool = False, debug: bool = False, @@ -260,7 +260,7 @@ def st_folium( m_id = get_full_id(folium_map) - def bounds_to_dict(bounds_list: List[List[float]]) -> Dict[str, Dict[str, float]]: + def bounds_to_dict(bounds_list: list[list[float]]) -> dict[str, dict[str, float]]: southwest, northeast = bounds_list return { "_southWest": { diff --git a/tests/test_frontend.py b/tests/test_frontend.py index b3721bc..85db609 100644 --- a/tests/test_frontend.py +++ b/tests/test_frontend.py @@ -274,18 +274,61 @@ def test_dynamic_feature_group_update(page: Page): page.get_by_role("link", name="dynamic updates").click() page.get_by_text("Show generated code").click() - page.locator("label").filter(has_text="Buildings").locator("div").nth(1).click() - expect(page.get_by_text('"fillColor"')).to_be_hidden() # fillColor only present in parcel style - expect(page.get_by_text('"dashArray"')).to_be_visible() # dashArray only present in building style - - page.locator("label").filter(has_text="None").locator("div").nth(1).click() + # Test showing only Parcel layer + page.get_by_test_id("stRadio").get_by_text("Parcels").click() + expect( + page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1') + .locator("path") + .first + ).to_be_visible() + expect( + page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1') + .locator("path") + .nth(1) + ).to_be_hidden() + expect( + page.get_by_text('"fillColor"') + ).to_be_visible() # fillColor only present in parcel style + expect( + page.get_by_text('"dashArray"') + ).to_be_hidden() # dashArray only present in building style + + # Test showing only Building layer + page.get_by_test_id("stRadio").get_by_text("Buildings").click() + expect( + page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1') + .locator("path") + .first + ).to_be_visible() + expect( + page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1') + .locator("path") + .nth(1) + ).to_be_hidden() expect(page.get_by_text("fillColor")).to_be_hidden() - expect(page.get_by_text("dashArray")).to_be_hidden() + expect(page.get_by_text("dashArray")).to_be_visible() - page.locator("label").filter(has_text="Parcels").locator("div").nth(1).click() - expect(page.get_by_text("fillColor")).to_be_visible() + # Test showing no layers + page.get_by_test_id("stRadio").get_by_text("None").click() + expect( + page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1') + .locator("path") + .first + ).to_be_hidden() + expect(page.get_by_text("fillColor")).to_be_hidden() expect(page.get_by_text("dashArray")).to_be_hidden() - page.locator("label").filter(has_text="Both").locator("div").nth(1).click() + # Test showing both layers + page.get_by_test_id("stRadio").get_by_text("Both").click() + expect( + page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1') + .locator("path") + .first + ).to_be_visible() + expect( + page.frame_locator('iframe[title="streamlit_folium\\.st_folium"] >> nth=1') + .locator("path") + .nth(1) + ).to_be_visible() expect(page.get_by_text("fillColor")).to_be_visible() - expect(page.get_by_text("dashArray")).to_be_visible() \ No newline at end of file + expect(page.get_by_text("dashArray")).to_be_visible() diff --git a/tests/test_package.py b/tests/test_package.py index 806cced..b196529 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -89,7 +89,7 @@ def test_feature_group(): fg_str = _get_feature_group_string(fg, m) - assert "var feature_group_feature_group = L.featureGroup(" in fg_str + assert "var feature_group_feature_group_0 = L.featureGroup(" in fg_str assert ".addTo(map_div);" in fg_str From 0ce6848f6a463cf6632aef679ea2e8313123adb3 Mon Sep 17 00:00:00 2001 From: Zachary Blackwood Date: Mon, 11 Dec 2023 14:12:13 -0500 Subject: [PATCH 7/8] update RELEASE --- streamlit_folium/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/streamlit_folium/__init__.py b/streamlit_folium/__init__.py index d4695e9..d500c6a 100644 --- a/streamlit_folium/__init__.py +++ b/streamlit_folium/__init__.py @@ -16,7 +16,7 @@ # Create a _RELEASE constant. We'll set this to False while we're developing # the component, and True when we're ready to package and distribute it. -_RELEASE = False +_RELEASE = True if not _RELEASE: _component_func = components.declare_component( From f8d060a2ecbb7231490fbcd1621f2dba676804a1 Mon Sep 17 00:00:00 2001 From: Zachary Blackwood Date: Mon, 11 Dec 2023 14:15:28 -0500 Subject: [PATCH 8/8] Tsx linting --- streamlit_folium/frontend/src/index.tsx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/streamlit_folium/frontend/src/index.tsx b/streamlit_folium/frontend/src/index.tsx index 4af47e6..d43d776 100644 --- a/streamlit_folium/frontend/src/index.tsx +++ b/streamlit_folium/frontend/src/index.tsx @@ -1,7 +1,7 @@ +import { Layer } from "leaflet" import { RenderData, Streamlit } from "streamlit-component-lib" import { debounce } from "underscore" import { circleToPolygon } from "./circle-to-polygon" -import { Layer } from "leaflet" type GlobalData = { lat_lng_clicked: any @@ -240,18 +240,16 @@ function onRender(event: Event): void { } } - if ( - feature_group !== window.__GLOBAL_DATA__.last_feature_group - ) { + if (feature_group !== window.__GLOBAL_DATA__.last_feature_group) { if (window.feature_group && window.feature_group.length > 0) { window.feature_group.forEach((layer: Layer) => { - window.map.removeLayer(layer); - }); + window.map.removeLayer(layer) + }) } - + window.__GLOBAL_DATA__.last_feature_group = feature_group - if (feature_group){ + if (feature_group) { // Though using `eval` is generally a bad idea, we're using it here // because we're evaluating code that we've generated ourselves on the // Python side. This is safe because we're not evaluating user input, so this @@ -269,7 +267,7 @@ function onRender(event: Event): void { } } } - } + } if (zoom && zoom !== window.__GLOBAL_DATA__.last_zoom) { window.map.setZoom(zoom)