79536769

Date: 2025-03-26 17:18:25
Score: 0.5
Natty:
Report link

The proposed code from @Yuvraj is not working, because it still creates link, but now this link is a JS code:

127.0.0.1 - - [26/Mar/2025 16:33:59] "POST / HTTP/1.1" 200 -
127.0.0.1 - - [26/Mar/2025 16:33:59] "GET /(function%20(factory,%20window)%20{%20%20%20%20//%20define%20an%20AMD%20module%20that%20relies%20on%20'leaflet'%20%20%20%20if%20(typeof%20define%20=== HTTP/1.1" 404 -
127.0.0.1 - - [26/Mar/2025 16:33:59] "GET /.leaflet-control-measure%20{%20%20%20%20background-color:%20 HTTP/1.1" 404 -
127.0.0.1 - - [26/Mar/2025 16:34:00] "GET /(function%20(factory,%20window)%20{%20%20%20%20//%20define%20an%20AMD%20module%20that%20relies%20on%20'leaflet'%20%20%20%20if%20(typeof%20define%20=== HTTP/1.1" 404 -
127.0.0.1 - - [26/Mar/2025 16:34:00] "GET /.leaflet-control-measure%20{%20%20%20%20background-color:%20 HTTP/1.1" 404 -

But, thanks to him I've found two other options

First option: static links

This will still create "localhost:port/leaflet.measure.js" and "localhost:port/leaflet.measure.css" links in header of final HTML page:

from jinja2 import Template
from folium.elements import JSCSSMixin
from folium.utilities import parse_options


class Measure(JSCSSMixin):
    _template = Template(
        """
        {% macro script(this, kwargs) %}
            var {{ this.get_name() }} = new L.control.measure(
                {{ this.options|tojson }});
            {{this._parent.get_name()}}.addControl({{this.get_name()}});
        {% endmacro %}
        """
    )

    # send static file from localhost via flask
    default_js = [("leaflet.measure.js", "leaflet.measure.js") ]
    default_css = [("leaflet.measure.css", "leaflet.measure.css") ]

    def __init__(self, embedded=True, **kwargs):
        super().__init__()
        self._name = "Measure"
        self.options = parse_options(**kwargs)

But we will resolve them with flask static file serving:

@app.route('/leaflet.measure.js', methods=['GET'])
def foo():
    return app.send_static_file('leaflet.measure.js')


@app.route('/leaflet.measure.css', methods=['GET'])
def baz():
    return app.send_static_file('leaflet.measure.css')

Second option: xzibit style, based on @Yuvraj idea

Inject JS/CSS code directly from static files from python package, no additional requests, no flask code modifications needed:

#  https://github.com/python-visualization/folium/blob/main/folium/elements.py
#  https://github.com/python-visualization/branca/blob/main/branca/element.py
#  https://github.com/python-visualization/folium/blob/main/folium/plugins/measure_control.py
import importlib.resources
from jinja2 import Template
from branca.element import Figure
from folium.elements import JSCSSMixin  # inherits from branca.element.MacroElement
from folium.utilities import parse_options


# I heard that you like templates, now you can inject template inside template, while injecting template to main template
class TemplateInjector:
    """ Class with compatible API for branca.element.Element to be added as a child to folium map
        It must have render() and get_name()
    """
    def __init__(self, name: str, template: Template):
        self._name = name
        self._template = template

    def render(self, **kwargs) -> str:
        return self._template.render(this=self, kwargs=kwargs)

    def get_name(self) -> str:
        return self._name


class Measure(JSCSSMixin):
    # will be self._template for all created class objects
    #   see MacroElement in <https://github.com/python-visualization/branca/blob/main/branca/element.py>
    _template = Template(
        """
        {% macro script(this, kwargs) %}
            var {{ this.get_name() }} = new L.control.measure(
                {{ this.options|tojson }});
            {{this._parent.get_name()}}.addControl({{this.get_name()}});
        {% endmacro %}
        """
    )

    # reload JSCSSMixin method
    def render(self, **kwargs):
        figure = self.get_root()
        assert isinstance(figure, Figure), "You cannot render this Element if it is not in a Figure."

        # load JS code and push it into template
        leaflet_measure_js = importlib.resources.files('geo_plotter').joinpath("static/leaflet.measure.js").read_text()
        js_template = Template(f"<script>{leaflet_measure_js}</script>")
        # push template into header
        figure.header.add_child(TemplateInjector("leaflet_measure_js", js_template))

        # load CSS code and push it into template
        leaflet_measure_css = importlib.resources.files('geo_plotter').joinpath("static/leaflet.measure.css").read_text()
        css_template = Template(f"<style>{leaflet_measure_css}</style>")
        # push template into header
        figure.header.add_child(TemplateInjector("leaflet_measure_css", css_template))

        super().render(**kwargs)

    def __init__(self, embedded=True, **kwargs):
        super().__init__()
        self._name = "Measure"
        self.options = parse_options(**kwargs)
Reasons:
  • Blacklisted phrase (0.5): thanks
  • Blacklisted phrase (1): this link
  • Long answer (-1):
  • Has code block (-0.5):
  • User mentioned (1): @Yuvraj
  • User mentioned (0): @Yuvraj
  • Self-answer (0.5):
  • High reputation (-1):
Posted by: banderlog013