Replace the IFRAME resizer by DIVs (#4596)

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.
This commit is contained in:
Simon Brunel
2017-08-02 07:25:55 +02:00
committed by GitHub
parent f90ee8c786
commit 2c52209ba7
3 changed files with 55 additions and 33 deletions

View File

@@ -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() {

View File

@@ -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;' +
'left:0;' +
'bottom:0;' +
'right:0;' +
'height:100%;' +
'width:100%;' +
var resizer = document.createElement('div');
var cls = CSS_PREFIX + 'size-monitor';
var maxSize = 1000000;
var style =
'position:absolute;' +
'left:0;' +
'top:0;' +
'right:0;' +
'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;
resizer.style.cssText = style;
resizer.className = cls;
resizer.innerHTML =
'<div class="' + cls + '-expand" style="' + style + '">' +
'<div style="' +
'position:absolute;' +
'width:' + maxSize + 'px;' +
'height:' + maxSize + 'px;' +
'left:0;' +
'top:0">' +
'</div>' +
'</div>' +
'<div class="' + cls + '-shrink" style="' + style + '">' +
'<div style="' +
'position:absolute;' +
'width:200%;' +
'height:200%;' +
'left:0; ' +
'top:0">' +
'</div>' +
'</div>';
// Prevent iframe from gaining focus on ItemMode keyboard navigation
// Accessibility bug fix
iframe.setAttribute('aria-hidden', 'true');
var expand = resizer.childNodes[0];
var shrink = resizer.childNodes[1];
// 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._reset = function() {
expand.scrollLeft = maxSize;
expand.scrollTop = maxSize;
shrink.scrollLeft = maxSize;
shrink.scrollTop = maxSize;
};
var onScroll = function() {
resizer._reset();
handler();
});
};
return iframe;
addEventListener(expand, 'scroll', onScroll.bind(expand, 'expand'));
addEventListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink'));
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();
}
});
}

View File

@@ -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();