]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Provide method to lookup a chart from a canvas (#7843)
authorEvert Timberg <evert.timberg+github@gmail.com>
Sun, 4 Oct 2020 15:08:38 +0000 (11:08 -0400)
committerGitHub <noreply@github.com>
Sun, 4 Oct 2020 15:08:38 +0000 (11:08 -0400)
* 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

docs/docs/developers/api.md
docs/docs/getting-started/v3-migration.md
src/core/core.controller.js
test/specs/core.controller.tests.js
types/core/index.d.ts

index d5dcb6e350338876bc6269a31e879674d5eba3c1..2ce6c25d5ef97590470fccb53293f2a8c9bb8acd 100644 (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")
+```
\ No newline at end of file
index d80c078e0007fe24dd3c07b9d67fbb70960f7018..473da19ddfb81730ed4902ef490c75ae614cfddc 100644 (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
index a4f4be60f7e17df257fbccb704942bcd9ad07da4..a43090a091f46e1acb1d8d31ac4cb8aa3a251210 100644 (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());
 
index 12045a787151fd7d864c89051055137b785635ef..ac79cab777802c65dab3a4f95d7ccc6c61f7223f 100644 (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();
+               });
+       });
 });
index dc3139dfa3412c73ff41e3ece2cb72402c362730..1d54f1fc13b88984847e19d951822edfdf0a7535 100644 (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;
 }