From 0f43866d514d10b821cf688cb964b0918fdc3258 Mon Sep 17 00:00:00 2001 From: Ya-Fan Chen <20377719+Lexachoc@users.noreply.github.com> Date: Thu, 3 Sep 2026 22:13:45 +0200 Subject: [PATCH 1/6] use ResizeObserver for responsive charts --- src/lib/clear_responsive.js | 6 +++--- src/plot_api/plot_api.js | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/lib/clear_responsive.js b/src/lib/clear_responsive.js index a2e33f26a1c..dada7f6d69b 100644 --- a/src/lib/clear_responsive.js +++ b/src/lib/clear_responsive.js @@ -6,8 +6,8 @@ * @param {DOM node or object} gd : graph div object */ module.exports = function clearResponsive(gd) { - if(gd._responsiveChartHandler) { - window.removeEventListener('resize', gd._responsiveChartHandler); - delete gd._responsiveChartHandler; + if(gd._responsiveChartObserver) { + gd._responsiveChartObserver.disconnect(); + delete gd._responsiveChartObserver; } }; diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 0adcd88b12b..67c306e54a6 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -167,14 +167,13 @@ function _doPlot(gd, data, layout, config) { // make the figure responsive if (gd._context.responsive) { - if (!gd._responsiveChartHandler) { - // Keep a reference to the resize handler to purge it down the road - gd._responsiveChartHandler = function () { + if (!gd._responsiveChartObserver) { + // Keep a reference to the resize observer to purge it down the road + gd._responsiveChartObserver = new ResizeObserver(function() { if (!Lib.isHidden(gd)) Plots.resize(gd); }; - // Listen to window resize - window.addEventListener('resize', gd._responsiveChartHandler); + gd._responsiveChartObserver.observe(gd); } } else { Lib.clearResponsive(gd); From 706d97f3dc8b9eb201289a27ccf8a606ed1dd9c7 Mon Sep 17 00:00:00 2001 From: Lexachoc <20377719+Lexachoc@users.noreply.github.com> Date: Thu, 3 Sep 2026 22:20:08 +0200 Subject: [PATCH 2/6] fix syntax error --- src/plot_api/plot_api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 67c306e54a6..02314767035 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -171,7 +171,7 @@ function _doPlot(gd, data, layout, config) { // Keep a reference to the resize observer to purge it down the road gd._responsiveChartObserver = new ResizeObserver(function() { if (!Lib.isHidden(gd)) Plots.resize(gd); - }; + }); gd._responsiveChartObserver.observe(gd); } From 7117e2e31f09fb6dc3863f7ec708853b4830dbd1 Mon Sep 17 00:00:00 2001 From: Ya-Fan Chen <20377719+Lexachoc@users.noreply.github.com> Date: Thu, 3 Sep 2026 23:21:26 +0200 Subject: [PATCH 3/6] add draftlog --- draftlogs/8017_change.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 draftlogs/8017_change.md diff --git a/draftlogs/8017_change.md b/draftlogs/8017_change.md new file mode 100644 index 00000000000..e2087918049 --- /dev/null +++ b/draftlogs/8017_change.md @@ -0,0 +1 @@ +Use `ResizeObserver` for responsive chart resizing instead of listening for window resize events [[#8017](https://github.com/plotly/plotly.js/pull/8017)] From 0c65dfbbef3eb99db689afd3d57de83ede1abea2 Mon Sep 17 00:00:00 2001 From: Lexachoc <20377719+Lexachoc@users.noreply.github.com> Date: Mon, 14 Sep 2026 20:38:17 +0200 Subject: [PATCH 4/6] Apply batched suggestions from code review --- src/lib/clear_responsive.js | 6 +++--- src/plot_api/plot_api.js | 33 ++++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/lib/clear_responsive.js b/src/lib/clear_responsive.js index dada7f6d69b..643e6cade88 100644 --- a/src/lib/clear_responsive.js +++ b/src/lib/clear_responsive.js @@ -6,8 +6,8 @@ * @param {DOM node or object} gd : graph div object */ module.exports = function clearResponsive(gd) { - if(gd._responsiveChartObserver) { - gd._responsiveChartObserver.disconnect(); - delete gd._responsiveChartObserver; + if (gd._clearResponsive) { + gd._clearResponsive(); + delete gd._clearResponsive; } }; diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index 02314767035..f48d808425b 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -165,15 +165,34 @@ function _doPlot(gd, data, layout, config) { gd.calcdata[i][0].trace = gd._fullData[i]; } - // make the figure responsive + // Make the figure responsive. We need to save the callback that clears the + // listener for proper teardown. if (gd._context.responsive) { - if (!gd._responsiveChartObserver) { - // Keep a reference to the resize observer to purge it down the road - gd._responsiveChartObserver = new ResizeObserver(function() { + if (!gd._clearResponsive) { + const resizeIfShown = () => { if (!Lib.isHidden(gd)) Plots.resize(gd); - }); - - gd._responsiveChartObserver.observe(gd); + }; + // We still need the window resize listener for `fillFrame` and an + // escape hatch for browser-like users that don't support `ResizeObserver` (like jsdom) + if (gd._context.fillFrame || typeof ResizeObserver === 'undefined') { + window.addEventListener('resize', resizeIfShown); + gd._clearResponsive = () => window.removeEventListener('resize', resizeIfShown); + } else { + let previousWidth = gd.offsetWidth; + let previousHeight = gd.offsetHeight; + const observer = new ResizeObserver(() => { + const width = gd.offsetWidth; + const height = gd.offsetHeight; + // Ignore size changes of one pixel or less (the same as plotAutoSize) + const changed = Math.abs(width - previousWidth) > 1 || Math.abs(height - previousHeight) > 1; + previousWidth = width; + previousHeight = height; + // Only resize plot if it changed and is visible (width and height > 0) + if (changed && width && height) resizeIfShown(); + }); + observer.observe(gd); + gd._clearResponsive = () => observer.disconnect(); + } } } else { Lib.clearResponsive(gd); From 200df32540ec07fead7e856f66f63eafc57727a5 Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Mon, 14 Sep 2026 15:01:05 -0600 Subject: [PATCH 5/6] Update attribute description --- src/plot_api/plot_config.js | 4 ++-- src/types/generated/schema.d.ts | 2 +- test/plot-schema.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index abbb689b673..dc67084bb35 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -128,8 +128,8 @@ var configAttributes = { valType: 'boolean', dflt: false, description: [ - 'Determines whether to change the layout size when window is resized.', - 'In v3, this option will be removed and will always be true.' + 'Determines whether to change the layout size when the graph container is resized.', + 'In v5, this option will be removed and will always be true.' ].join(' ') }, fillFrame: { diff --git a/src/types/generated/schema.d.ts b/src/types/generated/schema.d.ts index 4766d954d4c..c0a9eab9fad 100644 --- a/src/types/generated/schema.d.ts +++ b/src/types/generated/schema.d.ts @@ -16809,7 +16809,7 @@ export interface ConfigBase { */ queueLength?: number; /** - * Determines whether to change the layout size when window is resized. In v3, this option will be removed and will always be true. + * Determines whether to change the layout size when the graph container is resized. In v5, this option will be removed and will always be true. * @default false */ responsive?: boolean; diff --git a/test/plot-schema.json b/test/plot-schema.json index 39767518c96..c821c1d5ec4 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -279,7 +279,7 @@ "valType": "integer" }, "responsive": { - "description": "Determines whether to change the layout size when window is resized. In v3, this option will be removed and will always be true.", + "description": "Determines whether to change the layout size when the graph container is resized. In v5, this option will be removed and will always be true.", "dflt": false, "valType": "boolean" }, From 7428ff6441ee722ec73356c99ce27bff7891ecb7 Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Mon, 14 Sep 2026 15:10:18 -0600 Subject: [PATCH 6/6] Update draftlog --- draftlogs/8017_change.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draftlogs/8017_change.md b/draftlogs/8017_change.md index e2087918049..6be3df02dd3 100644 --- a/draftlogs/8017_change.md +++ b/draftlogs/8017_change.md @@ -1 +1 @@ -Use `ResizeObserver` for responsive chart resizing instead of listening for window resize events [[#8017](https://github.com/plotly/plotly.js/pull/8017)] +Use `ResizeObserver` for responsive chart resizing instead of listening for window resize events [[#8017](https://github.com/plotly/plotly.js/pull/8017)], with thanks to @Lexachoc for the contribution!