From 267522045284953b0f878208428994897718a7cf Mon Sep 17 00:00:00 2001 From: Scott Bell Date: Fri, 15 Dec 2023 09:40:36 +0100 Subject: [PATCH] Defer intersection monitoring until needed to prevent race conditions (#7278) * defer visibility rendering until actually used to prevent race conditions * remove extrace space --- API.md | 2 ++ src/plugins/plot/chart/MctChart.vue | 6 +++++- src/utils/visibility/VisibilityObserver.js | 9 +++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/API.md b/API.md index c0680282fc..ded6724a6d 100644 --- a/API.md +++ b/API.md @@ -1319,6 +1319,8 @@ The `renderWhenVisible` function is passed to the show function as part of the ` Additionally, `renderWhenVisible` returns a boolean value indicating whether the provided function was executed immediately (`true`) or deferred (`false`). +Monitoring of visibility begins after the first call to `renderWhenVisible` is made. + Here’s the signature for the show function: `show(element, isEditing, viewOptions)` diff --git a/src/plugins/plot/chart/MctChart.vue b/src/plugins/plot/chart/MctChart.vue index cb503073b7..cb15232d65 100644 --- a/src/plugins/plot/chart/MctChart.vue +++ b/src/plugins/plot/chart/MctChart.vue @@ -199,8 +199,8 @@ export default { mounted() { this.chartVisible = true; this.chartContainer = this.$refs.chart; + this.drawnOnce = false; this.visibilityObserver = new IntersectionObserver(this.visibilityChanged); - this.visibilityObserver.observe(this.chartContainer); eventHelpers.extend(this); this.seriesModels = []; this.config = this.getConfig(); @@ -687,6 +687,10 @@ export default { if (!this.drawScheduled) { const called = this.renderWhenVisible(this.draw); this.drawScheduled = called; + if (!this.drawnOnce && called) { + this.drawnOnce = true; + this.visibilityObserver.observe(this.chartContainer); + } } }, draw() { diff --git a/src/utils/visibility/VisibilityObserver.js b/src/utils/visibility/VisibilityObserver.js index 2088c6aed5..a0ab8572bf 100644 --- a/src/utils/visibility/VisibilityObserver.js +++ b/src/utils/visibility/VisibilityObserver.js @@ -40,9 +40,9 @@ export default class VisibilityObserver { } this.#element = element; this.isIntersecting = true; + this.calledOnce = false; this.#observer = new IntersectionObserver(this.#observerCallback); - this.#observer.observe(this.#element); this.lastUnfiredFunc = null; this.renderWhenVisible = this.renderWhenVisible.bind(this); } @@ -66,7 +66,12 @@ export default class VisibilityObserver { * @returns {boolean} True if the function was executed immediately, false otherwise. */ renderWhenVisible(func) { - if (this.isIntersecting) { + if (!this.calledOnce) { + this.calledOnce = true; + this.#observer.observe(this.#element); + window.requestAnimationFrame(func); + return true; + } else if (this.isIntersecting) { window.requestAnimationFrame(func); return true; } else {