From bdd111b521925c1a783b21f38967af558010f499 Mon Sep 17 00:00:00 2001 From: Hans Then Date: Sat, 9 Mar 2024 17:39:17 +0100 Subject: [PATCH 1/5] Re: #1519 Override css and js links Add a method to the JSCSSMixin that allows users to override a specific link to css or js. Unfortunately this still requires users to know the name of the of the link, which will require looking at the code or introspection. --- folium/elements.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/folium/elements.py b/folium/elements.py index 416ad3845f..c7db64b72e 100644 --- a/folium/elements.py +++ b/folium/elements.py @@ -1,4 +1,4 @@ -from typing import List, Tuple +from typing import List, Literal, Tuple from branca.element import CssLink, Element, Figure, JavascriptLink, MacroElement from jinja2 import Template @@ -24,6 +24,25 @@ def render(self, **kwargs) -> None: super().render(**kwargs) + def change_link(self, what: Literal["css", "js"], name: str, url: str): + """Modify a css or js link. + + If `name` does not exist, the defaults will be unchanged + """ + + def update(default_list): + return [(n, url if n == name else u) for (n, u) in default_list] + + if what == "css": + self.default_css = update(self.default_css) + elif what == "js": + self.default_js = update(self.default_js) + else: + raise ValueError( + f"""Unknown value: {what}. Must be either + 'js' or 'css'""" + ) + class ElementAddToElement(MacroElement): """Abstract class to add an element to another element.""" From 92973baa1bde624b6b7f7fe8134118206bc81315 Mon Sep 17 00:00:00 2001 From: Hans Then Date: Tue, 12 Mar 2024 17:43:26 +0100 Subject: [PATCH 2/5] Update to also add links when not already present Also added a method to bulk add several links in one call. --- folium/elements.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/folium/elements.py b/folium/elements.py index c7db64b72e..9a9e428404 100644 --- a/folium/elements.py +++ b/folium/elements.py @@ -1,4 +1,4 @@ -from typing import List, Literal, Tuple +from typing import List, Literal, Sequence, Tuple from branca.element import CssLink, Element, Figure, JavascriptLink, MacroElement from jinja2 import Template @@ -24,24 +24,33 @@ def render(self, **kwargs) -> None: super().render(**kwargs) - def change_link(self, what: Literal["css", "js"], name: str, url: str): + def add_link(self, what: Literal["css", "js"], name: str, url: str): """Modify a css or js link. - If `name` does not exist, the defaults will be unchanged + If `name` does not exist, the link will be appended """ def update(default_list): - return [(n, url if n == name else u) for (n, u) in default_list] + for i, pair in enumerate(default_list): + if pair[0] == name: + default_list[i] = (name, url) + break + else: + default_list.append((name, url)) if what == "css": - self.default_css = update(self.default_css) + update(self.default_css) elif what == "js": - self.default_js = update(self.default_js) + update(self.default_js) else: - raise ValueError( - f"""Unknown value: {what}. Must be either - 'js' or 'css'""" - ) + raise ValueError(f"""Unknown value: {what}. Must be either 'js' or 'css'""") + + def add_links( + self, what: Literal["css", "js"], defaults: Sequence[Tuple[str, str]] + ): + """Add multiple css or js links in a single call""" + for name, url in defaults: + self.add_link(what, name, url) class ElementAddToElement(MacroElement): From ecb896dfcb677d1d863c134da006693ba7be6c06 Mon Sep 17 00:00:00 2001 From: Hans Then Date: Wed, 3 Apr 2024 15:38:03 +0200 Subject: [PATCH 3/5] Updated after review comments --- folium/elements.py | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/folium/elements.py b/folium/elements.py index 9a9e428404..658030d57e 100644 --- a/folium/elements.py +++ b/folium/elements.py @@ -1,4 +1,4 @@ -from typing import List, Literal, Sequence, Tuple +from typing import List, Tuple from branca.element import CssLink, Element, Figure, JavascriptLink, MacroElement from jinja2 import Template @@ -24,33 +24,24 @@ def render(self, **kwargs) -> None: super().render(**kwargs) - def add_link(self, what: Literal["css", "js"], name: str, url: str): + def add_css_link(self, name, url): + self._add_link(name, url, self.default_css) + + def add_js_link(self, name, url): + 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 """ - def update(default_list): - for i, pair in enumerate(default_list): - if pair[0] == name: - default_list[i] = (name, url) - break - else: - default_list.append((name, url)) - - if what == "css": - update(self.default_css) - elif what == "js": - update(self.default_js) + for i, pair in enumerate(default_list): + if pair[0] == name: + default_list[i] = (name, url) + break else: - raise ValueError(f"""Unknown value: {what}. Must be either 'js' or 'css'""") - - def add_links( - self, what: Literal["css", "js"], defaults: Sequence[Tuple[str, str]] - ): - """Add multiple css or js links in a single call""" - for name, url in defaults: - self.add_link(what, name, url) + default_list.append((name, url)) class ElementAddToElement(MacroElement): From db2da9eaf35d4037fd028a9b39c0ac93922e2a8b Mon Sep 17 00:00:00 2001 From: Hans Then Date: Thu, 4 Apr 2024 10:47:53 +0200 Subject: [PATCH 4/5] Update folium/elements.py Co-authored-by: Frank Anema <33519926+Conengmo@users.noreply.github.com> --- folium/elements.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/folium/elements.py b/folium/elements.py index 658030d57e..9c41e66fab 100644 --- a/folium/elements.py +++ b/folium/elements.py @@ -24,10 +24,12 @@ def render(self, **kwargs) -> None: super().render(**kwargs) - def add_css_link(self, name, url): + 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, url): + 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]]): From 80caea99fd4a5f522b6af97e040f491c0b29a43e Mon Sep 17 00:00:00 2001 From: Hans Then Date: Thu, 4 Apr 2024 13:31:11 +0200 Subject: [PATCH 5/5] Add documentation on overriding css and js links --- docs/advanced_guide.rst | 1 + .../customize_javascript_and_css.md | 79 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 docs/advanced_guide/customize_javascript_and_css.md diff --git a/docs/advanced_guide.rst b/docs/advanced_guide.rst index bd4a60bf09..579eada3d7 100644 --- a/docs/advanced_guide.rst +++ b/docs/advanced_guide.rst @@ -14,3 +14,4 @@ Advanced guide advanced_guide/custom_tiles advanced_guide/piechart_icons advanced_guide/polygons_from_list_of_points + advanced_guide/customize_javascript_and_css diff --git a/docs/advanced_guide/customize_javascript_and_css.md b/docs/advanced_guide/customize_javascript_and_css.md new file mode 100644 index 0000000000..491c8d5d29 --- /dev/null +++ b/docs/advanced_guide/customize_javascript_and_css.md @@ -0,0 +1,79 @@ +# Customizing javascript or css resources + +```{code-cell} ipython3 +--- +nbsphinx: hidden +--- +import folium +``` + +## Adding javascript or css resources +Many leaflet resources require loading of custom css or javascript modules. This is handled in the `folium.elements.JSCSSMixin` class. Anything that inherits from this class can load custom resources. + +You can use the methods `add_js_link` and `add_css_link` to ensure these resources are loaded into the map. + +### Example 1: overriding the locations from where resources are loaded +One use case is to override the locations from where resources are loaded. This can be useful if you have to use a private CDN for your javascript and css resources, or if you want to use a different version. + +```{code-cell} +m = folium.Map() +m.add_css_link( + "bootstrap_css", + "https://example.com/bootstrap/400.5.0/css/bootstrap.min.css" +) +``` + + +### Example 2: loading additional javascript +A second use case is to load library modules that you can then use inside JsCode blocks. Continuing from the Realtime ISS example, see :doc:Realtime , we can modify this so that it uses the dayjs library to format the current date. + +```{code-cell} ipython3 +from folium.utilities import JsCode +from folium.plugins import Realtime + +m = folium.Map() +on_each_feature = JsCode(""" +function(f, l) { + l.bindPopup(function() { + return '
' + dayjs.unix(f.properties.timestamp).format() + '
'; + }); +} +""") + +source = JsCode(""" +function(responseHandler, errorHandler) { + var url = 'https://api.wheretheiss.at/v1/satellites/25544'; + + fetch(url) + .then((response) => { + return response.json().then((data) => { + var { id, timestamp, longitude, latitude } = data; + + return { + 'type': 'FeatureCollection', + 'features': [{ + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [longitude, latitude] + }, + 'properties': { + 'id': id, + 'timestamp': timestamp + } + }] + }; + }) + }) + .then(responseHandler) + .catch(errorHandler); +} +""") + +rt = Realtime(source, + on_each_feature=on_each_feature, + interval=1000) +rt.add_js_link("dayjs", "https://cdn.jsdelivr.net/npm/dayjs@1.11.10/dayjs.min.js") +rt.add_to(m) +m +```