Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui.leaflet and bind_visibility: tiles not loading #2338

Open
kleynjan opened this issue Jan 10, 2024 · 4 comments
Open

ui.leaflet and bind_visibility: tiles not loading #2338

kleynjan opened this issue Jan 10, 2024 · 4 comments
Labels
waiting Can not be fixed right now

Comments

@kleynjan
Copy link
Sponsor Contributor

Description

  1. Using ui.leaflet, create a map that is initially hidden and later (when location etc are known) made visible through bind_visibility.
  2. Expected behavior: when the bound value changes to True, the map is shown with the given center & zoom.
  3. Instead, the map tiles are not shown -- they appear only if/when the window is resized.

There seems to be a known issue with Leaflet when the container size is not known when initializing, but I don't know how to further isolate it for Nicegui. Likely a CSS issue?

See example below. Both maps are initially hidden. The left map is then made visible using tailwind classes, that works. Visibility for the map on the right hand side is enabled with bind_visibility; the map tiles are not correctly shown.

Screenshot 2024-01-10 at 16 32 39
from nicegui import ui


def toggle_visibility():
    a, r = ("visible", "invisible") if onoff1.value else ("invisible", "visible")
    mapcard.classes(add=a, remove=r)


onoff1 = ui.switch("via tailwind classes", value=False, on_change=toggle_visibility)

onoff2 = ui.switch("via bind_visibility", value=False)

with ui.card().classes("w-full flex flex-row"):
    with ui.card().classes("w-1/3 flex invisible") as mapcard:
        m = ui.leaflet(center=(51.505, -0.09)).classes("h-screen visible")

    with ui.card().classes("w-1/3 flex").bind_visibility_from(onoff2, "value"):
        m = ui.leaflet(center=(51.505, -0.09)).classes("h-screen")

ui.run()

The flex classes are only for display here, AFAICT the difference between the two methods remains with all styling I've tried. As a workaround I can work with the Tailwind classes, but that is of course a bit more clumsy.

@kleynjan kleynjan changed the title LeafletJS and bind_visibility: tiles not loading ui.leaflet and bind_visibility: tiles not loading Jan 10, 2024
@falkoschindler
Copy link
Contributor

Hi @kleynjan,

This is indeed an annoying bug we also noticed in one of our projects. I took the opportunity to further investigate different methods to show and hide a Leaflet map:

ui.label('Map 1: set_visibility')
ui.button('Show', on_click=lambda: m1.set_visibility(True))
ui.button('Hide', on_click=lambda: m1.set_visibility(False))
with ui.card() as m1:
    ui.leaflet(center=(51.505, -0.09)).classes('w-96 h-64')
    m1.set_visibility(False)

ui.label('Map 2: classes "visible" and "hidden"')
ui.button('Show', on_click=lambda: m2.classes('visible', remove='hidden'))
ui.button('Hide', on_click=lambda: m2.classes('hidden', remove='visible'))
with ui.card() as m2:
    ui.leaflet(center=(51.505, -0.09)).classes('w-96 h-64')
    m2.classes('hidden')

ui.label('Map 3: CSS display "block" and "none"')
ui.button('Show', on_click=lambda: m3.style('display: block'))
ui.button('Hide', on_click=lambda: m3.style('display: none'))
with ui.card() as m3:
    ui.leaflet(center=(51.505, -0.09)).classes('w-96 h-64')
    m3.style('display: none')

ui.label('Map 4: classes "visible" and "invisible"')
ui.button('Show', on_click=lambda: m4.classes('visible', remove='invisible'))
ui.button('Hide', on_click=lambda: m4.classes('invisible', remove='visible'))
with ui.card() as m4:
    ui.leaflet(center=(51.505, -0.09)).classes('w-96 h-64')
    m4.classes('invisible')

ui.label('Map 5: CSS visibility "visible" and "hidden"')
ui.button('Show', on_click=lambda: m5.style('visibility: visible'))
ui.button('Hide', on_click=lambda: m5.style('visibility: hidden'))
with ui.card() as m5:
    ui.leaflet(center=(51.505, -0.09)).classes('w-96 h-64')
    m5.style('visibility: hidden')

The first three methods are basically the same: set_visibility sets classes visible and hidden which change the visibility CSS property. The Leaflet map is broken like in your screenshot.

The last two methods change the display CSS property. The Leaflet map looks ok, but occupies space while hidden. This might be a useful workaround, unless you really need the map to be gone without taking up space.

In this StackOverflow post I found a workaround using the CSS height property:

ui.button('Show', on_click=lambda: m.style(remove='height: 0px;'))
ui.button('Hide', on_click=lambda: m.style('height: 0px;'))
with ui.element() as m:
    ui.leaflet(center=(51.505, -0.09)).classes('w-96 h-64')
    m.style('height: 0px; overflow: hidden')

@falkoschindler
Copy link
Contributor

Oh and here is another workaround using the map method invalidateSize:

ui.button('Show', on_click=lambda: (e.set_visibility(True), m.run_map_method('invalidateSize')))
ui.button('Hide', on_click=lambda: e.set_visibility(False))
with ui.element() as e:
    m = ui.leaflet(center=(51.505, -0.09)).classes('w-96 h-64')
    e.set_visibility(False)

@falkoschindler
Copy link
Contributor

It seems like this issue will be fixed in Leaflet 2.0: Leaflet/Leaflet#9010
So I think we need to sit and wait for its release.

@falkoschindler falkoschindler added the waiting Can not be fixed right now label Jan 21, 2024
@kleynjan
Copy link
Sponsor Contributor Author

Of course, Falko, that's fine. For the time being there are workarounds available.

Thanks for investigating,
-Peter

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting Can not be fixed right now
Projects
None yet
Development

No branches or pull requests

2 participants