emilhe / dash-leaflet

MIT License
212 stars 36 forks source link

Unable to detect container size, Unable to use invalidateSize() #36

Closed Hootie9lives closed 4 years ago

Hootie9lives commented 4 years ago

the map element in my application is inside a div. It looks like Dash-leaflet is unable to detect the container size. I am curious if there is a way to use invalidateSize() from the JS library

Hootie9lives commented 4 years ago

unable to drag or zoom on the map image

emilhe commented 4 years ago

Could you post an MWE demonstrating the issue?

Hootie9lives commented 4 years ago

Could you post an MWE demonstrating the issue?

This is pretty close to what I have

html.Div(
        bootstrap.Row([
            bootstrap.Col(bootstrap.Card([
                navbar,
                html.Div([
                bootstrap.CardBody(
                    bootstrap.Tabs([
                        bootstrap.Tab(bootstrap.Row([
                            bootstrap.Col([
                                html.Tbody(
                                    [
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    ], style={
                                        'padding': '5px',
                                        'letter-spacing': '1px',
                                        'font-family': 'sans-serif',
                                        'font-size': '.8rem',
                                        'display': 'table-cell',
                                        'width': '50%'
                                    },
                                ),
                                html.Div([
                                    dl.Map(dl.WMSTileLayer(url="service",
                                                           layers="layer",
                                                           format="image/png", transparent=True),
                                           zoom=1,
                                           style={'width': '600px',
                                                  'height': '500px',
                                                  'padding': '5px',
                                                  'display': 'table-cell'
                                                  }
                                           ),
                                ]),
                            ], width={'size': 12}, style={'display': 'table'}, className="table table-bordered")
                        ]), label="string", label_style={"color": "#5B2C6F"}),
                    ]),
                    style={'flex': 8, 'background': 'cyan', 'top': '10vh'}),

                bootstrap.CardBody(
                    [
                        bootstrap.Col(bootstrap.ButtonGroup(
                        ),
                            style={
                                'color': 'white',
                                'padding': '5px',
                                'top': '10%',
                                'cursor': 'pointer',
                                'width': '90%',
                                'height': '60vh',
                                'vertical-align': 'middle',
                                'display': 'flex',
                                'justify-self': 'center',
                                'align-self': 'center'
                            }, className="btn-group")
                    ], style={'flex': 1, 'background': 'cyan'})], style={'display': 'flex'}),
            ], color='secondary', inverse=False, style={'min-height': '80vh', 'padding': '10px',
                                                        'display': 'flex',
                                                        'border': '8px solid  # 73AD21'}), width=10)
        ],
            style={
                'width': '1600px',
                'overflow': 'auto',
                'resize': 'horizontal',
                'position': 'absolute',
                'top': '10%',
                'height': '90%',
                'left': '8%',
                'display': 'flex'
                    })
         , style={'height': '100vh', 'width': '100%', 'background-color': 'powderblue',
                            'margin-left': 'auto',
                            'margin-right': 'auto',
                            'display': 'grid',
                            'place-items': 'center',
                            'align-items': 'center',
                            'padding': '20em'})
emilhe commented 4 years ago

Thanks for the example. You are correct, calling that function is currently not supported. I just had a quick look, but it seems that this feature is not implemented in React Leaflet (please correct me if you find sources suggesting otherwise), hence it would require some work to implement it.

Hootie9lives commented 4 years ago

Thanks for the example. You are correct, calling that function is currently not supported. I just had a quick look, but it seems that this feature is not implemented in React Leaflet (please correct me if you find sources suggesting otherwise), hence it would require some work to implement it.

I found a few posts. I think these suggest this feature is in React Leaflet? https://stackoverflow.com/questions/59856361/map-is-not-visible-at-initialization-using-react-leaflet https://gis.stackexchange.com/questions/302180/leaflet-invalidate-size-is-not-a-function-undefined https://gis.stackexchange.com/questions/348228/map-is-not-visible-at-initialization-using-react-leaflet

emilhe commented 4 years ago

Do you think it is only a problem on init? I.e. should it be a prop (so that you can trigger it) or should it be a part of the init process of the map itself?

Hootie9lives commented 4 years ago

I don't want to give information I'm not confident about and potentially mislead. I feel this post directly relates and can give you some insights https://stackoverflow.com/questions/24412325/resizing-a-leaflet-map-on-container-resize

