mirror of
https://github.com/chartjs/Chart.js.git
synced 2024-10-06 12:19:08 +02:00
Detect attach/detach from any level (#9557)
This commit is contained in:
parent
4bf42f4e8e
commit
fca0309223
@ -123,7 +123,7 @@ class Chart {
|
||||
this.attached = false;
|
||||
this._animationsDisabled = undefined;
|
||||
this.$context = undefined;
|
||||
this._doResize = debounce(() => this.update('resize'), options.resizeDelay || 0);
|
||||
this._doResize = debounce(mode => this.update(mode), options.resizeDelay || 0);
|
||||
|
||||
// Add the chart instance to the global namespace
|
||||
instances[me.id] = me;
|
||||
@ -231,6 +231,7 @@ class Chart {
|
||||
const aspectRatio = options.maintainAspectRatio && me.aspectRatio;
|
||||
const newSize = me.platform.getMaximumSize(canvas, width, height, aspectRatio);
|
||||
const newRatio = options.devicePixelRatio || me.platform.getDevicePixelRatio();
|
||||
const mode = me.width ? 'resize' : 'attach';
|
||||
|
||||
me.width = newSize.width;
|
||||
me.height = newSize.height;
|
||||
@ -244,7 +245,7 @@ class Chart {
|
||||
callCallback(options.onResize, [me, newSize], me);
|
||||
|
||||
if (me.attached) {
|
||||
if (me._doResize()) {
|
||||
if (me._doResize(mode)) {
|
||||
// The resize update is delayed, only draw without updating.
|
||||
me.render();
|
||||
}
|
||||
@ -831,19 +832,22 @@ class Chart {
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
_stop() {
|
||||
const me = this;
|
||||
const {canvas, ctx} = me;
|
||||
let i, ilen;
|
||||
|
||||
me.stop();
|
||||
animator.remove(me);
|
||||
|
||||
// dataset controllers need to cleanup associated data
|
||||
for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
|
||||
me._destroyDatasetMeta(i);
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
const me = this;
|
||||
const {canvas, ctx} = me;
|
||||
|
||||
me._stop();
|
||||
me.config.clearCache();
|
||||
|
||||
if (canvas) {
|
||||
@ -940,6 +944,11 @@ class Chart {
|
||||
me.attached = false;
|
||||
|
||||
_remove('resize', listener);
|
||||
|
||||
// Stop animating and remove metasets, so when re-attached, the animations start from begining.
|
||||
me._stop();
|
||||
me._resize(0, 0);
|
||||
|
||||
_add('attach', attached);
|
||||
};
|
||||
|
||||
|
@ -42,24 +42,23 @@ export function throttled(fn, thisArg, updateFn) {
|
||||
|
||||
/**
|
||||
* Debounces calling `fn` for `delay` ms
|
||||
* @param {function} fn - Function to call. No arguments are passed.
|
||||
* @param {function} fn - Function to call.
|
||||
* @param {number} delay - Delay in ms. 0 = immediate invocation.
|
||||
* @returns {function}
|
||||
*/
|
||||
export function debounce(fn, delay) {
|
||||
let timeout;
|
||||
return function() {
|
||||
return function(...args) {
|
||||
if (delay) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(fn, delay);
|
||||
timeout = setTimeout(fn, delay, args);
|
||||
} else {
|
||||
fn();
|
||||
fn.apply(this, args);
|
||||
}
|
||||
return delay;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts 'start' to 'left', 'end' to 'right' and others to 'center'
|
||||
* @param {string} align start, end, center
|
||||
|
@ -116,18 +116,14 @@ function fromNativeEvent(event, chart) {
|
||||
|
||||
function createAttachObserver(chart, type, listener) {
|
||||
const canvas = chart.canvas;
|
||||
const container = canvas && _getParentNode(canvas);
|
||||
const element = container || canvas;
|
||||
const observer = new MutationObserver(entries => {
|
||||
const parent = _getParentNode(element);
|
||||
entries.forEach(entry => {
|
||||
for (let i = 0; i < entry.addedNodes.length; i++) {
|
||||
const added = entry.addedNodes[i];
|
||||
if (added === element || added === parent) {
|
||||
listener(entry.target);
|
||||
for (const entry of entries) {
|
||||
for (const node of entry.addedNodes) {
|
||||
if (node === canvas || node.contains(canvas)) {
|
||||
return listener();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
observer.observe(document, {childList: true, subtree: true});
|
||||
return observer;
|
||||
@ -135,21 +131,16 @@ function createAttachObserver(chart, type, listener) {
|
||||
|
||||
function createDetachObserver(chart, type, listener) {
|
||||
const canvas = chart.canvas;
|
||||
const container = canvas && _getParentNode(canvas);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
const observer = new MutationObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
for (let i = 0; i < entry.removedNodes.length; i++) {
|
||||
if (entry.removedNodes[i] === canvas) {
|
||||
listener();
|
||||
break;
|
||||
for (const entry of entries) {
|
||||
for (const node of entry.removedNodes) {
|
||||
if (node === canvas || node.contains(canvas)) {
|
||||
return listener();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
observer.observe(container, {childList: true});
|
||||
observer.observe(document, {childList: true, subtree: true});
|
||||
return observer;
|
||||
}
|
||||
|
||||
|
@ -1029,8 +1029,10 @@ describe('Chart', function() {
|
||||
});
|
||||
|
||||
parent.removeChild(wrapper);
|
||||
parent.appendChild(wrapper);
|
||||
wrapper.style.height = '355px';
|
||||
setTimeout(() => {
|
||||
parent.appendChild(wrapper);
|
||||
wrapper.style.height = '355px';
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// https://github.com/chartjs/Chart.js/issues/4737
|
||||
@ -1075,6 +1077,47 @@ describe('Chart', function() {
|
||||
canvas.parentNode.style.width = '455px';
|
||||
});
|
||||
});
|
||||
|
||||
it('should resize the canvas if attached to the DOM after construction with mutiple parents', function(done) {
|
||||
var canvas = document.createElement('canvas');
|
||||
var wrapper = document.createElement('div');
|
||||
var wrapper2 = document.createElement('div');
|
||||
var wrapper3 = document.createElement('div');
|
||||
var body = window.document.body;
|
||||
|
||||
var chart = new Chart(canvas, {
|
||||
type: 'line',
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false
|
||||
}
|
||||
});
|
||||
|
||||
expect(chart).toBeChartOfSize({
|
||||
dw: 0, dh: 0,
|
||||
rw: 0, rh: 0,
|
||||
});
|
||||
expect(chart.chartArea).toBeUndefined();
|
||||
|
||||
waitForResize(chart, function() {
|
||||
expect(chart).toBeChartOfSize({
|
||||
dw: 455, dh: 355,
|
||||
rw: 455, rh: 355,
|
||||
});
|
||||
|
||||
expect(chart.chartArea).not.toBeUndefined();
|
||||
|
||||
body.removeChild(wrapper3);
|
||||
chart.destroy();
|
||||
done();
|
||||
});
|
||||
|
||||
wrapper3.appendChild(wrapper2);
|
||||
wrapper2.appendChild(wrapper);
|
||||
wrapper.style.cssText = 'width: 455px; height: 355px';
|
||||
wrapper.appendChild(canvas);
|
||||
body.appendChild(wrapper3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('config.options.responsive: true (maintainAspectRatio: true)', function() {
|
||||
|
Loading…
Reference in New Issue
Block a user