Skip to content

Commit

Permalink
Replace the IFRAME resizer by DIVs (chartjs#4596)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
simonbrunel authored and yofreke committed Dec 30, 2017
1 parent 797f304 commit b6e1255
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 34 deletions.
4 changes: 1 addition & 3 deletions src/core/core.controller.js
Expand Up @@ -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() {
Expand Down
80 changes: 51 additions & 29 deletions src/platforms/platform.dom.js
Expand Up @@ -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 =
'<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>';

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
Expand Down Expand Up @@ -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();
}
});
}
Expand Down
6 changes: 4 additions & 2 deletions test/specs/core.controller.tests.js
Expand Up @@ -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,
Expand Down Expand Up @@ -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();

Expand Down

0 comments on commit b6e1255

Please sign in to comment.