Inject iframe for responsive charts only

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.
This commit is contained in:
Simon Brunel 2016-09-24 21:51:12 +02:00 committed by Evert Timberg
parent d3d9573af5
commit 806a3832ef
4 changed files with 65 additions and 25 deletions

View File

@ -151,8 +151,11 @@ module.exports = function(Chart) {
me.id = helpers.uid();
me.chart = instance;
me.config = instance.config;
me.options = me.config.options;
me.config = config;
me.options = config.options;
// Add the chart instance to the global namespace
Chart.instances[me.id] = me;
Object.defineProperty(me, 'data', {
get: function() {
@ -160,18 +163,16 @@ module.exports = function(Chart) {
}
});
// Always bind this so that if the responsive state changes we still work
// 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.
// See https://github.com/chartjs/Chart.js/issues/2210
if (me.options.responsive) {
helpers.addResizeListener(canvas.parentNode, function() {
if (me.config.options.responsive) {
me.resize();
}
});
// Add the chart instance to the global namespace
Chart.instances[me.id] = me;
if (me.options.responsive) {
// Silent resize before chart draws
// Initial resize before chart draws (must be silent to preserve initial animations).
me.resize(true);
}
@ -684,11 +685,11 @@ module.exports = function(Chart) {
me.stop();
me.clear();
helpers.unbindEvents(me, me.events);
if (canvas) {
helpers.unbindEvents(me, me.events);
helpers.removeResizeListener(canvas.parentNode);
releaseCanvas(canvas);
me.chart.canvas = null;
}
// if we scaled the canvas in response to a devicePixelRatio !== 1, we need to undo that transform here

View File

@ -980,15 +980,24 @@ module.exports = function(Chart) {
// Insert the iframe so that contentWindow is available
node.insertBefore(iframe, node.firstChild);
// Let's keep track of this added iframe and thus avoid DOM query when removing it.
node._chartjs = {
resizer: iframe
};
this.addEvent(iframe.contentWindow || iframe, 'resize', callback);
};
helpers.removeResizeListener = function(node) {
var hiddenIframe = node.querySelector('.chartjs-hidden-iframe');
// Remove the resize detect iframe
if (hiddenIframe) {
hiddenIframe.parentNode.removeChild(hiddenIframe);
if (!node || !node._chartjs) {
return;
}
var iframe = node._chartjs.resizer;
if (iframe) {
iframe.parentNode.removeChild(iframe);
}
delete node._chartjs;
};
helpers.isArray = Array.isArray?
function(obj) {

View File

@ -149,6 +149,18 @@ describe('Chart.Controller', function() {
rw: 165, rh: 85,
});
});
it('should NOT inject the resizer element', function() {
var chart = acquireChart({
options: {
responsive: false
}
});
var wrapper = chart.chart.canvas.parentNode;
expect(wrapper.childNodes.length).toBe(1);
expect(wrapper.firstChild.tagName).toBe('CANVAS');
});
});
describe('config.options.responsive: true (maintainAspectRatio: false)', function() {
@ -449,7 +461,6 @@ describe('Chart.Controller', function() {
describe('controller.destroy', function() {
it('should restore canvas (and context) initial values', function(done) {
var chart = acquireChart({
type: 'line',
options: {
responsive: true,
maintainAspectRatio: false
@ -484,5 +495,24 @@ describe('Chart.Controller', function() {
done();
});
});
it('should remove the resizer element when responsive: true', function() {
var chart = acquireChart({
options: {
responsive: true
}
});
var wrapper = chart.chart.canvas.parentNode;
var resizer = wrapper.firstChild;
expect(wrapper.childNodes.length).toBe(2);
expect(resizer.tagName).toBe('IFRAME');
chart.destroy();
expect(wrapper.childNodes.length).toBe(1);
expect(wrapper.firstChild.tagName).toBe('CANVAS');
});
});
});

View File

@ -253,23 +253,23 @@
window.document.body.appendChild(wrapper);
chart = new Chart(canvas.getContext("2d"), config);
chart.__test_persistent = options.persistent;
chart._test_persistent = options.persistent;
chart._test_wrapper = wrapper;
charts[chart.id] = chart;
return chart;
}
function releaseChart(chart) {
chart.destroy();
chart.chart.canvas.parentNode.remove();
chart._test_wrapper.remove();
delete charts[chart.id];
delete chart;
}
afterEach(function() {
// Auto releasing acquired charts
for (var id in charts) {
var chart = charts[id];
if (!chart.__test_persistent) {
if (!chart._test_persistent) {
releaseChart(chart);
}
}