| 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)
+| `events` | `string[]` | `['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove']` | The `events` option defines the browser events that the chart should listen to for. Each of these events trigger hover and are passed to plugins. [more...](#event-option)
| `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.
```javascript
var chart = new Chart(ctx, {
- type: 'line',
- data: data,
- options: {
- // This chart will not respond to mousemove, etc
+ type: 'line',
+ data: data,
+ options: {
+ // This chart will not respond to mousemove, etc
+ events: ['click']
+ }
+});
+```
+
+Events for each plugin can be further limited by defining (allowed) events array in plugin options:
+
+```javascript
+var chart = new Chart(ctx, {
+ type: 'line',
+ data: data,
+ options: {
+ // All of these (default) events trigger a hover and are passed to all plugins,
+ // unless limited at plugin options
+ events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
+ plugins: {
+ tooltip: {
+ // Tooltip will only receive click events
events: ['click']
+ }
}
+ }
});
```
* returned value can be used, for instance, to interrupt the current action.
* @param {string} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
* @param {Object} [args] - Extra arguments to apply to the hook call.
+ * @param {import('./core.plugins').filterCallback} [filter] - Filtering function for limiting which plugins are notified
* @returns {boolean} false if any of the plugins return false, else returns true.
*/
- notifyPlugins(hook, args) {
- return this._plugins.notify(this, hook, args);
+ notifyPlugins(hook, args, filter) {
+ return this._plugins.notify(this, hook, args, filter);
}
/**
_eventHandler(e, replay) {
const me = this;
const args = {event: e, replay, cancelable: true};
+ const eventFilter = (plugin) => (plugin.options.events || this.options.events).includes(e.type);
- if (me.notifyPlugins('beforeEvent', args) === false) {
+ if (me.notifyPlugins('beforeEvent', args, eventFilter) === false) {
return;
}
const changed = me._handleEvent(e, replay);
args.cancelable = false;
- me.notifyPlugins('afterEvent', args);
+ me.notifyPlugins('afterEvent', args, eventFilter);
if (changed || args.changed) {
me.render();
* @typedef { import("../plugins/plugin.tooltip").default } Tooltip
*/
+/**
+ * @callback filterCallback
+ * @param {{plugin: object, options: object}} value
+ * @param {number} [index]
+ * @param {array} [array]
+ * @param {object} [thisArg]
+ * @return {boolean}
+ */
+
+
export default class PluginService {
constructor() {
this._init = [];
* @param {Chart} chart - The chart instance for which plugins should be called.
* @param {string} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
* @param {object} [args] - Extra arguments to apply to the hook call.
+ * @param {filterCallback} [filter] - Filtering function for limiting which plugins are notified
* @returns {boolean} false if any of the plugins return false, else returns true.
*/
- notify(chart, hook, args) {
+ notify(chart, hook, args, filter) {
const me = this;
if (hook === 'beforeInit') {
me._notify(me._init, chart, 'install');
}
- const descriptors = me._descriptors(chart);
+ const descriptors = filter ? me._descriptors(chart).filter(filter) : me._descriptors(chart);
const result = me._notify(descriptors, chart, hook, args);
if (hook === 'destroy') {
plugins: [plugin]
});
});
+
+ it('should filter event callbacks by plugin events array', async function() {
+ const results = [];
+ const chart = window.acquireChart({
+ options: {
+ events: ['mousemove', 'test', 'test2'],
+ plugins: {
+ testPlugin: {
+ events: ['test']
+ }
+ }
+ },
+ plugins: [{
+ id: 'testPlugin',
+ beforeEvent: function(_chart, args) {
+ results.push('before' + args.event.type);
+ },
+ afterEvent: function(_chart, args) {
+ results.push('after' + args.event.type);
+ }
+ }]
+ });
+ await jasmine.triggerMouseEvent(chart, 'mousemove', {x: 0, y: 0});
+ await jasmine.triggerMouseEvent(chart, 'test', {x: 0, y: 0});
+ await jasmine.triggerMouseEvent(chart, 'test2', {x: 0, y: 0});
+ expect(results).toEqual(['beforetest', 'aftertest']);
+ });
});
});
});
});
- describe('active events', function() {
- it('should set the active events', function() {
+ describe('active elements', function() {
+ it('should set the active elements', function() {
var chart = window.acquireChart({
type: 'line',
data: {
expect(chart.tooltip.getActiveElements()[0].element).toBe(meta.data[0]);
});
});
+
+ describe('events', function() {
+ it('should not be called on events not in plugin events array', async function() {
+ var chart = window.acquireChart({
+ type: 'line',
+ data: {
+ datasets: [{
+ label: 'Dataset 1',
+ data: [10, 20, 30],
+ pointHoverBorderColor: 'rgb(255, 0, 0)',
+ pointHoverBackgroundColor: 'rgb(0, 255, 0)'
+ }],
+ labels: ['Point 1', 'Point 2', 'Point 3']
+ },
+ options: {
+ plugins: {
+ tooltip: {
+ events: ['click']
+ }
+ }
+ }
+ });
+
+ const meta = chart.getDatasetMeta(0);
+ const point = meta.data[1];
+
+ await jasmine.triggerMouseEvent(chart, 'mousemove', point);
+ expect(chart.tooltip.opacity).toEqual(0);
+ await jasmine.triggerMouseEvent(chart, 'click', point);
+ expect(chart.tooltip.opacity).toEqual(1);
+ });
+ });
});