Create download button in html view

Hi,

Is it possible to add a download button to a html view? We want to add a download widget to a folium map which is represented as a HTML view.

The following code does create a download button on the map.
However, when clicking, the script creates a acces denied error. Is there an other way to do this?

We don’t use the mapview or geojsonview here since we want to add special icons to the map, which is not possible in those views.

@WebView('Kaart voorzieningen', duration_guess=2, description="Interessante plekken in de buurt")
    def show_point_of_interest(self: 'Controller', params: Munch, **kwargs: Any) -> WebResult:
html_content = visualise_point_of_interest(params.page_1.information.plot)
return(WebResult(html=html_content))
def visualise_point_of_interest(params: Munch) -> str:

    m = folium.Map(location=[latitude, longitude], zoom_start=15 - multiplier, control_scale=True)

    bytes_buffer = BytesIO()
    m.save(bytes_buffer)
    print(bytes_buffer)

    # Standard map don't fit automaticly to the whole. So adjustments are needed to let the map cover the pane.
    html_content = f"""
    <div style="width: 110%; height: 95vh; position: absolute; top: 0; left: 0; bottom: 0;">
        {m._repr_html_()}
    </div>
    <div style="position: absolute; top: 10px; right: 10px; z-index: 1000;">
        <a href="{bytes_buffer}" download="map.html" style="padding: 10px 20px; background-color: #007BFF; color: white; text-decoration: none; border-radius: 5px; cursor: pointer;">
            Download Map
        </a>
    </div>
    """ 
    return html_content

Hi @wouterhouzr ,

Do you wish to download a HTML file, or a PNG?

To download as a HTML, I would suggest adding a DownloadButton in your parametrization and hooking that up to the same function:

from viktor import File
...

def visualise_point_of_interest(params: Munch) -> BytesIO:
    # Do your map fancy stuff here
    m = folium.Map(location=[params.latitude, params.longitude], zoom_start=15 - params.multiplier, control_scale=True)
    bytes_buffer = File()
    with bytes_buffer.open_binary() as fp:
        m.save(fp)
    return bytes_buffer

class Controller(ViktorController):
    label = "My Controller"
    parametrization = Parametrization

    @WebView('Kaart voorzieningen', duration_guess=2, description="Interessante plekken in de buurt")
    def show_point_of_interest(self: 'Controller', params: Munch, **kwargs: Any) -> WebResult:
        folium_map = visualise_point_of_interest(params)
        return WebResult(html=folium_map)

    def download(self, params, **kwargs) -> DownloadResult:
        bytes_buffer = visualise_point_of_interest(params)
        return DownloadResult(file_content=bytes_buffer, file_name="map.html")

In the case of a PNG, you’re going to need selenium as a dependency:

import selenium

...

class Controller(ViktorController):
    ...

    def download_png(self, params, **kwargs) -> DownloadResult:
        m = folium.Map(location=[params.latitude, params.longitude], zoom_start=15 - params.multiplier,
                       control_scale=True)
        img_data = m._to_png(5)
        image_file = File().from_data(img_data)
        return DownloadResult(image_file, file_name="test.png")

Hopes that helps

Hi @rvandijk,

Thanks for your response.
However, we would like to not add an downloadbutton to the parametrization.

Instead we would like to add the download option to png in the view just like the build-in option in plotly and the mapview to export the view directly to png.

.

Alternatively, if we add an downloadbutton to download the png using selenium we get the error message that we need to install a chromedriver. Do you know how we can work around that error message?

Hi @rvandijk,

Do you already have an idea regarding the selenium and chrome driver issue?

Hi @wouterhouzr, @Lotte ,

Sorry for taking the time.

I’ve been trying to solve this, by using html2canvas to download the folium as an image. However, since the folium iframe is being loaded from a different domain, we can’t access its content directly due to browser security policies. Therefore, I don’t think there is an easy way of doing this in html.

Regarding the selenium issue, I was indeed too soon with responding here; seems like there is indeed a chrome driver issue. Installing that into the viktor app might prove difficult indeed.

So even with the download button, downloading the Folium map is a difficult process. A potential solution that you could try is Is it possible to save a folium object in Python? - Stack Overflow.