item = item.canvas;
}
- if (item instanceof HTMLCanvasElement) {
- // To prevent canvas fingerprinting, some add-ons undefine the getContext
- // method, for example: https://github.com/kkapsner/CanvasBlocker
- // https://github.com/chartjs/Chart.js/issues/2807
- var context = item.getContext && item.getContext('2d');
- if (context instanceof CanvasRenderingContext2D) {
- initCanvas(item, config);
- return context;
- }
+ // To prevent canvas fingerprinting, some add-ons undefine the getContext
+ // method, for example: https://github.com/kkapsner/CanvasBlocker
+ // https://github.com/chartjs/Chart.js/issues/2807
+ var context = item && item.getContext && item.getContext('2d');
+
+ // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
+ // inside an iframe or when running in a protected environment. We could guess the
+ // types from their toString() value but let's keep things flexible and assume it's
+ // a sufficient condition if the item has a context2D which has item as `canvas`.
+ // https://github.com/chartjs/Chart.js/issues/3887
+ // https://github.com/chartjs/Chart.js/issues/4102
+ // https://github.com/chartjs/Chart.js/issues/4152
+ if (context && context.canvas === item) {
+ initCanvas(item, config);
+ return context;
}
return null;
if (!(actual instanceof Chart)) {
message = 'Expected ' + actual + ' to be an instance of Chart';
- } else if (!(actual.canvas instanceof HTMLCanvasElement)) {
+ } else if (Object.prototype.toString.call(actual.canvas) !== '[object HTMLCanvasElement]') {
message = 'Expected canvas to be an instance of HTMLCanvasElement';
- } else if (!(actual.ctx instanceof CanvasRenderingContext2D)) {
+ } else if (Object.prototype.toString.call(actual.ctx) !== '[object CanvasRenderingContext2D]') {
message = 'Expected context to be an instance of CanvasRenderingContext2D';
} else if (typeof actual.height !== 'number' || !isFinite(actual.height)) {
message = 'Expected height to be a strict finite number';
chart.destroy();
});
+
+ it('should accept a canvas from an iframe', function(done) {
+ var iframe = document.createElement('iframe');
+ iframe.onload = function() {
+ var doc = iframe.contentDocument;
+ doc.body.innerHTML += '<canvas id="chart"></canvas>';
+ var canvas = doc.getElementById('chart');
+ var chart = new Chart(canvas);
+
+ expect(chart).toBeValidChart();
+ expect(chart.canvas).toBe(canvas);
+ expect(chart.ctx).toBe(canvas.getContext('2d'));
+
+ chart.destroy();
+ canvas.remove();
+ iframe.remove();
+
+ done();
+ };
+
+ document.body.appendChild(iframe);
+ });
});
describe('config.options.aspectRatio', function() {