Skip to content

Commit 03a7d71

Browse files
authored
Pass the chart event instance to listeners (#271)
1 parent 91c37f5 commit 03a7d71

8 files changed

Lines changed: 38 additions & 23 deletions

File tree

.codeclimate.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
version: "2"
22
checks:
3+
argument-count:
4+
enabled: true
5+
config:
6+
threshold: 5
37
complex-logic:
48
enabled: false
59
method-complexity:

docs/guide/events.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ This plugin currently supports the following label events:
1414

1515
## Listeners
1616

17-
The `listeners` option allows to register callbacks to be notified when an event is detected on a specific label. This option is an object where each property represents an event, the key being the type of the event to listen and the value being a callback accepting a unique `context` argument.
17+
The `listeners` option allows to register callbacks to be notified when an event is detected on a specific label. This option is an object where each property represents an event, the key being the type of the event to listen and the value being a callback accepting the `context` and `event` arguments.
1818

1919
The `context` contains the same information as for [scriptable options](options.md#option-context), can be modified (e.g. add new properties) and thus, **if the callback explicitly returns `true`**, the label is updated with the new context and the chart re-rendered. This allows to implement visual interactions with labels such as highlight, selection, etc.
2020

@@ -32,10 +32,15 @@ If no listener is registered, incoming events are immediately ignored, preventin
3232
datasets: [{
3333
datalabels: {
3434
listeners: {
35-
click: function(context) {
35+
click: function(context, event) {
3636
// Receives `click` events only for labels of the first dataset.
3737
// The clicked label index is available in `context.dataIndex`.
3838
console.log('label ' + context.dataIndex + ' has been clicked!');
39+
console.log('mouse is at position x:', event.x, 'and y:', event.y);
40+
41+
if (event.native.ctrlKey) {
42+
console.log('control key is pressed!');
43+
}
3944
}
4045
}
4146
}
@@ -47,15 +52,15 @@ If no listener is registered, incoming events are immediately ignored, preventin
4752
plugins: {
4853
datalabels: {
4954
listeners: {
50-
enter: function(context) {
55+
enter: function(context, event) {
5156
// Receives `enter` events for any labels of any dataset. Indices of the
5257
// clicked label are: `context.datasetIndex` and `context.dataIndex`.
5358
// For example, we can modify keep track of the hovered state and
5459
// return `true` to update the label and re-render the chart.
5560
context.hovered = true;
5661
return true;
5762
},
58-
leave: function(context) {
63+
leave: function(context, event) {
5964
// Receives `leave` events for any labels of any dataset.
6065
context.hovered = false;
6166
return true;

src/plugin.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ function configure(dataset, options) {
6262
};
6363
}
6464

65-
function dispatchEvent(chart, listeners, label) {
65+
function dispatchEvent(chart, listeners, label, event) {
6666
if (!listeners) {
6767
return;
6868
}
@@ -80,7 +80,7 @@ function dispatchEvent(chart, listeners, label) {
8080
return;
8181
}
8282

83-
if (callbackHelper(callback, [context]) === true) {
83+
if (callbackHelper(callback, [context, event]) === true) {
8484
// Users are allowed to tweak the given context by injecting values that can be
8585
// used in scriptable options to display labels differently based on the current
8686
// event (e.g. highlight an hovered label). That's why we update the label with
@@ -90,7 +90,7 @@ function dispatchEvent(chart, listeners, label) {
9090
}
9191
}
9292

93-
function dispatchMoveEvents(chart, listeners, previous, label) {
93+
function dispatchMoveEvents(chart, listeners, previous, label, event) {
9494
var enter, leave;
9595

9696
if (!previous && !label) {
@@ -106,10 +106,10 @@ function dispatchMoveEvents(chart, listeners, previous, label) {
106106
}
107107

108108
if (leave) {
109-
dispatchEvent(chart, listeners.leave, previous);
109+
dispatchEvent(chart, listeners.leave, previous, event);
110110
}
111111
if (enter) {
112-
dispatchEvent(chart, listeners.enter, label);
112+
dispatchEvent(chart, listeners.enter, label, event);
113113
}
114114
}
115115

@@ -130,15 +130,15 @@ function handleMoveEvents(chart, event) {
130130

131131
previous = expando._hovered;
132132
expando._hovered = label;
133-
dispatchMoveEvents(chart, listeners, previous, label);
133+
dispatchMoveEvents(chart, listeners, previous, label, event);
134134
}
135135

136136
function handleClickEvents(chart, event) {
137137
var expando = chart[EXPANDO_KEY];
138138
var handlers = expando._listeners.click;
139139
var label = handlers && layout.lookup(expando._labels, event);
140140
if (label) {
141-
dispatchEvent(chart, handlers, label);
141+
dispatchEvent(chart, handlers, label, event);
142142
}
143143
}
144144

test/specs/events.spec.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,10 @@ describe('events', function() {
8080
expect(spy.calls.count()).toBe(2);
8181
expect(spy.calls.argsFor(0)[0].dataIndex).toBe(1);
8282
expect(spy.calls.argsFor(0)[0].datasetIndex).toBe(0);
83+
expect(spy.calls.argsFor(0)[1].native.type).toBe('mousemove');
8384
expect(spy.calls.argsFor(1)[0].dataIndex).toBe(2);
8485
expect(spy.calls.argsFor(1)[0].datasetIndex).toBe(0);
86+
expect(spy.calls.argsFor(1)[1].native.type).toBe('mousemove');
8587
});
8688
});
8789

@@ -115,6 +117,7 @@ describe('events', function() {
115117
expect(spy.calls.count()).toBe(1);
116118
expect(spy.calls.argsFor(0)[0].dataIndex).toBe(1);
117119
expect(spy.calls.argsFor(0)[0].datasetIndex).toBe(0);
120+
expect(spy.calls.argsFor(0)[1].native.type).toBe('mousemove');
118121
});
119122

120123
it('should be called when the mouse moves out the canvas', async function() {
@@ -146,6 +149,7 @@ describe('events', function() {
146149
expect(spy.calls.count()).toBe(1);
147150
expect(spy.calls.argsFor(0)[0].dataIndex).toBe(1);
148151
expect(spy.calls.argsFor(0)[0].datasetIndex).toBe(0);
152+
expect(spy.calls.argsFor(0)[1].native.type).toBe('mouseout');
149153
});
150154
});
151155

@@ -175,6 +179,7 @@ describe('events', function() {
175179
expect(spy.calls.count()).toBe(1);
176180
expect(spy.calls.argsFor(0)[0].dataIndex).toBe(1);
177181
expect(spy.calls.argsFor(0)[0].datasetIndex).toBe(0);
182+
expect(spy.calls.argsFor(0)[1].native.type).toBe('click');
178183
});
179184
});
180185

types/options.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import {ChartEvent} from 'chart.js';
12
import {Context} from './context';
23

34
type Align = 'bottom' | 'center' | 'end' | 'left' | 'right' | 'start' | 'top' | number;
45
type Anchor = 'center' | 'end' | 'start';
56
type Color = string | CanvasGradient | CanvasPattern;
6-
type Listener = (context: Context) => boolean | void;
7+
type Listener = (context: Context, event: ChartEvent) => boolean | void;
78
type TextAlign = 'left' | 'right' | 'start' | 'center' | 'end';
89

910
type Font = {

types/test/options.basic.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Chart} from 'chart.js';
1+
import {Chart, ChartEvent} from 'chart.js';
22
import {Context} from '../context';
33
import {Options} from '../options';
44

@@ -45,9 +45,9 @@ const options: Options = {
4545
offset: 42,
4646
opacity: 0.42,
4747
listeners: {
48-
click: (ctx: Context) => true,
49-
enter: (ctx: Context) => false,
50-
leave: (ctx: Context) => {
48+
click: (ctx: Context, event: ChartEvent) => true,
49+
enter: (ctx: Context, event: ChartEvent) => false,
50+
leave: (ctx: Context, event: ChartEvent) => {
5151
// return void
5252
}
5353
},

types/test/options.context.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Chart} from 'chart.js';
1+
import {Chart, ChartEvent} from 'chart.js';
22
import {Context} from '../context';
33
import {Options} from '../options';
44

@@ -9,7 +9,7 @@ interface CustomContext extends Context {
99
const options: Options = {
1010
rotation: (ctx: CustomContext) => ctx.foo || 0,
1111
listeners: {
12-
click: (ctx: CustomContext) => {
12+
click: (ctx: CustomContext, event: ChartEvent) => {
1313
ctx.foo = 42;
1414
}
1515
},

types/test/options.inline.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Chart} from 'chart.js';
1+
import {Chart, ChartEvent} from 'chart.js';
22
import {Context} from '../context';
33

44
const chart = new Chart('id', {
@@ -16,12 +16,12 @@ const chart = new Chart('id', {
1616
bla: {
1717
align: 'end',
1818
listeners: {
19-
click: (ctx: Context) => true
19+
click: (ctx: Context, event: ChartEvent) => true
2020
}
2121
}
2222
},
2323
listeners: {
24-
click: (ctx: Context) => true
24+
click: (ctx: Context, event: ChartEvent) => true
2525
}
2626
}
2727
}
@@ -37,12 +37,12 @@ const chart = new Chart('id', {
3737
bla: {
3838
align: 'end',
3939
listeners: {
40-
click: (ctx: Context) => true
40+
click: (ctx: Context, event: ChartEvent) => true
4141
}
4242
}
4343
},
4444
listeners: {
45-
click: (ctx: Context) => true
45+
click: (ctx: Context, event: ChartEvent) => true
4646
}
4747
}
4848
}

0 commit comments

Comments
 (0)