from typing import List, Tuple 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.""" default_js: List[Tuple[str, str]] = [] default_css: List[Tuple[str, str]] = [] def render(self, **kwargs) -> None: figure = self.get_root() assert isinstance( figure, Figure ), "You cannot render this Element if it is not in a Figure." for name, url in self.default_js: figure.header.add_child(JavascriptLink(url), name=name) for name, url in self.default_css: figure.header.add_child(CssLink(url), name=name) super().render(**kwargs) def add_css_link(self, name: str, url: str): """Add or update css resource link.""" self._add_link(name, url, self.default_css) def add_js_link(self, name: str, url: str): """Add or update JS resource link.""" self._add_link(name, url, self.default_js) def _add_link(self, name: str, url: str, default_list: List[Tuple[str, str]]): """Modify a css or js link. If `name` does not exist, the link will be appended """ for i, pair in enumerate(default_list): if pair[0] == name: default_list[i] = (name, url) break else: 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.""" _template = Template( """ {% macro script(this, kwargs) %} {{ this.element_name }}.addTo({{ this.element_parent_name }}); {% endmacro %} """ ) def __init__(self, element_name: str, element_parent_name: str): super().__init__() self.element_name = element_name self.element_parent_name = element_parent_name