From: Evert Timberg Date: Sun, 4 Oct 2020 15:08:38 +0000 (-0400) Subject: Provide method to lookup a chart from a canvas (#7843) X-Git-Tag: v3.0.0-beta.4~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8438da9e8426f8b707b1b0dbb87d43ae32ffc7d1;p=thirdparty%2FChart.js.git 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 --- diff --git a/docs/docs/developers/api.md b/docs/docs/developers/api.md index d5dcb6e35..2ce6c25d5 100644 --- a/docs/docs/developers/api.md +++ b/docs/docs/developers/api.md @@ -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 diff --git a/docs/docs/getting-started/v3-migration.md b/docs/docs/getting-started/v3-migration.md index d80c078e0..473da19dd 100644 --- a/docs/docs/getting-started/v3-migration.md +++ b/docs/docs/getting-started/v3-migration.md @@ -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 diff --git a/src/core/core.controller.js b/src/core/core.controller.js index a4f4be60f..a43090a09 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -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()); diff --git a/test/specs/core.controller.tests.js b/test/specs/core.controller.tests.js index 12045a787..ac79cab77 100644 --- a/test/specs/core.controller.tests.js +++ b/test/specs/core.controller.tests.js @@ -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(); + }); + }); }); diff --git a/types/core/index.d.ts b/types/core/index.d.ts index dc3139dfa..1d54f1fc1 100644 --- a/types/core/index.d.ts +++ b/types/core/index.d.ts @@ -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; }