Browse Source

EChart resizeObserver skipping initial rendering (#4584)

Should fix #4535 overcoming the before discussed resizing approaches
causing issues, illustrated
[here](https://depley.github.io/nicegui-custom-echarts/)


Suggested solution is based on [ecomfe/vue-echarts ..
autoresize.ts](https://github.com/ecomfe/vue-echarts/blob/b7852ab6430084c54a8e1c0a05648748da94bc64/src/composables/autoresize.ts#L7).
Basically a direct attached resizeObserver but skipping an initial
resize if the initial size of the container element hasn't changed.

The in [#4535
comment](https://github.com/zauberzeug/nicegui/issues/4535#issuecomment-2781492261)
discussed MREs can be reproduced in nicegui via

```py
from nicegui import ui

# scatter series chart
# expected behaviour: should not render twice initially, render once after resizing
echart_many_data = ui.echart({
    'xAxis': {'type': 'value'},
    'yAxis': {'type': 'value'},
    'series': [{
        'type': 'scatter',
        'data': [[x, x] for x in range(20_000)]
    }],
})

# line series chart
# expected behaviour: animation drawing a line and points on initial rendering 
# (broken animation behaviour was that the line is already there)  
echart_animation = ui.echart({
    'xAxis': {
        'type': 'category',
        'data': ["Mon", "Tue", "Wed", "Thu", "Fri"],
    },
    'yAxis': {'type': 'value'},
    'series': [{
        'type': 'line',
        'data': [150, 230, 224, 147, 260],
    }],
})

ui.run(uvicorn_reload_includes='*.py,*.js,*.vue')
```

---------

Co-authored-by: Falko Schindler <falko@zauberzeug.com>
depley 1 month ago
parent
commit
ea165f8f61
1 changed files with 12 additions and 7 deletions
  1. 12 7
      nicegui/elements/echart.js

+ 12 - 7
nicegui/elements/echart.js

@@ -54,13 +54,18 @@ export default {
       this.chart.on(event, (e) => this.$emit(`chart:${event}`, e));
     }
 
-    // Prevent interruption of chart animations due to resize operations.
-    // It is recommended to register the callbacks for such an event before setOption.
-    const createResizeObserver = () => {
-      new ResizeObserver(this.chart.resize).observe(this.$el);
-      this.chart.off("finished", createResizeObserver);
-    };
-    this.chart.on("finished", createResizeObserver);
+    let initialResizeTriggered = false;
+    const initialWidth = this.$el.offsetWidth;
+    const initialHeight = this.$el.offsetHeight;
+    new ResizeObserver(() => {
+      if (!initialResizeTriggered) {
+        initialResizeTriggered = true;
+        if (this.$el.offsetWidth === initialWidth && this.$el.offsetHeight === initialHeight) {
+          return;
+        }
+      }
+      this.chart.resize();
+    }).observe(this.$el);
 
     this.update_chart();
   },