Resize Leaflet map when its container is resized

Hello,

I’m having some issues with dash-leaflet; in particular with it’s width when the parent container is resized. I’m using dash-resizable-panels to resize some divs.

Here’s a MRE:

# pip install dash dash-leaflet dash-resizable-panels
import dash
import dash_leaflet as dl
from dash import html
from dash_resizable_panels import PanelGroup, Panel, PanelResizeHandle

handle = {"height": "100%", "width": "3px", "backgroundColor": "#51ada6"}
layout = html.Div([
	PanelGroup(id="panel-group", 
			   children=[
					Panel(id="panel-1",children=[html.Div([html.P("Dummy component")])]),
					PanelResizeHandle(html.Div(style=handle)),
					Panel(id="panel-2",
						  children=[
							dl.Map(center=[45.81, 15.98], zoom=12, children=[
                                dl.TileLayer(),
                                dl.FeatureGroup([dl.EditControl()]),
                            ], style={'height': '100%', 'width': '100%'})]
					)], direction="horizontal",),
], style={"height": "100vh"})

app = dash.Dash(__name__)
app.layout = layout
if __name__ == "__main__":
	app.run_server()

The initial layout is fine:

However, when I resize the map container I’m left with an un-rendered part of the map (gray part on the right) which looks like this:

Is there any way (be it through python or js) to resize or rerender the leaflet map when the container is resized so that the map fills (renders) the full width of its container?

Hi ,

The Dash LeafLet documentation says there is a trackResize parameter that is triggered when the window size changes : Dash. But it works only for the whole window, not for the element itself.

So what I would do is to create a clientside callback that create an event listener, that listens for size variation of the #map element. If it is resized, then trigger the window.resize event (jquery - How to trigger the window resize event in JavaScript? - Stack Overflow)

# pip install dash dash-leaflet dash-resizable-panels
import dash
import dash_leaflet as dl
from dash import html, Input, Output, clientside_callback
from dash_resizable_panels import PanelGroup, Panel, PanelResizeHandle

handle = {"height": "100%", "width": "3px", "backgroundColor": "#51ada6"}
layout = html.Div([
    PanelGroup(id="panel-group", 
               children=[
                    Panel(id="panel-1",children=[html.Div([html.P("Dummy component")])]),
                    PanelResizeHandle(html.Div(style=handle)),
                    Panel(id="panel-2",
                          children=[
                            dl.Map(id="map", center=[45.81, 15.98], zoom=12, trackResize=True, children=[
                                dl.TileLayer(),
                                dl.FeatureGroup([dl.EditControl()]),
                            ], style={'height': '100%', 'width': '100%'})]
                    )], direction="horizontal",),
], style={"height": "100vh"})

app = dash.Dash(__name__)
app.layout = layout


clientside_callback(
    """
    function set_event(map_id) {

        // On resize event 
        var callback = function() {
            console.log("Resizing")
            window.dispatchEvent(new Event('resize'));
        }

        new ResizeObserver(callback).observe(document.getElementById(map_id))

        return dash_clientside.no_update;
    }
    """,
    Output("map", "id"),
    Input("map", "id")
)

The output is just a dummy output, that’s why I return no_update.
The input is executed once, which is perfect to set only one listener (resizeObserver).

Tested and worked :slight_smile:

1 Like

Yes, this works great. Thanks!