Provide method to lookup a chart from a canvas (#7843)

* Provide method to lookup a chart from a canvas
* Throw an error during construction if a canvas is in use
* Migration docs for new constructor behaviour
This commit is contained in:
Evert Timberg 2020-10-04 11:08:38 -04:00 committed by GitHub
parent df0b79b9cc
commit 8438da9e84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 94 additions and 0 deletions

View File

@ -204,3 +204,11 @@ Sets the visibility for the given dataset to true. Updates the chart and animate
```javascript
chart.show(1); // shows dataset at index 1 and does 'show' animation.
```
## Static: getChart(key)
Finds the chart instance from the given key. If the key is a `string`, it is interpreted as the ID of the Canvas node for the Chart. The key can also be a `CanvasRenderingContext2D` or an `HTMLDOMElement`. This will return `undefined` if no Chart is found. To be found, the chart must have previously been created.
```javascript
const chart = Chart.getChart("canvas-id")
```

View File

@ -21,6 +21,7 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released
* Distributed files are now in lower case. For example: `dist/chart.js`.
* Chart.js is no longer providing the `Chart.bundle.js` and `Chart.bundle.min.js`. Please see the [installation](installation.md) and [integration](integration.md) docs for details on the recommended way to setup Chart.js if you were using these builds.
* `moment` is no longer specified as an npm dependency. If you are using the `time` or `timeseries` scales, you must include one of [the available adapters](https://github.com/chartjs/awesome#adapters) and corresponding date library. You no longer need to exclude moment from your build.
* The `Chart` constructor will throw an error if the canvas/context provided is already in use
* Chart.js 3 is tree-shakeable. So if you are using it as an `npm` module in a project, you need to import and register the controllers, elements, scales and plugins you want to use. You will not have to call `register` if importing Chart.js via a `script` tag, but will not get the tree shaking benefits in this case. Here is an example of registering components:
```javascript

View File

@ -222,6 +222,14 @@ class Chart {
config = initConfig(config);
const initialCanvas = getCanvas(item);
const existingChart = Chart.getChart(initialCanvas);
if (existingChart) {
throw new Error(
'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' +
' must be destroyed before the canvas can be reused.'
);
}
this.platform = me._initializePlatform(initialCanvas, config);
const context = me.platform.acquireContext(initialCanvas, config);
@ -1155,6 +1163,11 @@ Chart.instances = {};
Chart.registry = registry;
Chart.version = version;
Chart.getChart = (key) => {
const canvas = getCanvas(key);
return Object.values(Chart.instances).filter((c) => c.canvas === canvas).pop();
};
// @ts-ignore
const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate());

View File

@ -10,6 +10,33 @@ describe('Chart', function() {
expect(chart instanceof Chart).toBeTruthy();
});
it('should throw an error if the canvas is already in use', function() {
var config = {
type: 'line',
data: {
datasets: [{
data: [1, 2, 3, 4]
}],
labels: ['A', 'B', 'C', 'D']
}
};
var chart = acquireChart(config);
var canvas = chart.canvas;
function createChart() {
return new Chart(canvas, config);
}
expect(createChart).toThrow(new Error(
'Canvas is already in use. ' +
'Chart with ID \'' + chart.id + '\'' +
' must be destroyed before the canvas can be reused.'
));
chart.destroy();
expect(createChart).not.toThrow();
});
describe('config initialization', function() {
it('should create missing config.data properties', function() {
var chart = acquireChart({});
@ -1440,4 +1467,48 @@ describe('Chart', function() {
expect(chart.getDataVisibility(1)).toBe(false);
});
});
describe('getChart', function() {
it('should get the chart from the canvas ID', function() {
var chart = acquireChart({
type: 'pie',
data: {
datasets: [{
data: [1, 2, 3]
}]
}
});
chart.canvas.id = 'myID';
expect(Chart.getChart('myID')).toBe(chart);
});
it('should get the chart from an HTMLCanvasElement', function() {
var chart = acquireChart({
type: 'pie',
data: {
datasets: [{
data: [1, 2, 3]
}]
}
});
expect(Chart.getChart(chart.canvas)).toBe(chart);
});
it('should get the chart from an CanvasRenderingContext2D', function() {
var chart = acquireChart({
type: 'pie',
data: {
datasets: [{
data: [1, 2, 3]
}]
}
});
expect(Chart.getChart(chart.ctx)).toBe(chart);
});
it('should return undefined when a chart is not found or bad data is provided', function() {
expect(Chart.getChart(1)).toBeUndefined();
});
});
});

View File

@ -302,6 +302,7 @@ export declare class Chart<
static readonly version: string;
static readonly instances: { [key: string]: Chart };
static readonly registry: Registry;
static getChart(key: string | CanvasRenderingContext2D | HTMLCanvasElement) : Chart | undefined;
static register(...items: IChartComponentLike[]): void;
static unregister(...items: IChartComponentLike[]): void;
}