-
Notifications
You must be signed in to change notification settings - Fork 319
/
events.js
119 lines (106 loc) · 3.31 KB
/
events.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import {defined, callback} from 'chart.js/helpers';
import {getElements} from './interaction';
const clickHooks = ['click', 'dblclick'];
const moveHooks = ['enter', 'leave'];
export const hooks = clickHooks.concat(moveHooks);
export function updateListeners(chart, state, options) {
state.listened = false;
state.moveListened = false;
state._getElements = getElements; // for testing
hooks.forEach(hook => {
if (typeof options[hook] === 'function') {
state.listened = true;
state.listeners[hook] = options[hook];
} else if (defined(state.listeners[hook])) {
delete state.listeners[hook];
}
});
moveHooks.forEach(hook => {
if (typeof options[hook] === 'function') {
state.moveListened = true;
}
});
if (!state.listened || !state.moveListened) {
state.annotations.forEach(scope => {
if (!state.listened) {
clickHooks.forEach(hook => {
if (typeof scope[hook] === 'function') {
state.listened = true;
}
});
}
if (!state.moveListened) {
moveHooks.forEach(hook => {
if (typeof scope[hook] === 'function') {
state.listened = true;
state.moveListened = true;
}
});
}
});
}
}
export function handleEvent(state, event, options) {
if (state.listened) {
switch (event.type) {
case 'mousemove':
case 'mouseout':
handleMoveEvents(state, event, options);
break;
case 'click':
handleClickEvents(state, event, options);
break;
default:
}
}
}
function handleMoveEvents(state, event, options) {
if (!state.moveListened) {
return;
}
let elements;
if (event.type === 'mousemove') {
elements = getElements(state, event, options.interaction);
} else {
elements = [];
}
const previous = state.hovered;
state.hovered = elements;
const context = {state, event};
dispatchMoveEvents(context, 'leave', previous, elements);
dispatchMoveEvents(context, 'enter', elements, previous);
}
function dispatchMoveEvents({state, event}, hook, elements, checkElements) {
for (const element of elements) {
if (checkElements.indexOf(element) < 0) {
dispatchEvent(element.options[hook] || state.listeners[hook], element, event);
}
}
}
function handleClickEvents(state, event, options) {
const listeners = state.listeners;
const elements = getElements(state, event, options.interaction);
for (const element of elements) {
const elOpts = element.options;
const dblclick = elOpts.dblclick || listeners.dblclick;
const click = elOpts.click || listeners.click;
if (element.clickTimeout) {
// 2nd click before timeout, so its a double click
clearTimeout(element.clickTimeout);
delete element.clickTimeout;
dispatchEvent(dblclick, element, event);
} else if (dblclick) {
// if there is a dblclick handler, wait for dblClickSpeed ms before deciding its a click
element.clickTimeout = setTimeout(() => {
delete element.clickTimeout;
dispatchEvent(click, element, event);
}, options.dblClickSpeed);
} else {
// no double click handler, just call the click handler directly
dispatchEvent(click, element, event);
}
}
}
function dispatchEvent(handler, element, event) {
callback(handler, [element.$context, event]);
}