From: Evert Timberg Date: Sun, 24 May 2020 14:28:41 +0000 (-0400) Subject: Legend onClick callback supports arrow functions (#7410) X-Git-Tag: v3.0.0-beta.2~131 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=13b8924ac39add7d56842e611c8417afc8aa4a69;p=thirdparty%2FChart.js.git Legend onClick callback supports arrow functions (#7410) #7409 Legend callbacks support arrow functions The `Legend` is no longer implicitly found through `this` and instead passed as an explicit argument to the callback functions. --- diff --git a/docs/docs/configuration/legend.md b/docs/docs/configuration/legend.md index 2d7f0a658..a0b9523c5 100644 --- a/docs/docs/configuration/legend.md +++ b/docs/docs/configuration/legend.md @@ -14,9 +14,9 @@ The legend configuration is passed into the `options.legend` namespace. The glob | `position` | `string` | `'top'` | Position of the legend. [more...](#position) | `align` | `string` | `'center'` | Alignment of the legend. [more...](#align) | `fullWidth` | `boolean` | `true` | Marks that this box should take the full width of the canvas (pushing down other boxes). This is unlikely to need to be changed in day-to-day use. -| `onClick` | `function` | | A callback that is called when a click event is registered on a label item. -| `onHover` | `function` | | A callback that is called when a 'mousemove' event is registered on top of a label item. -| `onLeave` | `function` | | A callback that is called when a 'mousemove' event is registered outside of a previously hovered label item. +| `onClick` | `function` | | A callback that is called when a click event is registered on a label item. Arguments: `[event, legendItem, legend]`. +| `onHover` | `function` | | A callback that is called when a 'mousemove' event is registered on top of a label item. Arguments: `[event, legendItem, legend]`. +| `onLeave` | `function` | | A callback that is called when a 'mousemove' event is registered outside of a previously hovered label item. Arguments: `[event, legendItem, legend]`. | `reverse` | `boolean` | `false` | Legend will show datasets in reverse order. | `labels` | `object` | | See the [Legend Label Configuration](#legend-label-configuration) section below. | `rtl` | `boolean` | | `true` for rendering the legends from right to left. @@ -134,16 +134,16 @@ It can be common to want to trigger different behaviour when clicking an item in The default legend click handler is: ```javascript -function(e, legendItem) { - var index = legendItem.datasetIndex; - var ci = this.chart; - var meta = ci.getDatasetMeta(index); - - // See controller.isDatasetVisible comment - meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null; - - // We hid a dataset ... rerender the chart - ci.update(); +function(e, legendItem, legend) { + const index = legendItem.datasetIndex; + const ci = legend.chart; + if (ci.isDatasetVisible(index)) { + ci.hide(index); + legendItem.hidden = true; + } else { + ci.show(index); + legendItem.hidden = false; + } } ``` @@ -151,14 +151,14 @@ Lets say we wanted instead to link the display of the first two datasets. We cou ```javascript var defaultLegendClickHandler = Chart.defaults.legend.onClick; -var newLegendClickHandler = function (e, legendItem) { +var newLegendClickHandler = function (e, legendItem, legend) { var index = legendItem.datasetIndex; if (index > 1) { // Do the original logic defaultLegendClickHandler(e, legendItem); } else { - let ci = this.chart; + let ci = legend.chart; [ ci.getDatasetMeta(0), ci.getDatasetMeta(1) diff --git a/docs/docs/general/interactions/events.md b/docs/docs/general/interactions/events.md index a59c20726..b7a6cb167 100644 --- a/docs/docs/general/interactions/events.md +++ b/docs/docs/general/interactions/events.md @@ -7,8 +7,8 @@ The following properties define how the chart interacts with events. | Name | Type | Default | Description | ---- | ---- | ------- | ----------- | `events` | `string[]` | `['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove']` | The `events` option defines the browser events that the chart should listen to for tooltips and hovering. [more...](#event-option) -| `onHover` | `function` | `null` | Called when any of the events fire. Called in the context of the chart and passed the event and an array of active elements (bars, points, etc). -| `onClick` | `function` | `null` | Called if the event is of type `'mouseup'` or `'click'`. Called in the context of the chart and passed the event and an array of active elements. +| `onHover` | `function` | `null` | Called when any of the events fire. Passed the event, an array of active elements (bars, points, etc), and the chart. +| `onClick` | `function` | `null` | Called if the event is of type `'mouseup'` or `'click'`. Passed the event, an array of active elements, and the chart. ## Event Option For example, to have the chart only respond to click events, you could do: diff --git a/docs/docs/getting-started/v3-migration.md b/docs/docs/getting-started/v3-migration.md index fd70ab59c..a1de622e1 100644 --- a/docs/docs/getting-started/v3-migration.md +++ b/docs/docs/getting-started/v3-migration.md @@ -157,6 +157,7 @@ Animation system was completely rewritten in Chart.js v3. Each property can now * `{mode: 'single'}` was replaced with `{mode: 'nearest', intersect: true}` * `modes['X-axis']` was replaced with `{mode: 'index', intersect: false}` * `options.onClick` is now limited to the chart area +* `options.onClick` and `options.onHover` now receive the `chart` instance as a 3rd argument #### Ticks @@ -279,6 +280,8 @@ The following properties and methods were removed: * `IPlugin.afterScaleUpdate`. Use `afterLayout` instead * `Legend.margins` is now private +* Legend `onClick`, `onHover`, and `onLeave` options now receive the legend as the 3rd argument in addition to implicitly via `this` +* Legend `onClick`, `onHover`, and `onLeave` options now receive a wrapped `event` as the first parameter. The previous first parameter value is accessible via `event.native`. * `Title.margins` is now private * The tooltip item's `x` and `y` attributes were removed. Use `datasetIndex` and `index` to get the element and any corresponding data from it diff --git a/samples/charts/multi-series-pie.html b/samples/charts/multi-series-pie.html index 4a61c420b..546676094 100644 --- a/samples/charts/multi-series-pie.html +++ b/samples/charts/multi-series-pie.html @@ -71,12 +71,12 @@ return labels; } }, - onClick: function(mouseEvent, legendItem) { + onClick: function(mouseEvent, legendItem, legend) { // toggle the visibility of the dataset from what it currently is - this.chart.getDatasetMeta( + legend.chart.getDatasetMeta( legendItem.datasetIndex - ).hidden = this.chart.isDatasetVisible(legendItem.datasetIndex); - this.chart.update(); + ).hidden = legend.chart.isDatasetVisible(legendItem.datasetIndex); + legend.chart.update(); } }, tooltips: { diff --git a/samples/charts/pie.html b/samples/charts/pie.html index b994c338a..7dbc148e3 100644 --- a/samples/charts/pie.html +++ b/samples/charts/pie.html @@ -75,7 +75,7 @@ label: 'New dataset ' + config.data.datasets.length, }; - for (var index = 0; index < config.data.labels.length; ++index) { + for (var index = 0; index < 10; ++index) { newDataset.data.push(randomScalingFactor()); var colorName = colorNames[index % colorNames.length]; diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 361322de9..2d0c5468c 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -47,9 +47,9 @@ defaults.set('doughnut', { } }, - onClick(e, legendItem) { - this.chart.toggleDataVisibility(legendItem.index); - this.chart.update(); + onClick(e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); } }, diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index 3d6331602..c44cec8cb 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -55,9 +55,9 @@ defaults.set('polarArea', { } }, - onClick(e, legendItem) { - this.chart.toggleDataVisibility(legendItem.index); - this.chart.update(); + onClick(e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); } }, diff --git a/src/core/core.controller.js b/src/core/core.controller.js index cdcc1d7af..220fa198f 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -1108,12 +1108,12 @@ export default class Chart { // Invoke onHover hook // Need to call with native event here to not break backwards compatibility - callCallback(options.onHover || options.hover.onHover, [e.native, me.active], me); + callCallback(options.onHover || options.hover.onHover, [e.native, me.active, me], me); if (e.type === 'mouseup' || e.type === 'click') { - if (options.onClick && _isPointInArea(e, me.chartArea)) { + if (_isPointInArea(e, me.chartArea)) { // Use e.native here for backwards compatibility - options.onClick.call(me, e.native, me.active); + callCallback(options.onClick, [e, me.active, me], me); } } diff --git a/src/plugins/plugin.legend.js b/src/plugins/plugin.legend.js index 79f61db6e..0faddddd9 100644 --- a/src/plugins/plugin.legend.js +++ b/src/plugins/plugin.legend.js @@ -19,9 +19,9 @@ defaults.set('legend', { weight: 1000, // a callback that will handle - onClick(e, legendItem) { + onClick(e, legendItem, legend) { const index = legendItem.datasetIndex; - const ci = this.chart; + const ci = legend.chart; if (ci.isDatasetVisible(index)) { ci.hide(index); legendItem.hidden = true; @@ -659,21 +659,19 @@ export class Legend extends Element { const hoveredItem = me._getLegendItemAt(e.x, e.y); if (type === 'click') { - if (hoveredItem && opts.onClick) { - // use e.native for backwards compatibility - opts.onClick.call(me, e.native, hoveredItem); + if (hoveredItem) { + call(opts.onClick, [e, hoveredItem, me], me); } } else { if (opts.onLeave && hoveredItem !== me._hoveredItem) { if (me._hoveredItem) { - opts.onLeave.call(me, e.native, me._hoveredItem); + call(opts.onLeave, [e, me._hoveredItem, me], me); } me._hoveredItem = hoveredItem; } - if (opts.onHover && hoveredItem) { - // use e.native for backwards compatibility - opts.onHover.call(me, e.native, hoveredItem); + if (hoveredItem) { + call(opts.onHover, [e, hoveredItem, me], me); } } } diff --git a/test/specs/global.defaults.tests.js b/test/specs/global.defaults.tests.js index 30652473a..ccbbea180 100644 --- a/test/specs/global.defaults.tests.js +++ b/test/specs/global.defaults.tests.js @@ -147,12 +147,12 @@ describe('Default Configs', function() { spyOn(chart, 'update').and.callThrough(); var legendItem = chart.legend.legendItems[0]; - config.legend.onClick.call(chart.legend, null, legendItem); + config.legend.onClick(null, legendItem, chart.legend); expect(chart.getDataVisibility(0)).toBe(false); expect(chart.update).toHaveBeenCalled(); - config.legend.onClick.call(chart.legend, null, legendItem); + config.legend.onClick(null, legendItem, chart.legend); expect(chart.getDataVisibility(0)).toBe(true); }); }); @@ -243,12 +243,12 @@ describe('Default Configs', function() { spyOn(chart, 'update').and.callThrough(); var legendItem = chart.legend.legendItems[0]; - config.legend.onClick.call(chart.legend, null, legendItem); + config.legend.onClick(null, legendItem, chart.legend); expect(chart.getDataVisibility(0)).toBe(false); expect(chart.update).toHaveBeenCalled(); - config.legend.onClick.call(chart.legend, null, legendItem); + config.legend.onClick(null, legendItem, chart.legend); expect(chart.getDataVisibility(0)).toBe(true); }); });