diff --git a/docs/reference.rst b/docs/reference.rst index 5ed5f7c323..da20b33775 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -35,6 +35,7 @@ Utilities --------------------- .. autoclass:: folium.utilities.JsCode +.. autoclass:: folium.elements.EventHandler Plugins diff --git a/folium/elements.py b/folium/elements.py index 9c41e66fab..3d44985175 100644 --- a/folium/elements.py +++ b/folium/elements.py @@ -3,6 +3,8 @@ from branca.element import CssLink, Element, Figure, JavascriptLink, MacroElement from jinja2 import Template +from folium.utilities import JsCode + class JSCSSMixin(Element): """Render links to external Javascript and CSS resources.""" @@ -46,6 +48,80 @@ def _add_link(self, name: str, url: str, default_list: List[Tuple[str, str]]): default_list.append((name, url)) +class EventHandler(MacroElement): + ''' + Add javascript event handlers. + + Examples + -------- + >>> import folium + >>> from folium.utilities import JsCode + >>> + >>> m = folium.Map() + >>> + >>> geo_json_data = { + ... "type": "FeatureCollection", + ... "features": [ + ... { + ... "type": "Feature", + ... "geometry": { + ... "type": "Polygon", + ... "coordinates": [ + ... [ + ... [100.0, 0.0], + ... [101.0, 0.0], + ... [101.0, 1.0], + ... [100.0, 1.0], + ... [100.0, 0.0], + ... ] + ... ], + ... }, + ... "properties": {"prop1": {"title": "Somewhere on Sumatra"}}, + ... } + ... ], + ... } + >>> + >>> g = folium.GeoJson(geo_json_data).add_to(m) + >>> + >>> highlight = JsCode( + ... """ + ... function highlight(e) { + ... e.target.original_color = e.layer.options.color; + ... e.target.setStyle({ color: "green" }); + ... } + ... """ + ... ) + >>> + >>> reset = JsCode( + ... """ + ... function reset(e) { + ... e.target.setStyle({ color: e.target.original_color }); + ... } + ... """ + ... ) + >>> + >>> g.add_child(EventHandler("mouseover", highlight)) + >>> g.add_child(EventHandler("mouseout", reset)) + ''' + + _template = Template( + """ + {% macro script(this, kwargs) %} + {{ this._parent.get_name()}}.on( + {{ this.event|tojson}}, + {{ this.handler.js_code }} + ); + {% endmacro %} + """ + ) + + def __init__(self, event: str, handler: JsCode): + super().__init__() + self._name = "EventHandler" + self.event = event + self.handler = handler + + class ElementAddToElement(MacroElement): """Abstract class to add an element to another element.""" diff --git a/tests/test_features.py b/tests/test_features.py index c879ad119c..94d27d329b 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -13,6 +13,8 @@ import folium from folium import Choropleth, ClickForMarker, GeoJson, Map, Popup +from folium.elements import EventHandler +from folium.utilities import JsCode @pytest.fixture @@ -283,6 +285,23 @@ def test_geojson_empty_features_with_styling(): m.get_root().render() +def test_geojson_event_handler(): + """Test that event handlers are properly generated""" + m = Map() + data = {"type": "FeatureCollection", "features": []} + geojson = GeoJson(data, style_function=lambda x: {}).add_to(m) + fn = JsCode( + """ + function f(e) { + console.log("only for testing") + } + """ + ) + geojson.add_child(EventHandler("mouseover", fn)) + rendered = m.get_root().render() + assert fn.js_code in rendered + + def test_geometry_collection_get_bounds(): """Assert #1599 is fixed""" geojson_data = {