bokeh icon indicating copy to clipboard operation
bokeh copied to clipboard

[BUG] Plot sizing not working with css transitions (scale)

Open xavArtley opened this issue 2 years ago • 2 comments

Software versions

Python version : 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:57:54) [MSC v.1924 64 bit (AMD64)] IPython version : (not installed) Tornado version : 6.3.3 Bokeh version : 3.1.1 BokehJS static path : c:\users\xa235208\documents\developments\bug_bokeh.venv\lib\site-packages\bokeh\server\static node.js version : v16.14.2 npm version : 8.5.0 Operating system : Windows-10-10.0.19041-SP0

Browser name and version

No response

Jupyter notebook / Jupyter Lab version

No response

Expected behavior

Bokeh figure correctly scaling after css transition

Observed behavior

When a css transition is used to scale an html element, bokeh figure with sizing_mode="stretch_width" does not rescale correctly

Example code

from bokeh.embed import components
from bokeh.plotting import figure
from bokeh.resources import Resources
from jinja2 import Template

# dummy plot
x_f = [1.5, 2, 9]
y_f = [3, 3, 3.1]
p1 = figure(height=350, sizing_mode="stretch_width")
p1.line(x_f, y_f)
script1, div1 = components(p1)
p2 = figure(height=350, sizing_mode="stretch_width")
p2.line(x_f, y_f)
script2, div2 = components(p2)


style = """
<style>
* {
    box-sizing: border-box;
}

.tabs {
    padding-left: 10px;
    padding-right: 10px;
    display: flex;
    width: 100%;
    border-radius: 8px 8px 0 0;
}

.tabby-tab label {
    display: block;
    box-sizing: border-box;
    /* tab content must clear this */
    height: 40px;

    padding: 10px;
    text-align: center;
    background: #9768D1;
    cursor: pointer;
    transition: background 0.5s ease;

}

.tabby-tab label:hover {
    background: #7B52AB;
}

.tabby-content {
    position: absolute;
    top: 40px;

    transition:
        opacity 0.8s ease,
        transform 0.8s ease;
        right 0.8s ease;
        left 0.8s ease;

    /* show/hide */
    opacity: 0;
    transform: scale(0.1);
    transform-origin: top left;

}

.tabby-tab [type=radio] {
    display: none;
}

[type=radio]:checked~label {
    background: #553285;
    z-index: 2;
}

[type=radio]:checked~label~.tabby-content {
    z-index: 1;
    opacity: 1;
    transform: scale(1);
    left: 10px;
    right: 10px;
}

.plots {
    width: 100%;
}

.plot {
    height: 350px;
}
</style>
"""

template = Template(
    """<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        {{ resources }}
        {{ style }}
        {{ script1 }}
        {{ script2 }}
    </head>
    <body>
        <section>
            <div class="tabs">
                <div class="tabby-tab">
                    <input type="radio" id="tab-1" name="tabby-tabs" checked>
                    <label for="tab-1">Tab1</label>
                    <div class="tabby-content">
                        <div class="plot">
                            {{div2}}
                        </div>
                    </div>
                </div>
                <div class="tabby-tab">
                    <input type="radio" id="tab-2" name="tabby-tabs">
                    <label for="tab-2">Tab2</label>
                    <div class="tabby-content">
                        <div class="plot">
                            {{div1}}
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </body>
</html>
"""
)

resources = Resources().render()

html = template.render(
    resources=resources,
    style=style,
    script1=script1,
    script2=script2,
    div1=div1,
    div2=div2,
)
with open("test.html", "w") as file:
    file.write(html)

Stack traceback or browser console output

No response

Screenshots

bokeh_sizing_bug

xavArtley avatar Nov 13 '23 12:11 xavArtley

My work around :

 <script>
    const tabs_content = document.getElementsByClassName("tabby-content")
    Array.from(tabs_content).forEach(el => el.addEventListener(
        "transitionend", evt => {
            if (evt.propertyName == "transform") {
                const bkfigures = Array.from(evt.target.getElementsByClassName("bk-Figure"))
                Bokeh.index.roots.filter(root => bkfigures.includes(root.el)).map(root =>
                    {
                        root.invalidate_layout()
                    }
                )
            }
        }
    ))
    </script>

not perfect but better than nothing workaround_bokeh_sizing_bug

xavArtley avatar Nov 14 '23 09:11 xavArtley

@xavArtley first things first, is this an issue with latest (3.3.2)?

bryevdv avatar Dec 24 '23 04:12 bryevdv