From 5aaff3a1aa38ad8f807d676d26dbac933c8f2d6e Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Tue, 21 Jan 2020 06:36:53 -0500 Subject: [PATCH] Convert Tooltip to a plugin (#6990) * Convert Tooltip to a plugin * code review feedback * Update docs. Convert positioners map to be on the plugin directly --- docs/configuration/tooltip.md | 9 ++-- docs/getting-started/v3-migration.md | 1 + src/core/core.controller.js | 39 +------------- src/core/core.plugins.js | 7 +++ src/index.js | 2 - src/plugins/index.js | 4 +- .../plugin.tooltip.js} | 54 +++++++++++++++++-- test/specs/global.namespace.tests.js | 2 - ...oltip.tests.js => plugin.tooltip.tests.js} | 13 +++-- 9 files changed, 75 insertions(+), 56 deletions(-) rename src/{core/core.tooltip.js => plugins/plugin.tooltip.js} (96%) rename test/specs/{core.tooltip.tests.js => plugin.tooltip.tests.js} (98%) diff --git a/docs/configuration/tooltip.md b/docs/configuration/tooltip.md index d57568b7f..3d59d4690 100644 --- a/docs/configuration/tooltip.md +++ b/docs/configuration/tooltip.md @@ -61,13 +61,14 @@ Example: ```javascript /** * Custom positioner - * @function Chart.Tooltip.positioners.custom + * @function Tooltip.positioners.custom * @param elements {Chart.Element[]} the tooltip elements * @param eventPosition {Point} the position of the event in canvas coordinates * @returns {Point} the tooltip position */ -Chart.Tooltip.positioners.custom = function(elements, eventPosition) { - /** @type {Chart.Tooltip} */ +const tooltipPlugin = Chart.plugins.getAll().find(p => p.id === 'tooltip'); +tooltipPlugin.positioners.custom = function(elements, eventPosition) { + /** @type {Tooltip} */ var tooltip = this; /* ... */ @@ -99,7 +100,7 @@ Allows filtering of [tooltip items](#tooltip-item-interface). Must implement at ## Tooltip Callbacks -The tooltip label configuration is nested below the tooltip configuration using the `callbacks` key. The tooltip has the following callbacks for providing text. For all functions, `this` will be the tooltip object created from the `Chart.Tooltip` constructor. +The tooltip label configuration is nested below the tooltip configuration using the `callbacks` key. The tooltip has the following callbacks for providing text. For all functions, `this` will be the tooltip object created from the `Tooltip` constructor. All functions are called with the same arguments: a [tooltip item](#tooltip-item-interface) and the `data` object passed to the chart. All functions must return either a string or an array of strings. Arrays of strings are treated as multiple lines of text. diff --git a/docs/getting-started/v3-migration.md b/docs/getting-started/v3-migration.md index d11ccb1f7..c1ce80600 100644 --- a/docs/getting-started/v3-migration.md +++ b/docs/getting-started/v3-migration.md @@ -79,6 +79,7 @@ Animation system was completely rewritten in Chart.js v3. Each property can now * `Chart.Controller` * `Chart.prototype.generateLegend` * `Chart.types` +* `Chart.Tooltip` is now provided by the tooltip plugin. The positioners can be accessed from `tooltipPlugin.positioners` * `DatasetController.addElementAndReset` * `DatasetController.createMetaData` * `DatasetController.createMetaDataset` diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 488f81e98..3f1749f2f 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -9,7 +9,6 @@ import layouts from './core.layouts'; import platform from '../platforms/platform'; import plugins from './core.plugins'; import scaleService from '../core/core.scaleService'; -import Tooltip from './core.tooltip'; const valueOrDefault = helpers.valueOrDefault; @@ -117,8 +116,6 @@ function updateConfig(chart) { chart._animationsDisabled = isAnimationDisabled(newOptions); chart.ensureScalesHaveIDs(); chart.buildOrUpdateScales(); - - chart.tooltip.initialize(); } const KNOWN_POSITIONS = new Set(['top', 'bottom', 'left', 'right', 'chartArea']); @@ -218,8 +215,6 @@ class Chart { me.resize(true); } - me.initToolTip(); - // After init plugin notification plugins.notify(me, 'afterInit'); @@ -466,7 +461,7 @@ class Chart { */ reset() { this.resetElements(); - this.tooltip.initialize(); + plugins.notify(this, 'reset'); } update(mode) { @@ -638,8 +633,6 @@ class Chart { layers[i].draw(me.chartArea); } - me._drawTooltip(); - plugins.notify(me, 'afterDraw'); } @@ -723,27 +716,6 @@ class Chart { plugins.notify(me, 'afterDatasetDraw', [args]); } - /** - * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw` - * hook, in which case, plugins will not be called on `afterTooltipDraw`. - * @private - */ - _drawTooltip() { - const me = this; - const tooltip = me.tooltip; - const args = { - tooltip: tooltip - }; - - if (plugins.notify(me, 'beforeTooltipDraw', [args]) === false) { - return; - } - - tooltip.draw(me.ctx); - - plugins.notify(me, 'afterTooltipDraw', [args]); - } - /** * Get the single element that was clicked on * @return An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw @@ -866,10 +838,6 @@ class Chart { return this.canvas.toDataURL.apply(this.canvas, arguments); } - initToolTip() { - this.tooltip = new Tooltip({_chart: this}); - } - /** * @private */ @@ -958,7 +926,6 @@ class Chart { */ eventHandler(e) { const me = this; - const tooltip = me.tooltip; if (plugins.notify(me, 'beforeEvent', [e]) === false) { return; @@ -966,10 +933,6 @@ class Chart { me.handleEvent(e); - if (tooltip) { - tooltip.handleEvent(e); - } - plugins.notify(me, 'afterEvent', [e]); me.render(); diff --git a/src/core/core.plugins.js b/src/core/core.plugins.js index 6772637af..4f7a03d2f 100644 --- a/src/core/core.plugins.js +++ b/src/core/core.plugins.js @@ -200,6 +200,13 @@ export default { * @param {Chart.Controller} chart - The chart instance. * @param {object} options - The plugin options. */ +/** + * @method IPlugin#reset + * @desc Called during chart reset + * @param {Chart.Controller} chart - The chart instance. + * @param {object} options - The plugin options. + * @since version 3.0.0 + */ /** * @method IPlugin#beforeDatasetsUpdate * @desc Called before updating the `chart` datasets. If any plugin returns `false`, diff --git a/src/index.js b/src/index.js index 8e8ef17e1..e472b1528 100644 --- a/src/index.js +++ b/src/index.js @@ -20,7 +20,6 @@ import pluginsCore from './core/core.plugins'; import Scale from './core/core.scale'; import scaleService from './core/core.scaleService'; import Ticks from './core/core.ticks'; -import Tooltip from './core/core.tooltip'; Chart.helpers = helpers; Chart._adapters = _adapters; @@ -39,7 +38,6 @@ Chart.plugins = pluginsCore; Chart.Scale = Scale; Chart.scaleService = scaleService; Chart.Ticks = Ticks; -Chart.Tooltip = Tooltip; // Register built-in scales import scales from './scales'; diff --git a/src/plugins/index.js b/src/plugins/index.js index 1cd2a0363..939df980f 100644 --- a/src/plugins/index.js +++ b/src/plugins/index.js @@ -3,9 +3,11 @@ import filler from './plugin.filler'; import legend from './plugin.legend'; import title from './plugin.title'; +import tooltip from './plugin.tooltip'; export default { filler, legend, - title + title, + tooltip }; diff --git a/src/core/core.tooltip.js b/src/plugins/plugin.tooltip.js similarity index 96% rename from src/core/core.tooltip.js rename to src/plugins/plugin.tooltip.js index 5aff16c63..0c5bc1eed 100644 --- a/src/core/core.tooltip.js +++ b/src/plugins/plugin.tooltip.js @@ -1,9 +1,10 @@ 'use strict'; -import defaults from './core.defaults'; -import Element from './core.element'; +import Animations from '../core/core.animations'; +import defaults from '../core/core.defaults'; +import Element from '../core/core.element'; +import plugins from '../core/core.plugins'; import helpers from '../helpers/index'; -import Animations from './core.animations'; const valueOrDefault = helpers.valueOrDefault; const getRtlHelper = helpers.rtl.getRtlAdapter; @@ -1001,4 +1002,49 @@ class Tooltip extends Element { */ Tooltip.positioners = positioners; -export default Tooltip; +export default { + id: 'tooltip', + _element: Tooltip, + positioners, + + afterInit: function(chart) { + const tooltipOpts = chart.options.tooltips; + + if (tooltipOpts) { + chart.tooltip = new Tooltip({_chart: chart}); + } + }, + + beforeUpdate: function(chart) { + if (chart.tooltip) { + chart.tooltip.initialize(); + } + }, + + reset: function(chart) { + if (chart.tooltip) { + chart.tooltip.initialize(); + } + }, + + afterDraw: function(chart) { + const tooltip = chart.tooltip; + const args = { + tooltip + }; + + if (plugins.notify(chart, 'beforeTooltipDraw', [args]) === false) { + return; + } + + tooltip.draw(chart.ctx); + + plugins.notify(chart, 'afterTooltipDraw', [args]); + }, + + afterEvent: function(chart, e) { + if (chart.tooltip) { + chart.tooltip.handleEvent(e); + } + } +}; diff --git a/test/specs/global.namespace.tests.js b/test/specs/global.namespace.tests.js index 89f8cad5b..8e4ffa5e7 100644 --- a/test/specs/global.namespace.tests.js +++ b/test/specs/global.namespace.tests.js @@ -16,8 +16,6 @@ describe('Chart namespace', function() { expect(Chart.Scale instanceof Object).toBeTruthy(); expect(Chart.scaleService instanceof Object).toBeTruthy(); expect(Chart.Ticks instanceof Object).toBeTruthy(); - expect(Chart.Tooltip instanceof Object).toBeTruthy(); - expect(Chart.Tooltip.positioners instanceof Object).toBeTruthy(); }); }); diff --git a/test/specs/core.tooltip.tests.js b/test/specs/plugin.tooltip.tests.js similarity index 98% rename from test/specs/core.tooltip.tests.js rename to test/specs/plugin.tooltip.tests.js index b1f9cc2b4..b890922e4 100644 --- a/test/specs/core.tooltip.tests.js +++ b/test/specs/plugin.tooltip.tests.js @@ -1,4 +1,7 @@ // Test the rectangle element +const tooltipPlugin = Chart.plugins.getAll().find(p => p.id === 'tooltip'); +const Tooltip = tooltipPlugin._element; + describe('Core.Tooltip', function() { describe('auto', jasmine.fixture.specs('core.tooltip')); @@ -890,11 +893,11 @@ describe('Core.Tooltip', function() { describe('positioners', function() { it('Should call custom positioner with correct parameters and scope', function(done) { - Chart.Tooltip.positioners.test = function() { + tooltipPlugin.positioners.test = function() { return {x: 0, y: 0}; }; - spyOn(Chart.Tooltip.positioners, 'test').and.callThrough(); + spyOn(tooltipPlugin.positioners, 'test').and.callThrough(); var chart = window.acquireChart({ type: 'line', @@ -925,14 +928,14 @@ describe('Core.Tooltip', function() { var datasetIndex = 0; var meta = chart.getDatasetMeta(datasetIndex); var point = meta.data[pointIndex]; - var fn = Chart.Tooltip.positioners.test; + var fn = tooltipPlugin.positioners.test; afterEvent(chart, 'mousemove', function() { expect(fn.calls.count()).toBe(1); expect(fn.calls.first().args[0] instanceof Array).toBe(true); expect(Object.prototype.hasOwnProperty.call(fn.calls.first().args[1], 'x')).toBe(true); expect(Object.prototype.hasOwnProperty.call(fn.calls.first().args[1], 'y')).toBe(true); - expect(fn.calls.first().object instanceof Chart.Tooltip).toBe(true); + expect(fn.calls.first().object instanceof Tooltip).toBe(true); done(); }); @@ -1261,7 +1264,7 @@ describe('Core.Tooltip', function() { ]; var mockContext = window.createMockContext(); - var tooltip = new Chart.Tooltip({ + var tooltip = new Tooltip({ _chart: { options: { tooltips: { -- 2.47.2