apache / echarts

Apache ECharts is a powerful, interactive charting and data visualization library for browser
https://echarts.apache.org
Apache License 2.0
60.65k stars 19.61k forks source link

Chart resize is not correct in some case of flex box layout. #11791

Open 100pah opened 4 years ago

100pah commented 4 years ago

Version

4.5.0

Steps to reproduce

Check it please: https://jsfiddle.net/6s4odwtu/

<!DOCTYPE html>

<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
    </head>
    <body>
        <style>
            .container {
                /* width: 500px; */
                display: flex;
                border: 1px solid red;
                padding: 5px;
            }
            .left {
                position: relative;
                height: 300px;
                flex: 0.5;
                border: 1px solid green;
            }
            .right {
                position: relative;
                height: 300px;
                flex: 1;
                border: 1px solid blue;
            }
            .chart {
                width: 100%;
                height: 100%;
                /* left: 0;
                top: 0; */
                position: relative;
            }
            #info {
                position: fixed;
                background: #000;
                border: 2px solid #eee;
                right: 10px;
                top: 10px;
                padding: 5px;
                width: 130px;
                height: 100px;
                color: #fff;
                box-shadow: 0 0 5px #000;
                font-size: 12px;
                z-index: 9999;
            }

        </style>

        <button id="expand">container: 700px</button>
        <button id="collapse">container: 500px</button>

        <div id="container" class="container">
            <div class="left" id="main0-box">
                <div id="main0" class="chart">
            </div>
            </div>
            <div class="right" id="main1-box">
                <div id="main1" class="chart">
            </div>

            </div>
        </div>

        <script>

            var expandBtn = document.getElementById('expand');
            var collapseBtn = document.getElementById('collapse');
            var container = document.getElementById('container');

            expandBtn.onclick = function () {
                container.style.width = '700px';
                resize();
            };
            collapseBtn.onclick = function () {
                container.style.width = '500px';
                resize();
            };

            var option;

            option0 = {
                xAxis: {},
                yAxis: {},
                series: {
                    type: 'line',
                    data: [[11, 22], [33, 44]]
                }
            };
            option1 = {
                xAxis: {},
                yAxis: {},
                series: {
                    type: 'line',
                    data: [[11, 22], [33, 44]]
                }
            };

            var main0 = document.getElementById('main0');
            var main1 = document.getElementById('main1');
            var main0Box = document.getElementById('main0-box');
            var main1Box = document.getElementById('main1-box');
            var chart0 = echarts.init(main0);
            var chart1 = echarts.init(main1);
            function resize() {
                console.log('before resize, main0Box', main0Box.offsetWidth);
                console.log('before resize, main1Box', main1Box.offsetWidth);
                chart0.resize();
                chart1.resize();
                console.log('after resize, main0Box', main0Box.offsetWidth);
                console.log('after resize, main1Box', main1Box.offsetWidth);
            };
            chart0.setOption(option0);
            chart1.setOption(option1);

        </script>

    </body>
</html>

What is expected?

Resize correct.

What is actually happening?

Resize not correct.

The reason seams to be: echarts(zrender) set the "width/height" manually on its root dom element, and try to set domRoot.style.display = 'none'; in Painter.js#resize.

That does not work in the case above: If there are more than one echarts instance and the echarts element is position: relative, set width/height and display:none one by one influence the layout of flex box. In the above case, it firstly call chart.resize() on the first chart. And then the chart set its domRoot.style.display = 'none';. But the second chart still have its width/height set on its dom root. Thus the offsetWidth the first chart fetched is different from the final width of its parent dom.

So, do we really need to manually set width/height on echarts root dom in zrender? If we do it, it might influence the layout in some cases.

echarts-bot[bot] commented 4 years ago

Hi! We've received your issue and please be patient to get responded. 🎉 The average response time is expected to be within one day for weekdays.

In the meanwhile, please make sure that you have posted enough image to demo your request. You may also check out the API and chart option to get the answer.

If you don't get helped for a long time (over a week) or have an urgent question to ask, you may also send an email to dev@echarts.apache.org. Please attach the issue link if it's a technical questions.

If you are interested in the project, you may also subscribe our mail list.

Have a nice day! 🍵

nuragic commented 4 years ago

Hello,

I've also found a similar (or maybe the same) problem using a chart inside a flexbox layout.

I have a layout that contains a left column, a central container, and a right column. Both left and right columns can be toggled on/off (show/hide); the central container is where the chart is rendered.

What I've been observing is: the width property (dynamically created CSS rule of the chart container div) increase dynamically e.g. when I hide a column in my layout; however, it doesn't decrease e.g. when I show again the same column of my layout.

If I remove the witdh property from the dynamically created CSS rule, then it's immediately recalculated by the JS and it actually have a right value! 🤷‍♂

nuragic commented 4 years ago

I've temporally solved this by setting width: auto!important from my CSS to override the width from the dynamically created CSS rule.

plainheart commented 3 years ago

Probably it can work by hiding manually all root DOMs of ECharts before resizing. Just like what mentioned in #13004. But I'm not clear if we should do it in zrender.

PVermeer commented 2 years ago

Faced the same issue: Work around (simplified):

new ResizeObserver(() => chart.resize()).observe(resizedElementByFlexbox);
ChristopherJBarr commented 1 year ago

I think I found a way around this. If you set the flexbox element wrapping the chart to position: relative and overflow:hidden (not needed just looks better that way). Then set the chart itself to position:absolute and 100% width and height, it seems to resize correctly.

djaeger-inercomp commented 1 year ago

@ChristopherJBarr brilliant, tried around for quite some time, then found your answer and it works straight away, thank you!

AKclown commented 1 year ago

I think I found a way around this. If you set the flexbox element wrapping the chart to position: relative and overflow:hidden (not needed just looks better that way). Then set the chart itself to position:absolute and 100% width and height, it seems to resize correctly.

Thank you so much, it works for me

fireflysemantics commented 10 months ago

I think this issue may be related to this: https://stackoverflow.com/questions/77661631/having-an-echart-on-the-front-and-back-of-a-flip-card-breaks-resizing

fireflysemantics commented 10 months ago

Since applying absolute positioning to the element that the EChart is rendered within like this this fixes it:

div[echarts] {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

Would it b e OK to just style the element that echarts is added to like this by default?

fuxing2024 commented 2 days ago

我想我找到了解决这个问题的方法。如果你将包裹图表的弹性框元素设置为 position:relative 和 overflow:hidden(不需要,这样看起来会更好)。然后将图表本身设置为 position:absolute 和 100% 宽度和高度,它似乎可以正确调整大小。

大哥真神了,非常有用,爆赞