@neo4j-nvl/interaction-handlers 1.2.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -1
- package/README.md +4 -4
- package/lib/__tests__/click-interaction.test.js +450 -264
- package/lib/__tests__/hover-interaction.test.js +83 -15
- package/lib/__tests__/zoom-interaction.test.js +20 -46
- package/lib/interaction-handlers/box-select-interaction.d.ts +1 -1
- package/lib/interaction-handlers/click-interaction.d.ts +46 -16
- package/lib/interaction-handlers/click-interaction.js +55 -34
- package/lib/interaction-handlers/hover-interaction.d.ts +5 -5
- package/lib/interaction-handlers/lasso-interaction.d.ts +1 -1
- package/lib/interaction-handlers/pan-interaction.d.ts +1 -1
- package/lib/interaction-handlers/zoom-interaction.d.ts +1 -8
- package/lib/interaction-handlers/zoom-interaction.js +0 -1
- package/package.json +2 -2
|
@@ -17,303 +17,489 @@ describe('ClickInteraction', () => {
|
|
|
17
17
|
clickInteraction.destroy();
|
|
18
18
|
myNVL.destroy();
|
|
19
19
|
callbackMock.mockReset();
|
|
20
|
+
jest.restoreAllMocks();
|
|
20
21
|
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
let mouseEvent = new MouseEvent('mousedown', {
|
|
25
|
-
clientX: 10,
|
|
26
|
-
clientY: 10
|
|
27
|
-
});
|
|
28
|
-
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
29
|
-
mouseEvent = new MouseEvent('click', {
|
|
30
|
-
clientX: 10,
|
|
31
|
-
clientY: 10
|
|
32
|
-
});
|
|
33
|
-
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
34
|
-
return new Promise((resolve) => {
|
|
35
|
-
expect(callbackMock).toHaveBeenCalledWith(mouseEvent);
|
|
36
|
-
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
22
|
+
describe('clicks on empty canvas', () => {
|
|
23
|
+
test('clicking outside of nodes and relationships should not select anything', () => {
|
|
24
|
+
clickInteraction.updateCallback('onCanvasClick', callbackMock);
|
|
37
25
|
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
38
|
-
|
|
26
|
+
let mouseEvent = new MouseEvent('mousedown', {
|
|
27
|
+
clientX: 10,
|
|
28
|
+
clientY: 10
|
|
29
|
+
});
|
|
30
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
31
|
+
mouseEvent = new MouseEvent('click', {
|
|
32
|
+
clientX: 10,
|
|
33
|
+
clientY: 10
|
|
34
|
+
});
|
|
35
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
expect(callbackMock).toHaveBeenCalledWith(mouseEvent);
|
|
38
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
39
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
40
|
+
resolve();
|
|
41
|
+
});
|
|
39
42
|
});
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
test('clicking outside of nodes and relationships should de-select everything', () => {
|
|
44
|
+
clickInteraction.updateCallback('onCanvasClick', callbackMock);
|
|
45
|
+
myNVL.updateElementsInGraph([
|
|
46
|
+
{ id: '0', selected: true },
|
|
47
|
+
{ id: '1', selected: true }
|
|
48
|
+
], []);
|
|
49
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(2);
|
|
50
|
+
let mouseEvent = new MouseEvent('mousedown', {
|
|
51
|
+
clientX: 10,
|
|
52
|
+
clientY: 10
|
|
53
|
+
});
|
|
54
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
55
|
+
mouseEvent = new MouseEvent('click', {
|
|
56
|
+
clientX: 10,
|
|
57
|
+
clientY: 10
|
|
58
|
+
});
|
|
59
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
60
|
+
return new Promise((resolve) => {
|
|
61
|
+
expect(callbackMock).toHaveBeenCalledWith(mouseEvent);
|
|
62
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
63
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
64
|
+
resolve();
|
|
65
|
+
});
|
|
51
66
|
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
67
|
+
test(`clicking outside of nodes and relationships should not de-select anything
|
|
68
|
+
when selection mode is turned off but still trigger callback`, () => {
|
|
69
|
+
clickInteraction.destroy();
|
|
70
|
+
clickInteraction = new ClickInteraction(myNVL, { selectOnClick: false });
|
|
71
|
+
clickInteraction.updateCallback('onCanvasClick', callbackMock);
|
|
72
|
+
myNVL.updateElementsInGraph([
|
|
73
|
+
{ id: '0', selected: true },
|
|
74
|
+
{ id: '1', selected: true }
|
|
75
|
+
], []);
|
|
76
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(2);
|
|
77
|
+
let mouseEvent = new MouseEvent('mousedown', {
|
|
78
|
+
clientX: 10,
|
|
79
|
+
clientY: 10
|
|
80
|
+
});
|
|
81
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
82
|
+
mouseEvent = new MouseEvent('click', {
|
|
83
|
+
clientX: 10,
|
|
84
|
+
clientY: 10
|
|
85
|
+
});
|
|
86
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
87
|
+
return new Promise((resolve) => {
|
|
88
|
+
expect(callbackMock).toHaveBeenCalledWith(mouseEvent);
|
|
89
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
90
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(2);
|
|
91
|
+
resolve();
|
|
92
|
+
});
|
|
56
93
|
});
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
94
|
+
test('context menu event on canvas should trigger canvas right-click callback', () => {
|
|
95
|
+
clickInteraction.updateCallback('onCanvasRightClick', callbackMock);
|
|
96
|
+
const mouseEvent = new MouseEvent('contextmenu', {
|
|
97
|
+
clientX: 50,
|
|
98
|
+
clientY: 50
|
|
99
|
+
});
|
|
100
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
101
|
+
return new Promise((resolve) => {
|
|
102
|
+
expect(callbackMock).toHaveBeenCalledWith(mouseEvent);
|
|
103
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
104
|
+
resolve();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
test('releasing right mouse button should not select anything and trigger no callbacks', () => {
|
|
108
|
+
clickInteraction.updateCallback('onNodeClick', callbackMock);
|
|
109
|
+
const mouseEvent = new MouseEvent('mouseup', {
|
|
110
|
+
clientX: 10,
|
|
111
|
+
clientY: 10,
|
|
112
|
+
button: 2
|
|
113
|
+
});
|
|
114
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
115
|
+
return new Promise((resolve) => {
|
|
116
|
+
expect(callbackMock).toHaveBeenCalledTimes(0);
|
|
117
|
+
resolve();
|
|
118
|
+
});
|
|
63
119
|
});
|
|
64
120
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
121
|
+
describe('clicks on nodes', () => {
|
|
122
|
+
test('clicking on a node should select it and trigger callback', () => {
|
|
123
|
+
clickInteraction.updateCallback('onNodeClick', callbackMock);
|
|
124
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', {
|
|
125
|
+
clientX: 100,
|
|
126
|
+
clientY: 100
|
|
127
|
+
}));
|
|
128
|
+
const mouseEvent = new MouseEvent('click', {
|
|
129
|
+
clientX: 100,
|
|
130
|
+
clientY: 100
|
|
131
|
+
});
|
|
132
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
133
|
+
return new Promise((resolve) => {
|
|
134
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', selected: true, x: 100, y: 100 }, {
|
|
135
|
+
nodes: [
|
|
136
|
+
{
|
|
137
|
+
data: { id: '0', selected: true, x: 100, y: 100 },
|
|
138
|
+
distance: 0,
|
|
139
|
+
distanceVector: { x: 0, y: 0 },
|
|
140
|
+
insideNode: true,
|
|
141
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
142
|
+
targetCoordinates: { x: 100, y: 100 }
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
relationships: [
|
|
146
|
+
{
|
|
147
|
+
data: { id: '10', from: '0', to: '1' },
|
|
148
|
+
distance: 0,
|
|
149
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
150
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
151
|
+
toTargetCoordinates: { x: 200, y: 200 }
|
|
152
|
+
}
|
|
153
|
+
],
|
|
154
|
+
clusters: []
|
|
155
|
+
}, mouseEvent);
|
|
156
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
157
|
+
resolve();
|
|
158
|
+
});
|
|
78
159
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
160
|
+
test('clicking on a node should not select it if selection mode is off but still trigger callback', () => {
|
|
161
|
+
clickInteraction.destroy();
|
|
162
|
+
clickInteraction = new ClickInteraction(myNVL, { selectOnClick: false });
|
|
163
|
+
clickInteraction.updateCallback('onNodeClick', callbackMock);
|
|
164
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', {
|
|
165
|
+
clientX: 100,
|
|
166
|
+
clientY: 100
|
|
167
|
+
}));
|
|
168
|
+
const mouseEvent = new MouseEvent('click', {
|
|
169
|
+
clientX: 100,
|
|
170
|
+
clientY: 100
|
|
171
|
+
});
|
|
172
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
173
|
+
return new Promise((resolve) => {
|
|
174
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', x: 100, y: 100 }, {
|
|
175
|
+
nodes: [
|
|
176
|
+
{
|
|
177
|
+
data: { id: '0', x: 100, y: 100 },
|
|
178
|
+
distance: 0,
|
|
179
|
+
distanceVector: { x: 0, y: 0 },
|
|
180
|
+
insideNode: true,
|
|
181
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
182
|
+
targetCoordinates: { x: 100, y: 100 }
|
|
183
|
+
}
|
|
184
|
+
],
|
|
185
|
+
relationships: [
|
|
186
|
+
{
|
|
187
|
+
data: { id: '10', from: '0', to: '1' },
|
|
188
|
+
distance: 0,
|
|
189
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
190
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
191
|
+
toTargetCoordinates: { x: 200, y: 200 }
|
|
192
|
+
}
|
|
193
|
+
],
|
|
194
|
+
clusters: []
|
|
195
|
+
}, mouseEvent);
|
|
196
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
197
|
+
resolve();
|
|
198
|
+
});
|
|
83
199
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
expect(
|
|
88
|
-
|
|
89
|
-
|
|
200
|
+
test('clicking on a node should de-select other selected nodes and trigger callback', () => {
|
|
201
|
+
clickInteraction.updateCallback('onNodeClick', callbackMock);
|
|
202
|
+
myNVL.updateElementsInGraph([{ id: '0' }, { id: '1', selected: true }], []);
|
|
203
|
+
expect(myNVL.getSelectedNodes()).toEqual([{ id: '1', selected: true, x: 200, y: 200 }]);
|
|
204
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', {
|
|
205
|
+
clientX: 100,
|
|
206
|
+
clientY: 100
|
|
207
|
+
}));
|
|
208
|
+
const mouseEvent = new MouseEvent('click', {
|
|
209
|
+
clientX: 100,
|
|
210
|
+
clientY: 100
|
|
211
|
+
});
|
|
212
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
213
|
+
return new Promise((resolve) => {
|
|
214
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', selected: true, x: 100, y: 100 }, {
|
|
215
|
+
nodes: [
|
|
216
|
+
{
|
|
217
|
+
data: { id: '0', selected: true, x: 100, y: 100 },
|
|
218
|
+
distance: 0,
|
|
219
|
+
distanceVector: { x: 0, y: 0 },
|
|
220
|
+
insideNode: true,
|
|
221
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
222
|
+
targetCoordinates: { x: 100, y: 100 }
|
|
223
|
+
}
|
|
224
|
+
],
|
|
225
|
+
relationships: [
|
|
226
|
+
{
|
|
227
|
+
data: { id: '10', from: '0', to: '1' },
|
|
228
|
+
distance: 0,
|
|
229
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
230
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
231
|
+
toTargetCoordinates: { x: 200, y: 200 }
|
|
232
|
+
}
|
|
233
|
+
],
|
|
234
|
+
clusters: []
|
|
235
|
+
}, mouseEvent);
|
|
236
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
237
|
+
expect(myNVL.getSelectedNodes()).toEqual([{ id: '0', selected: true, x: 100, y: 100 }]);
|
|
238
|
+
resolve();
|
|
239
|
+
});
|
|
90
240
|
});
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
clientX: 100,
|
|
96
|
-
clientY: 100
|
|
97
|
-
|
|
98
|
-
const mouseEvent = new MouseEvent('click', {
|
|
99
|
-
clientX: 100,
|
|
100
|
-
clientY: 100
|
|
241
|
+
test('clicking an already selected node should de-select it', () => {
|
|
242
|
+
clickInteraction.updateCallback('onNodeClick', callbackMock);
|
|
243
|
+
myNVL.updateElementsInGraph([{ id: '0', selected: true }], []);
|
|
244
|
+
expect(myNVL.getSelectedNodes().map((node) => node.id)).toEqual(['0']);
|
|
245
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', { clientX: 100, clientY: 100 }));
|
|
246
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('click', { clientX: 100, clientY: 100 }));
|
|
247
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
101
248
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
249
|
+
test('context menu event on a node should trigger node right-click callback', () => {
|
|
250
|
+
clickInteraction.updateCallback('onNodeRightClick', callbackMock);
|
|
251
|
+
const mouseEvent = new MouseEvent('contextmenu', {
|
|
252
|
+
clientX: 100,
|
|
253
|
+
clientY: 100
|
|
254
|
+
});
|
|
255
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
256
|
+
return new Promise((resolve) => {
|
|
257
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', x: 100, y: 100 }, {
|
|
258
|
+
nodes: [
|
|
259
|
+
{
|
|
260
|
+
data: { id: '0', x: 100, y: 100 },
|
|
261
|
+
distance: 0,
|
|
262
|
+
distanceVector: { x: 0, y: 0 },
|
|
263
|
+
insideNode: true,
|
|
264
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
265
|
+
targetCoordinates: { x: 100, y: 100 }
|
|
266
|
+
}
|
|
267
|
+
],
|
|
268
|
+
relationships: [
|
|
269
|
+
{
|
|
270
|
+
data: { id: '10', from: '0', to: '1' },
|
|
271
|
+
distance: 0,
|
|
272
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
273
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
274
|
+
toTargetCoordinates: { x: 200, y: 200 }
|
|
275
|
+
}
|
|
276
|
+
],
|
|
277
|
+
clusters: []
|
|
278
|
+
}, mouseEvent);
|
|
279
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
280
|
+
resolve();
|
|
281
|
+
});
|
|
127
282
|
});
|
|
128
283
|
});
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
284
|
+
describe('clicks on relationships', () => {
|
|
285
|
+
test('clicking on a relationship should select it and trigger callback', () => {
|
|
286
|
+
clickInteraction.updateCallback('onRelationshipClick', callbackMock);
|
|
287
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', {
|
|
288
|
+
clientX: 150,
|
|
289
|
+
clientY: 150
|
|
290
|
+
}));
|
|
291
|
+
const mouseEvent = new MouseEvent('click', {
|
|
292
|
+
clientX: 150,
|
|
293
|
+
clientY: 150
|
|
294
|
+
});
|
|
295
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
296
|
+
return new Promise((resolve) => {
|
|
297
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '10', selected: true, from: '0', to: '1' }, {
|
|
298
|
+
nodes: [],
|
|
299
|
+
relationships: [
|
|
300
|
+
{
|
|
301
|
+
data: { id: '10', selected: true, from: '0', to: '1' },
|
|
302
|
+
distance: 0,
|
|
303
|
+
pointerCoordinates: { x: 150, y: 150 },
|
|
304
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
305
|
+
toTargetCoordinates: { x: 200, y: 200 }
|
|
306
|
+
}
|
|
307
|
+
],
|
|
308
|
+
clusters: []
|
|
309
|
+
}, mouseEvent);
|
|
310
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
311
|
+
resolve();
|
|
312
|
+
});
|
|
138
313
|
});
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
distance: 0,
|
|
147
|
-
pointerCoordinates: { x: 150, y: 150 },
|
|
148
|
-
fromTargetCoordinates: { x: 100, y: 100 },
|
|
149
|
-
toTargetCoordinates: { x: 200, y: 200 }
|
|
150
|
-
}
|
|
151
|
-
]
|
|
152
|
-
}, mouseEvent);
|
|
153
|
-
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
154
|
-
resolve();
|
|
314
|
+
test('clicking an already selected relationship should de-select it', () => {
|
|
315
|
+
clickInteraction.updateCallback('onRelationshipClick', callbackMock);
|
|
316
|
+
myNVL.updateElementsInGraph([], [{ id: '10', from: '0', to: '1', selected: true }]);
|
|
317
|
+
expect(myNVL.getSelectedRelationships().map((relationship) => relationship.id)).toEqual(['10']);
|
|
318
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', { clientX: 150, clientY: 150 }));
|
|
319
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('click', { clientX: 150, clientY: 150 }));
|
|
320
|
+
expect(myNVL.getSelectedRelationships()).toHaveLength(0);
|
|
155
321
|
});
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
322
|
+
test('context menu event on a relationship should trigger relationship right-click callback', () => {
|
|
323
|
+
clickInteraction.updateCallback('onRelationshipRightClick', callbackMock);
|
|
324
|
+
const mouseEvent = new MouseEvent('contextmenu', {
|
|
325
|
+
clientX: 150,
|
|
326
|
+
clientY: 150
|
|
327
|
+
});
|
|
328
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
329
|
+
return new Promise((resolve) => {
|
|
330
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '10', from: '0', to: '1' }, {
|
|
331
|
+
nodes: [],
|
|
332
|
+
relationships: [
|
|
333
|
+
{
|
|
334
|
+
data: { id: '10', from: '0', to: '1' },
|
|
335
|
+
distance: 0,
|
|
336
|
+
pointerCoordinates: { x: 150, y: 150 },
|
|
337
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
338
|
+
toTargetCoordinates: { x: 200, y: 200 }
|
|
339
|
+
}
|
|
340
|
+
],
|
|
341
|
+
clusters: []
|
|
342
|
+
}, mouseEvent);
|
|
343
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
344
|
+
resolve();
|
|
345
|
+
});
|
|
168
346
|
});
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
pointerCoordinates: { x: 100, y: 100 },
|
|
179
|
-
targetCoordinates: { x: 100, y: 100 }
|
|
180
|
-
}
|
|
181
|
-
],
|
|
182
|
-
relationships: [
|
|
347
|
+
});
|
|
348
|
+
describe('clicks on cluster hulls', () => {
|
|
349
|
+
test('clicking a cluster hull should trigger onClusterClick and select member nodes', () => {
|
|
350
|
+
clickInteraction.updateCallback('onClusterClick', callbackMock);
|
|
351
|
+
const cluster = { id: 'group-a', nodeIds: ['0', '1'] };
|
|
352
|
+
const nvlTargets = {
|
|
353
|
+
nodes: [],
|
|
354
|
+
relationships: [],
|
|
355
|
+
clusters: [
|
|
183
356
|
{
|
|
184
|
-
data:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
357
|
+
data: cluster,
|
|
358
|
+
pointerCoordinates: { x: 50, y: 50 },
|
|
359
|
+
hull: [
|
|
360
|
+
{ x: 0, y: 0 },
|
|
361
|
+
{ x: 100, y: 0 },
|
|
362
|
+
{ x: 100, y: 100 },
|
|
363
|
+
{ x: 0, y: 100 }
|
|
364
|
+
]
|
|
189
365
|
}
|
|
190
366
|
]
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
367
|
+
};
|
|
368
|
+
jest.spyOn(myNVL, 'getHits').mockImplementation((event) => Object.assign(event, { nvlTargets }));
|
|
369
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', {
|
|
370
|
+
clientX: 50,
|
|
371
|
+
clientY: 50
|
|
372
|
+
}));
|
|
373
|
+
const mouseEvent = new MouseEvent('click', {
|
|
374
|
+
clientX: 50,
|
|
375
|
+
clientY: 50
|
|
376
|
+
});
|
|
377
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
378
|
+
expect(callbackMock).toHaveBeenCalledWith(cluster, nvlTargets, mouseEvent);
|
|
379
|
+
expect(myNVL
|
|
380
|
+
.getSelectedNodes()
|
|
381
|
+
.map((n) => n.id)
|
|
382
|
+
.sort()).toEqual(['0', '1']);
|
|
207
383
|
});
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
distanceVector: { x: 0, y: 0 },
|
|
216
|
-
insideNode: true,
|
|
217
|
-
pointerCoordinates: { x: 100, y: 100 },
|
|
218
|
-
targetCoordinates: { x: 100, y: 100 }
|
|
219
|
-
}
|
|
220
|
-
],
|
|
221
|
-
relationships: [
|
|
384
|
+
test('clicking a cluster hull whose members are all selected should de-select them', () => {
|
|
385
|
+
clickInteraction.updateCallback('onClusterClick', callbackMock);
|
|
386
|
+
const cluster = { id: 'group-a', nodeIds: ['0', '1'] };
|
|
387
|
+
const nvlTargets = {
|
|
388
|
+
nodes: [],
|
|
389
|
+
relationships: [],
|
|
390
|
+
clusters: [
|
|
222
391
|
{
|
|
223
|
-
data:
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
392
|
+
data: cluster,
|
|
393
|
+
pointerCoordinates: { x: 50, y: 50 },
|
|
394
|
+
hull: [
|
|
395
|
+
{ x: 0, y: 0 },
|
|
396
|
+
{ x: 100, y: 0 },
|
|
397
|
+
{ x: 100, y: 100 },
|
|
398
|
+
{ x: 0, y: 100 }
|
|
399
|
+
]
|
|
228
400
|
}
|
|
229
401
|
]
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
clientX: 50,
|
|
240
|
-
clientY: 50
|
|
241
|
-
});
|
|
242
|
-
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
243
|
-
return new Promise((resolve) => {
|
|
244
|
-
expect(callbackMock).toHaveBeenCalledWith(mouseEvent);
|
|
245
|
-
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
246
|
-
resolve();
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
test('context menu event on a node should trigger node right-click callback', () => {
|
|
250
|
-
clickInteraction.updateCallback('onNodeRightClick', callbackMock);
|
|
251
|
-
const mouseEvent = new MouseEvent('contextmenu', {
|
|
252
|
-
clientX: 100,
|
|
253
|
-
clientY: 100
|
|
402
|
+
};
|
|
403
|
+
jest.spyOn(myNVL, 'getHits').mockImplementation((event) => Object.assign(event, { nvlTargets }));
|
|
404
|
+
myNVL.updateElementsInGraph([
|
|
405
|
+
{ id: '0', selected: true },
|
|
406
|
+
{ id: '1', selected: true }
|
|
407
|
+
], []);
|
|
408
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', { clientX: 50, clientY: 50 }));
|
|
409
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('click', { clientX: 50, clientY: 50 }));
|
|
410
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
254
411
|
});
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
distanceVector: { x: 0, y: 0 },
|
|
263
|
-
insideNode: true,
|
|
264
|
-
pointerCoordinates: { x: 100, y: 100 },
|
|
265
|
-
targetCoordinates: { x: 100, y: 100 }
|
|
266
|
-
}
|
|
267
|
-
],
|
|
268
|
-
relationships: [
|
|
412
|
+
test('clicking a cluster hull with only some members selected should select all of them', () => {
|
|
413
|
+
clickInteraction.updateCallback('onClusterClick', callbackMock);
|
|
414
|
+
const cluster = { id: 'group-a', nodeIds: ['0', '1'] };
|
|
415
|
+
const nvlTargets = {
|
|
416
|
+
nodes: [],
|
|
417
|
+
relationships: [],
|
|
418
|
+
clusters: [
|
|
269
419
|
{
|
|
270
|
-
data:
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
420
|
+
data: cluster,
|
|
421
|
+
pointerCoordinates: { x: 50, y: 50 },
|
|
422
|
+
hull: [
|
|
423
|
+
{ x: 0, y: 0 },
|
|
424
|
+
{ x: 100, y: 0 },
|
|
425
|
+
{ x: 100, y: 100 },
|
|
426
|
+
{ x: 0, y: 100 }
|
|
427
|
+
]
|
|
275
428
|
}
|
|
276
429
|
]
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
clientY: 150
|
|
430
|
+
};
|
|
431
|
+
jest.spyOn(myNVL, 'getHits').mockImplementation((event) => Object.assign(event, { nvlTargets }));
|
|
432
|
+
myNVL.updateElementsInGraph([{ id: '0', selected: true }], []);
|
|
433
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', { clientX: 50, clientY: 50 }));
|
|
434
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('click', { clientX: 50, clientY: 50 }));
|
|
435
|
+
expect(myNVL
|
|
436
|
+
.getSelectedNodes()
|
|
437
|
+
.map((node) => node.id)
|
|
438
|
+
.sort()).toEqual(['0', '1']);
|
|
287
439
|
});
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
440
|
+
test.each([
|
|
441
|
+
['onClusterDoubleClick', 'dblclick'],
|
|
442
|
+
['onClusterRightClick', 'contextmenu']
|
|
443
|
+
])('%s is triggered for a cluster hull', (callbackName, eventName) => {
|
|
444
|
+
clickInteraction.updateCallback(callbackName, callbackMock);
|
|
445
|
+
const cluster = { id: 'group-a', nodeIds: ['0', '1'] };
|
|
446
|
+
const nvlTargets = {
|
|
291
447
|
nodes: [],
|
|
292
|
-
relationships: [
|
|
448
|
+
relationships: [],
|
|
449
|
+
clusters: [
|
|
293
450
|
{
|
|
294
|
-
data:
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
451
|
+
data: cluster,
|
|
452
|
+
pointerCoordinates: { x: 50, y: 50 },
|
|
453
|
+
hull: [
|
|
454
|
+
{ x: 0, y: 0 },
|
|
455
|
+
{ x: 100, y: 0 },
|
|
456
|
+
{ x: 100, y: 100 },
|
|
457
|
+
{ x: 0, y: 100 }
|
|
458
|
+
]
|
|
299
459
|
}
|
|
300
460
|
]
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
|
|
461
|
+
};
|
|
462
|
+
jest.spyOn(myNVL, 'getHits').mockImplementation((event) => Object.assign(event, { nvlTargets }));
|
|
463
|
+
const mouseEvent = new MouseEvent(eventName, { clientX: 50, clientY: 50 });
|
|
464
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
465
|
+
expect(callbackMock).toHaveBeenCalledWith(cluster, nvlTargets, mouseEvent);
|
|
304
466
|
});
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
467
|
+
test('node hits take priority over cluster hits', () => {
|
|
468
|
+
clickInteraction.updateCallback('onNodeClick', callbackMock);
|
|
469
|
+
clickInteraction.updateCallback('onClusterClick', jest.fn());
|
|
470
|
+
const clusterCallback = jest.fn();
|
|
471
|
+
clickInteraction.updateCallback('onClusterClick', clusterCallback);
|
|
472
|
+
jest.spyOn(myNVL, 'getHits').mockImplementation((event) => Object.assign(event, {
|
|
473
|
+
nvlTargets: {
|
|
474
|
+
nodes: [
|
|
475
|
+
{
|
|
476
|
+
data: { id: '0', x: 100, y: 100 },
|
|
477
|
+
distance: 0,
|
|
478
|
+
distanceVector: { x: 0, y: 0 },
|
|
479
|
+
insideNode: true,
|
|
480
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
481
|
+
targetCoordinates: { x: 100, y: 100 }
|
|
482
|
+
}
|
|
483
|
+
],
|
|
484
|
+
relationships: [],
|
|
485
|
+
clusters: [
|
|
486
|
+
{
|
|
487
|
+
data: { id: 'group-a', nodeIds: ['0', '1'] },
|
|
488
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
489
|
+
hull: [
|
|
490
|
+
{ x: 0, y: 0 },
|
|
491
|
+
{ x: 200, y: 0 },
|
|
492
|
+
{ x: 200, y: 200 },
|
|
493
|
+
{ x: 0, y: 200 }
|
|
494
|
+
]
|
|
495
|
+
}
|
|
496
|
+
]
|
|
497
|
+
}
|
|
498
|
+
}));
|
|
499
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', { clientX: 100, clientY: 100 }));
|
|
500
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('click', { clientX: 100, clientY: 100 }));
|
|
501
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
502
|
+
expect(clusterCallback).not.toHaveBeenCalled();
|
|
317
503
|
});
|
|
318
504
|
});
|
|
319
505
|
});
|