emilhe commented 4 years ago

I just did some more testing on your example. Modifying it slightly to make it runnable,

import dash
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as bootstrap
import dash_leaflet as dl

app = dash.Dash(__name__, update_title=None)  # remove "Updating..." from title

app.layout = html.Div(
        bootstrap.Row([
            bootstrap.Col(bootstrap.Card([
                html.Div([
                bootstrap.CardBody(
                    bootstrap.Tabs([
                        bootstrap.Tab(bootstrap.Row([
                            bootstrap.Col([
                                html.Tbody(
                                    [
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    html.Tr([html.Td("string"), html.Td("string")],
                                            style={'height': '2vh'}),
                                    ], style={
                                        'padding': '5px',
                                        'letter-spacing': '1px',
                                        'font-family': 'sans-serif',
                                        'font-size': '.8rem',
                                        'display': 'table-cell',
                                        'width': '50%'
                                    },
                                ),
                                html.Div([
                                    dl.Map(dl.TileLayer(),
                                           zoom=5,
                                           style={'width': '600px',
                                                  'height': '500px',
                                                  'padding': '5px',
                                                  'display': 'table-cell'
                                                  }
                                           ),
                                ]),
                            ], width={'size': 12}, style={'display': 'table'}, className="table table-bordered")
                        ]), label="string", label_style={"color": "#5B2C6F"}),
                    ]),
                    style={'flex': 8, 'background': 'cyan', 'top': '10vh'}),

                bootstrap.CardBody(
                    [
                        bootstrap.Col(bootstrap.ButtonGroup(
                        ),
                            style={
                                'color': 'white',
                                'padding': '5px',
                                'top': '10%',
                                'cursor': 'pointer',
                                'width': '90%',
                                'height': '60vh',
                                'vertical-align': 'middle',
                                'display': 'flex',
                                'justify-self': 'center',
                                'align-self': 'center'
                            }, className="btn-group")
                    ], style={'flex': 1, 'background': 'cyan'})], style={'display': 'flex'}),
            ], color='secondary', inverse=False, style={'min-height': '80vh', 'padding': '10px',
                                                        'display': 'flex',
                                                        'border': '8px solid  # 73AD21'}), width=10)
        ],
            style={
                'width': '1600px',
                'overflow': 'auto',
                'resize': 'horizontal',
                'position': 'absolute',
                'top': '10%',
                'height': '90%',
                'left': '8%',
                'display': 'flex'
                    })
         , style={'height': '100vh', 'width': '100%', 'background-color': 'powderblue',
                            'margin-left': 'auto',
                            'margin-right': 'auto',
                            'display': 'grid',
                            'place-items': 'center',
                            'align-items': 'center',
                            'padding': '20em'})

if __name__ == '__main__':
    app.run_server()

the map loads just fine on my PC. Does the above code work on yours?

Hootie9lives commented 4 years ago

would you be so kind to use bold or italic on the changes you made? sometimes I get too tired from work to see the changes if not highlighted in some way

emilhe commented 4 years ago

You can compare using any diff tool, e.g. this one (first link on Google). In short, i removed the navbar (it was not defined), replaced your WMSTileLayer with a normal TileLayer (i don't have access to your tiles) and added some app code.

Hootie9lives commented 4 years ago

testing, no luck yet. Going blind looking at all the divs

emilhe commented 4 years ago

I just had a discussion with another Dash Leaflet user. She experienced a similar behaviour, in her case it was related to the use of tabs. Maps on tabs that were initially hidden would render falsely in some cases. Are you also using tabs?

Hootie9lives commented 4 years ago

Yes, I have it in one of the 4 tabs. If you have it narrowed down to tabs, maybe for now I can just use it without tabs

Hootie9lives commented 4 years ago

reporting back

image

I put the leaflet element outside of the tabs and now it works. Not sure what's causing it to not work in tabs

emilhe commented 4 years ago

Great that it works. Otherwise, after playing around with it, i think the easiest solution is simply to delay the rendering of the map (via a callback) until the tab is shown the first time.

Hootie9lives commented 4 years ago

looks like I may be able to get around this problem by not using dash-leaflet in tabs. I'll let you decide if this issue is ready to be closed. I appreciate your work!

emilhe commented 4 years ago

Thanks! I think that the option of delaying rendering via a callback is OK (or simply avoiding tabs, as you have done), so i'll close the issue for now. Happy coding :)