widgetti / ipyvuetify

Jupyter widgets based on vuetify UI components
MIT License
345 stars 59 forks source link

Select widget is not being displayed in a full screen ipyleaflet map #141

Open dfguerrerom opened 3 years ago

dfguerrerom commented 3 years ago

I'm trying to include some ipyvuetify widgets inside an ipyleaflet map, however, when I try to open the items in the Full-screen mode, they are not displayed.


from ipyleaflet import Map, WidgetControl, FullScreenControl
import ipyvuetify as v

map_=Map(center=[4,-74], zoom=5)
map_.add_control(FullScreenControl())

dropdown = v.Select(items=[1,2,3,4,5,])
widget_control = WidgetControl(widget=dropdown)
map_.add_control(widget_control)

map_

This is without full-screen mode image

And this is how is displayed in the full-screen map image

mariobuikhuizen commented 3 years ago

ipyvuetify injects a special element in the notebook to be able to display overlays (like the item list of a select). This element is probably not part of the DOM that is used in full-screen.

Screenshot 2021-08-31 at 12 37 34
12rambau commented 2 years ago

I know that's an old one but I have news on this issue:

So when you use the fullscreen option of the map the div that contains the map get the maximum z-index via the user agent (https://stackoverflow.com/questions/18578244/displaying-elements-other-than-fullscreen-element-html5-fullscreen-api).

the rest of the component are shown without problem because they have the following structure:

<div class="leaflet-container ...">  <!-- that's the full screen element --> 
    <div class="leaflet-pane leaflet-map-pane"> <!-- that's the map -->
    <div class="leaflet-control-container>
        <div class="leaflet-top leaflet-left">...</div> <!-- that's where the components live -->
    </div>
</div>

According to what I've understand everything that live outside of the "fullscrened" component (in this case the "leaflet-container") will be hidden. That's the case of the menus as they are living in the "overlay" component.

<div vuetify-overlay="true class="v-application ...">
    <div class="v-menu_content">...</div> <!-- this is where the menus are living they are just display or hidden depending on menu click with the "display" style -->
</div>

So @mariobuikhuizen the element is still part of the DOM the only issue is that it's outside of the computed "rendered_cell" <div> tag

That being said i don't have any solution or css trick to avoid this situation

12rambau commented 2 years ago

Here is the start of a solution. I created a custom fullsreenControl that fake the fullscreen behaviour by manually setting the dimensions of the map. as I keep control over the z-index, I can set it under the one of the "overlay" component (802).

from ipywidgets import Button, Layout
from ipyleaflet import WidgetControl
from IPython.display import Javascript, display
import ipyvuetify as v

class FullScreenControl(WidgetControl):

    ICONS = ["expand", "compress"]
    METHODS = ["embed","fullscreen"]

    def __init__(self, **kwargs):

        self.zoomed = False

        # create a btn
        self.w_btn = Button( 
            tooltip="set fullscreen",
            icon=self.ICONS[self.zoomed],
            layout=Layout(width="30px", height="30px", line_height="30px", padding="0px"),
        )

        # overwrite the widget set in the kwargs (if any)
        kwargs["widget"] = self.w_btn
        kwargs["position"] = kwargs.pop("position", "topleft")
        kwargs["transparent_bg"] = True

        # create the widget
        super().__init__(**kwargs)

        # add javascrip behaviour
        self.w_btn.on_click(self._on_click)

        # template with js behaviour
        self.template = v.VuetifyTemplate(template="""
        <script>
            {methods: {
                jupyter_fullscreen() {
                    var element = document.getElementsByClassName("leaflet-container")[0];
                    element.style["position"] = "fixed";
                    element.style["width"] = "100vw";
                    element.style["height"] = "100vh";
                    element.style["z-index"] = 800;
                    element.style["top"] = 0;
                    element.style["left"] = 0;
                    window.dispatchEvent(new Event('resize'));
                },
                jupyter_embed() {
                    var element = document.getElementsByClassName("leaflet-container")[0];
                    element.style["position"] = "relative";
                    element.style["width"] = "";
                    element.style["height"] = "";
                    element.style["z-index"] = 400;
                    element.style["top"] = "";
                    element.style["left"] = "";
                    window.dispatchEvent(new Event('resize'));
                }
            }}
        </script>
        """)
        display(self.template)

    def _on_click(self, widget):

        # change the zoom state 
        self.zoomed = not self.zoomed

        # change icon
        self.w_btn.icon = self.ICONS[self.zoomed]

        # zoom 
        self.template.send({"method": self.METHODS[self.zoomed], "args": []})

        return

from ipyleaflet import Map, WidgetControl
import ipyvuetify as v

map_=Map(center=[4,-74], zoom=5)
map_.add_control(FullScreenControl(position="topleft"))

dropdown = v.Select(label="titi", items=["toto",2,3,4,5,], v_model=None)
widget_control = WidgetControl(widget=dropdown)
map_.add_control(widget_control)

map_

it works well in voila dashboard but lead to funny results in JupyterNotebook windows. @dfguerrerom I think I will include this component and refine it in sepal-ui directly

12rambau commented 1 year ago

I think this is now solved. The solution is complex and involved CSS and JS tricks. I would suggest anyone coming here to use sepal-ui to use ipyvuetify on maps, we already took care of most of the issues.