From 03b07ec8c6301e78a50390f50af9ae1976bdfb53 Mon Sep 17 00:00:00 2001 From: Simon Brunel Date: Sat, 29 Jul 2017 16:16:46 +0200 Subject: [PATCH] Replace the IFRAME resizer by DIVs Resize detection is now based on scroll events from two divs nested under a main one. Implementation inspired from https://github.com/marcj/css-element-queries. --- src/core/core.controller.js | 4 +- src/platforms/platform.dom.js | 80 ++++++++++++++++++----------- test/specs/core.controller.tests.js | 6 ++- 3 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 1dbf90f0162..5ae591d41fe 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -731,9 +731,7 @@ module.exports = function(Chart) { listeners[type] = listener; }); - // Responsiveness is currently based on the use of an iframe, however this method causes - // performance issues and could be troublesome when used with ad blockers. So make sure - // that the user is still able to create a chart without iframe when responsive is false. + // Elements used to detect size change should not be injected for non responsive charts. // See https://github.com/chartjs/Chart.js/issues/2210 if (me.options.responsive) { listener = function() { diff --git a/src/platforms/platform.dom.js b/src/platforms/platform.dom.js index 2659ac6a433..8fe9f27073c 100644 --- a/src/platforms/platform.dom.js +++ b/src/platforms/platform.dom.js @@ -165,43 +165,62 @@ function throttled(fn, thisArg) { }; } +// Implementation based on https://github.com/marcj/css-element-queries function createResizer(handler) { - var iframe = document.createElement('iframe'); - iframe.className = 'chartjs-hidden-iframe'; - iframe.style.cssText = - 'display:block;' + - 'overflow:hidden;' + - 'border:0;' + - 'margin:0;' + - 'top:0;' + + var resizer = document.createElement('div'); + var cls = CSS_PREFIX + 'size-monitor'; + var maxSize = 1000000; + var style = + 'position:absolute;' + 'left:0;' + - 'bottom:0;' + + 'top:0;' + 'right:0;' + - 'height:100%;' + - 'width:100%;' + - 'position:absolute;' + + 'bottom:0;' + + 'overflow:hidden;' + 'pointer-events:none;' + + 'visibility:hidden;' + 'z-index:-1;'; - // Prevent the iframe to gain focus on tab. - // https://github.com/chartjs/Chart.js/issues/3090 - iframe.tabIndex = -1; - - // Prevent iframe from gaining focus on ItemMode keyboard navigation - // Accessibility bug fix - iframe.setAttribute('aria-hidden', 'true'); - - // If the iframe is re-attached to the DOM, the resize listener is removed because the - // content is reloaded, so make sure to install the handler after the iframe is loaded. - // https://github.com/chartjs/Chart.js/issues/3521 - addEventListener(iframe, 'load', function() { - addEventListener(iframe.contentWindow || iframe, 'resize', handler); - // The iframe size might have changed while loading, which can also - // happen if the size has been changed while detached from the DOM. + resizer.style.cssText = style; + resizer.className = cls; + resizer.innerHTML = + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
'; + + var expand = resizer.childNodes[0]; + var shrink = resizer.childNodes[1]; + + resizer._reset = function() { + expand.scrollLeft = maxSize; + expand.scrollTop = maxSize; + shrink.scrollLeft = maxSize; + shrink.scrollTop = maxSize; + }; + var onScroll = function() { + resizer._reset(); handler(); - }); + }; + + addEventListener(expand, 'scroll', onScroll.bind(expand, 'expand')); + addEventListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink')); - return iframe; + return resizer; } // https://davidwalsh.name/detect-node-insertion @@ -253,6 +272,9 @@ function addResizeListener(node, listener, chart) { if (container && container !== resizer.parentNode) { container.insertBefore(resizer, container.firstChild); } + + // The container size might have changed, let's reset the resizer state. + resizer._reset(); } }); } diff --git a/test/specs/core.controller.tests.js b/test/specs/core.controller.tests.js index 24f062b78d3..76740315ae1 100644 --- a/test/specs/core.controller.tests.js +++ b/test/specs/core.controller.tests.js @@ -420,7 +420,8 @@ describe('Chart', function() { waitForResize(chart, function() { var resizer = wrapper.firstChild; - expect(resizer.tagName).toBe('IFRAME'); + expect(resizer.className).toBe('chartjs-size-monitor'); + expect(resizer.tagName).toBe('DIV'); expect(chart).toBeChartOfSize({ dw: 455, dh: 355, rw: 455, rh: 355, @@ -687,7 +688,8 @@ describe('Chart', function() { var wrapper = chart.canvas.parentNode; var resizer = wrapper.firstChild; expect(wrapper.childNodes.length).toBe(2); - expect(resizer.tagName).toBe('IFRAME'); + expect(resizer.className).toBe('chartjs-size-monitor'); + expect(resizer.tagName).toBe('DIV'); chart.destroy();