@neo4j-nvl/interaction-handlers 0.3.1 → 0.3.2-e0e72a58
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/README.md +1 -1
- package/lib/__tests__/click-interaction.test.d.ts +1 -0
- package/lib/__tests__/click-interaction.test.js +319 -0
- package/lib/__tests__/drag-node-interaction.test.d.ts +1 -0
- package/lib/__tests__/drag-node-interaction.test.js +131 -0
- package/lib/__tests__/hover-interaction.test.d.ts +1 -0
- package/lib/__tests__/hover-interaction.test.js +306 -0
- package/lib/__tests__/lasso-interaction.test.d.ts +1 -0
- package/lib/__tests__/lasso-interaction.test.js +79 -0
- package/lib/interaction-handlers/base.js +2 -2
- package/lib/interaction-handlers/box-select-interaction.d.ts +5 -1
- package/lib/interaction-handlers/box-select-interaction.js +5 -1
- package/lib/interaction-handlers/click-interaction.d.ts +1 -1
- package/lib/interaction-handlers/click-interaction.js +1 -1
- package/lib/interaction-handlers/drag-node-interaction.d.ts +4 -1
- package/lib/interaction-handlers/drag-node-interaction.js +4 -1
- package/lib/interaction-handlers/draw-interaction.d.ts +5 -0
- package/lib/interaction-handlers/draw-interaction.js +44 -2
- package/lib/interaction-handlers/hover-interaction.d.ts +5 -2
- package/lib/interaction-handlers/hover-interaction.js +6 -3
- package/lib/interaction-handlers/lasso-interaction.d.ts +6 -2
- package/lib/interaction-handlers/lasso-interaction.js +6 -2
- package/lib/interaction-handlers/pan-interaction.d.ts +11 -1
- package/lib/interaction-handlers/pan-interaction.js +11 -1
- package/lib/interaction-handlers/zoom-interaction.d.ts +4 -1
- package/lib/interaction-handlers/zoom-interaction.js +4 -1
- package/lib/overlay-renderer/overlay-renderer.js +3 -3
- package/package.json +19 -4
package/README.md
CHANGED
|
@@ -34,4 +34,4 @@ clickInteraction.updateCallback('onNodeClick', (node) => {
|
|
|
34
34
|
|
|
35
35
|
If you are using React and want to add interactivity to your graph, you can also make use of the InteractiveReactWrapper.
|
|
36
36
|
|
|
37
|
-
You can find more instructions and examples on how to use NVL in the docs.
|
|
37
|
+
You can find more instructions and examples on how to use NVL interaction handlers in the [docs](https://neo4j.com/docs/nvl/current/interaction-handlers/).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import NVL from '@neo4j-nvl/base';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
import { ClickInteraction } from '../interaction-handlers/click-interaction';
|
|
4
|
+
jest.mock('@neo4j-nvl/layout-workers');
|
|
5
|
+
describe('ClickInteraction', () => {
|
|
6
|
+
let clickInteraction;
|
|
7
|
+
let myNVL;
|
|
8
|
+
const callbackMock = jest.fn();
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
myNVL = new NVL(document.createElement('div'), [
|
|
11
|
+
{ id: '0', x: 100, y: 100 },
|
|
12
|
+
{ id: '1', x: 200, y: 200 }
|
|
13
|
+
], [{ id: '10', from: '0', to: '1' }], { disableWebGL: true, initialZoom: 1, layout: 'free' });
|
|
14
|
+
clickInteraction = new ClickInteraction(myNVL, { selectOnClick: true });
|
|
15
|
+
});
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
clickInteraction.destroy();
|
|
18
|
+
myNVL.destroy();
|
|
19
|
+
callbackMock.mockReset();
|
|
20
|
+
});
|
|
21
|
+
test('clicking outside of nodes and relationships should not select anything', () => {
|
|
22
|
+
clickInteraction.updateCallback('onCanvasClick', callbackMock);
|
|
23
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
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);
|
|
37
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
38
|
+
resolve();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
test('clicking outside of nodes and relationships should de-select everything', () => {
|
|
42
|
+
clickInteraction.updateCallback('onCanvasClick', callbackMock);
|
|
43
|
+
myNVL.updateElementsInGraph([
|
|
44
|
+
{ id: '0', selected: true },
|
|
45
|
+
{ id: '1', selected: true }
|
|
46
|
+
], []);
|
|
47
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(2);
|
|
48
|
+
let mouseEvent = new MouseEvent('mousedown', {
|
|
49
|
+
clientX: 10,
|
|
50
|
+
clientY: 10
|
|
51
|
+
});
|
|
52
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
53
|
+
mouseEvent = new MouseEvent('click', {
|
|
54
|
+
clientX: 10,
|
|
55
|
+
clientY: 10
|
|
56
|
+
});
|
|
57
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
expect(callbackMock).toHaveBeenCalledWith(mouseEvent);
|
|
60
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
61
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
62
|
+
resolve();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
test(`clicking outside of nodes and relationships should not de-select anything
|
|
66
|
+
when selection mode is turned off but still trigger callback`, () => {
|
|
67
|
+
clickInteraction.destroy();
|
|
68
|
+
clickInteraction = new ClickInteraction(myNVL, { selectOnClick: false });
|
|
69
|
+
clickInteraction.updateCallback('onCanvasClick', callbackMock);
|
|
70
|
+
myNVL.updateElementsInGraph([
|
|
71
|
+
{ id: '0', selected: true },
|
|
72
|
+
{ id: '1', selected: true }
|
|
73
|
+
], []);
|
|
74
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(2);
|
|
75
|
+
let mouseEvent = new MouseEvent('mousedown', {
|
|
76
|
+
clientX: 10,
|
|
77
|
+
clientY: 10
|
|
78
|
+
});
|
|
79
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
80
|
+
mouseEvent = new MouseEvent('click', {
|
|
81
|
+
clientX: 10,
|
|
82
|
+
clientY: 10
|
|
83
|
+
});
|
|
84
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
expect(callbackMock).toHaveBeenCalledWith(mouseEvent);
|
|
87
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
88
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(2);
|
|
89
|
+
resolve();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
test('clicking on a node should select it and trigger callback', () => {
|
|
93
|
+
clickInteraction.updateCallback('onNodeClick', callbackMock);
|
|
94
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', {
|
|
95
|
+
clientX: 100,
|
|
96
|
+
clientY: 100
|
|
97
|
+
}));
|
|
98
|
+
const mouseEvent = new MouseEvent('click', {
|
|
99
|
+
clientX: 100,
|
|
100
|
+
clientY: 100
|
|
101
|
+
});
|
|
102
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', selected: true, x: 100, y: 100 }, {
|
|
105
|
+
nodes: [
|
|
106
|
+
{
|
|
107
|
+
data: { id: '0', selected: true, x: 100, y: 100 },
|
|
108
|
+
distance: 0,
|
|
109
|
+
distanceVector: { x: 0, y: 0 },
|
|
110
|
+
insideNode: true,
|
|
111
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
112
|
+
targetCoordinates: { x: 100, y: 100 }
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
relationships: [
|
|
116
|
+
{
|
|
117
|
+
data: { id: '10', from: '0', to: '1' },
|
|
118
|
+
distance: 0,
|
|
119
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
120
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
121
|
+
toTargetCoordinates: { x: 200, y: 200 }
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
}, mouseEvent);
|
|
125
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
126
|
+
resolve();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
test('clicking on a relationship should select it and trigger callback', () => {
|
|
130
|
+
clickInteraction.updateCallback('onRelationshipClick', callbackMock);
|
|
131
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', {
|
|
132
|
+
clientX: 150,
|
|
133
|
+
clientY: 150
|
|
134
|
+
}));
|
|
135
|
+
const mouseEvent = new MouseEvent('click', {
|
|
136
|
+
clientX: 150,
|
|
137
|
+
clientY: 150
|
|
138
|
+
});
|
|
139
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
140
|
+
return new Promise((resolve) => {
|
|
141
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '10', selected: true, from: '0', to: '1' }, {
|
|
142
|
+
nodes: [],
|
|
143
|
+
relationships: [
|
|
144
|
+
{
|
|
145
|
+
data: { id: '10', selected: true, from: '0', to: '1' },
|
|
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();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
test('clicking on a node should not select it if selection mode is off but still trigger callback', () => {
|
|
158
|
+
clickInteraction.destroy();
|
|
159
|
+
clickInteraction = new ClickInteraction(myNVL, { selectOnClick: false });
|
|
160
|
+
clickInteraction.updateCallback('onNodeClick', callbackMock);
|
|
161
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', {
|
|
162
|
+
clientX: 100,
|
|
163
|
+
clientY: 100
|
|
164
|
+
}));
|
|
165
|
+
const mouseEvent = new MouseEvent('click', {
|
|
166
|
+
clientX: 100,
|
|
167
|
+
clientY: 100
|
|
168
|
+
});
|
|
169
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
170
|
+
return new Promise((resolve) => {
|
|
171
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', x: 100, y: 100 }, {
|
|
172
|
+
nodes: [
|
|
173
|
+
{
|
|
174
|
+
data: { id: '0', x: 100, y: 100 },
|
|
175
|
+
distance: 0,
|
|
176
|
+
distanceVector: { x: 0, y: 0 },
|
|
177
|
+
insideNode: true,
|
|
178
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
179
|
+
targetCoordinates: { x: 100, y: 100 }
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
relationships: [
|
|
183
|
+
{
|
|
184
|
+
data: { id: '10', from: '0', to: '1' },
|
|
185
|
+
distance: 0,
|
|
186
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
187
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
188
|
+
toTargetCoordinates: { x: 200, y: 200 }
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
}, mouseEvent);
|
|
192
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
193
|
+
resolve();
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
test('clicking on a node should de-select other selected nodes and trigger callback', () => {
|
|
197
|
+
clickInteraction.updateCallback('onNodeClick', callbackMock);
|
|
198
|
+
myNVL.updateElementsInGraph([{ id: '0' }, { id: '1', selected: true }], []);
|
|
199
|
+
expect(myNVL.getSelectedNodes()).toEqual([{ id: '1', selected: true, x: 200, y: 200 }]);
|
|
200
|
+
myNVL.getContainer().dispatchEvent(new MouseEvent('mousedown', {
|
|
201
|
+
clientX: 100,
|
|
202
|
+
clientY: 100
|
|
203
|
+
}));
|
|
204
|
+
const mouseEvent = new MouseEvent('click', {
|
|
205
|
+
clientX: 100,
|
|
206
|
+
clientY: 100
|
|
207
|
+
});
|
|
208
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
209
|
+
return new Promise((resolve) => {
|
|
210
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', selected: true, x: 100, y: 100 }, {
|
|
211
|
+
nodes: [
|
|
212
|
+
{
|
|
213
|
+
data: { id: '0', selected: true, x: 100, y: 100 },
|
|
214
|
+
distance: 0,
|
|
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: [
|
|
222
|
+
{
|
|
223
|
+
data: { id: '10', from: '0', to: '1' },
|
|
224
|
+
distance: 0,
|
|
225
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
226
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
227
|
+
toTargetCoordinates: { x: 200, y: 200 }
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
}, mouseEvent);
|
|
231
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
232
|
+
expect(myNVL.getSelectedNodes()).toEqual([{ id: '0', selected: true, x: 100, y: 100 }]);
|
|
233
|
+
resolve();
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
test('context menu event on canvas should trigger canvas right-click callback', () => {
|
|
237
|
+
clickInteraction.updateCallback('onCanvasRightClick', callbackMock);
|
|
238
|
+
const mouseEvent = new MouseEvent('contextmenu', {
|
|
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
|
|
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
|
+
}, mouseEvent);
|
|
278
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
279
|
+
resolve();
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
test('context menu event on a relationship should trigger relationship right-click callback', () => {
|
|
283
|
+
clickInteraction.updateCallback('onRelationshipRightClick', callbackMock);
|
|
284
|
+
const mouseEvent = new MouseEvent('contextmenu', {
|
|
285
|
+
clientX: 150,
|
|
286
|
+
clientY: 150
|
|
287
|
+
});
|
|
288
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
289
|
+
return new Promise((resolve) => {
|
|
290
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '10', from: '0', to: '1' }, {
|
|
291
|
+
nodes: [],
|
|
292
|
+
relationships: [
|
|
293
|
+
{
|
|
294
|
+
data: { id: '10', from: '0', to: '1' },
|
|
295
|
+
distance: 0,
|
|
296
|
+
pointerCoordinates: { x: 150, y: 150 },
|
|
297
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
298
|
+
toTargetCoordinates: { x: 200, y: 200 }
|
|
299
|
+
}
|
|
300
|
+
]
|
|
301
|
+
}, mouseEvent);
|
|
302
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
303
|
+
resolve();
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
test('releasing right mouse button should not select anything and trigger no callbacks', () => {
|
|
307
|
+
clickInteraction.updateCallback('onNodeClick', callbackMock);
|
|
308
|
+
const mouseEvent = new MouseEvent('mouseup', {
|
|
309
|
+
clientX: 10,
|
|
310
|
+
clientY: 10,
|
|
311
|
+
button: 2
|
|
312
|
+
});
|
|
313
|
+
myNVL.getContainer().dispatchEvent(mouseEvent);
|
|
314
|
+
return new Promise((resolve) => {
|
|
315
|
+
expect(callbackMock).toHaveBeenCalledTimes(0);
|
|
316
|
+
resolve();
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import NVL from '@neo4j-nvl/base';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
import { DragNodeInteraction } from '../interaction-handlers/drag-node-interaction';
|
|
4
|
+
jest.mock('@neo4j-nvl/layout-workers');
|
|
5
|
+
describe('DragNodeInteraction', () => {
|
|
6
|
+
let dragNodeInteraction;
|
|
7
|
+
let myNVL;
|
|
8
|
+
const dragStartCallbackMock = jest.fn();
|
|
9
|
+
const dragCallbackMock = jest.fn();
|
|
10
|
+
const dragEndCallbackMock = jest.fn();
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
myNVL = new NVL(document.createElement('div'), [
|
|
13
|
+
{ id: '0', x: 10, y: 10 },
|
|
14
|
+
{ id: '1', x: 200, y: 200 }
|
|
15
|
+
], [{ id: '10', from: '0', to: '1' }], { disableWebGL: true, initialZoom: 1, layout: 'free' });
|
|
16
|
+
dragNodeInteraction = new DragNodeInteraction(myNVL);
|
|
17
|
+
});
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
dragNodeInteraction.destroy();
|
|
20
|
+
myNVL.destroy();
|
|
21
|
+
dragStartCallbackMock.mockReset();
|
|
22
|
+
dragCallbackMock.mockReset();
|
|
23
|
+
dragEndCallbackMock.mockReset();
|
|
24
|
+
});
|
|
25
|
+
test('performing a simple drag operation should invoke all expected callbacks', () => {
|
|
26
|
+
dragNodeInteraction.updateCallback('onDragStart', dragStartCallbackMock);
|
|
27
|
+
dragNodeInteraction.updateCallback('onDrag', dragCallbackMock);
|
|
28
|
+
dragNodeInteraction.updateCallback('onDragEnd', dragEndCallbackMock);
|
|
29
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
30
|
+
const mouseDownEvent = new MouseEvent('mousedown', {
|
|
31
|
+
clientX: 10,
|
|
32
|
+
clientY: 10
|
|
33
|
+
});
|
|
34
|
+
const mouseMoveEvent = new MouseEvent('mousemove', {
|
|
35
|
+
buttons: 1,
|
|
36
|
+
clientX: 20,
|
|
37
|
+
clientY: 20
|
|
38
|
+
});
|
|
39
|
+
const mouseUpEvent = new MouseEvent('mouseup', {
|
|
40
|
+
clientX: 20,
|
|
41
|
+
clientY: 20
|
|
42
|
+
});
|
|
43
|
+
const container = myNVL.getContainer();
|
|
44
|
+
container.dispatchEvent(mouseDownEvent);
|
|
45
|
+
container.dispatchEvent(mouseMoveEvent);
|
|
46
|
+
container.dispatchEvent(mouseUpEvent);
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
expect(dragStartCallbackMock).toHaveBeenCalledTimes(1);
|
|
49
|
+
expect(dragStartCallbackMock).toHaveBeenCalledWith([{ id: '0', x: 10, y: 10 }], mouseMoveEvent);
|
|
50
|
+
expect(dragCallbackMock).toHaveBeenCalledTimes(1);
|
|
51
|
+
expect(dragCallbackMock).toHaveBeenCalledWith([{ id: '0', x: 10, y: 10 }], mouseMoveEvent);
|
|
52
|
+
expect(dragEndCallbackMock).toHaveBeenCalledTimes(1);
|
|
53
|
+
expect(dragEndCallbackMock).toHaveBeenCalledWith([{ id: '0', x: 10, y: 10 }], mouseUpEvent);
|
|
54
|
+
resolve();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
test('performing dragging on selection of nodes should invoke all expected callbacks', () => {
|
|
58
|
+
dragNodeInteraction.updateCallback('onDragStart', dragStartCallbackMock);
|
|
59
|
+
dragNodeInteraction.updateCallback('onDrag', dragCallbackMock);
|
|
60
|
+
dragNodeInteraction.updateCallback('onDragEnd', dragEndCallbackMock);
|
|
61
|
+
myNVL.updateElementsInGraph([
|
|
62
|
+
{ id: '0', selected: true },
|
|
63
|
+
{ id: '1', selected: true }
|
|
64
|
+
], []);
|
|
65
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(2);
|
|
66
|
+
const mouseDownEvent = new MouseEvent('mousedown', {
|
|
67
|
+
clientX: 10,
|
|
68
|
+
clientY: 10
|
|
69
|
+
});
|
|
70
|
+
const mouseMoveEvent = new MouseEvent('mousemove', {
|
|
71
|
+
buttons: 1,
|
|
72
|
+
clientX: 20,
|
|
73
|
+
clientY: 20
|
|
74
|
+
});
|
|
75
|
+
const mouseUpEvent = new MouseEvent('mouseup', {
|
|
76
|
+
clientX: 20,
|
|
77
|
+
clientY: 20
|
|
78
|
+
});
|
|
79
|
+
const container = myNVL.getContainer();
|
|
80
|
+
container.dispatchEvent(mouseDownEvent);
|
|
81
|
+
container.dispatchEvent(mouseMoveEvent);
|
|
82
|
+
container.dispatchEvent(mouseUpEvent);
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
expect(dragStartCallbackMock).toHaveBeenCalledTimes(1);
|
|
85
|
+
expect(dragStartCallbackMock).toHaveBeenCalledWith([
|
|
86
|
+
{ id: '0', selected: true, x: 10, y: 10 },
|
|
87
|
+
{ id: '1', selected: true, x: 200, y: 200 }
|
|
88
|
+
], mouseMoveEvent);
|
|
89
|
+
expect(dragCallbackMock).toHaveBeenCalledTimes(1);
|
|
90
|
+
expect(dragCallbackMock).toHaveBeenCalledWith([
|
|
91
|
+
{ id: '0', selected: true, x: 10, y: 10 },
|
|
92
|
+
{ id: '1', selected: true, x: 200, y: 200 }
|
|
93
|
+
], mouseMoveEvent);
|
|
94
|
+
expect(dragEndCallbackMock).toHaveBeenCalledTimes(1);
|
|
95
|
+
expect(dragEndCallbackMock).toHaveBeenCalledWith([
|
|
96
|
+
{ id: '0', selected: true, x: 10, y: 10 },
|
|
97
|
+
{ id: '1', selected: true, x: 200, y: 200 }
|
|
98
|
+
], mouseUpEvent);
|
|
99
|
+
resolve();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
test('dragging should not be invoked when the mouse is moved less than the drag threshold', () => {
|
|
103
|
+
dragNodeInteraction.updateCallback('onDragStart', dragStartCallbackMock);
|
|
104
|
+
dragNodeInteraction.updateCallback('onDrag', dragCallbackMock);
|
|
105
|
+
dragNodeInteraction.updateCallback('onDragEnd', dragEndCallbackMock);
|
|
106
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
107
|
+
const mouseDownEvent = new MouseEvent('mousedown', {
|
|
108
|
+
clientX: 10,
|
|
109
|
+
clientY: 10
|
|
110
|
+
});
|
|
111
|
+
const mouseMoveEvent = new MouseEvent('mousemove', {
|
|
112
|
+
buttons: 1,
|
|
113
|
+
clientX: 12,
|
|
114
|
+
clientY: 12
|
|
115
|
+
});
|
|
116
|
+
const mouseUpEvent = new MouseEvent('mouseup', {
|
|
117
|
+
clientX: 12,
|
|
118
|
+
clientY: 12
|
|
119
|
+
});
|
|
120
|
+
const container = myNVL.getContainer();
|
|
121
|
+
container.dispatchEvent(mouseDownEvent);
|
|
122
|
+
container.dispatchEvent(mouseMoveEvent);
|
|
123
|
+
container.dispatchEvent(mouseUpEvent);
|
|
124
|
+
return new Promise((resolve) => {
|
|
125
|
+
expect(dragStartCallbackMock).toHaveBeenCalledTimes(0);
|
|
126
|
+
expect(dragCallbackMock).toHaveBeenCalledTimes(0);
|
|
127
|
+
expect(dragEndCallbackMock).toHaveBeenCalledTimes(0);
|
|
128
|
+
resolve();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import NVL from '@neo4j-nvl/base';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
import { HoverInteraction } from '../interaction-handlers/hover-interaction';
|
|
4
|
+
// jest.mock('@neo4j-nvl/base')
|
|
5
|
+
jest.mock('@neo4j-nvl/layout-workers');
|
|
6
|
+
describe('HoverInteraction', () => {
|
|
7
|
+
let hoverInteraction;
|
|
8
|
+
let myNVL;
|
|
9
|
+
const callbackMock = jest.fn();
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
myNVL = new NVL(document.createElement('div'), [
|
|
12
|
+
{ id: '0', x: 100, y: 100 },
|
|
13
|
+
{ id: '1', x: 200, y: 200 }
|
|
14
|
+
], [{ id: '10', from: '0', to: '1' }], { disableWebGL: true, initialZoom: 1 });
|
|
15
|
+
hoverInteraction = new HoverInteraction(myNVL, { drawShadowOnHover: true });
|
|
16
|
+
hoverInteraction.updateCallback('onHover', callbackMock);
|
|
17
|
+
});
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
hoverInteraction.destroy();
|
|
20
|
+
myNVL.destroy();
|
|
21
|
+
callbackMock.mockReset();
|
|
22
|
+
});
|
|
23
|
+
describe('handleHover', () => {
|
|
24
|
+
it('should register hover event on canvas', () => {
|
|
25
|
+
const mouseEvent = new MouseEvent('mousemove', {
|
|
26
|
+
clientX: 10,
|
|
27
|
+
clientY: 10
|
|
28
|
+
});
|
|
29
|
+
hoverInteraction.handleHover(mouseEvent);
|
|
30
|
+
expect(callbackMock).toHaveBeenCalledWith(undefined, { nodes: [], relationships: [] }, mouseEvent);
|
|
31
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
32
|
+
});
|
|
33
|
+
it('should register hover event for node', () => {
|
|
34
|
+
const mouseEvent = new MouseEvent('mousemove', {
|
|
35
|
+
clientX: 100,
|
|
36
|
+
clientY: 100
|
|
37
|
+
});
|
|
38
|
+
hoverInteraction.handleHover(mouseEvent);
|
|
39
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', x: 100, y: 100, hovered: true }, {
|
|
40
|
+
nodes: [
|
|
41
|
+
{
|
|
42
|
+
data: { id: '0', x: 100, y: 100, hovered: true },
|
|
43
|
+
distance: 0,
|
|
44
|
+
targetCoordinates: { x: 100, y: 100 },
|
|
45
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
46
|
+
distanceVector: { x: 0, y: 0 },
|
|
47
|
+
insideNode: true
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
relationships: [
|
|
51
|
+
{
|
|
52
|
+
data: { id: '10', from: '0', to: '1' },
|
|
53
|
+
distance: 0,
|
|
54
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
55
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
56
|
+
pointerCoordinates: { x: 100, y: 100 }
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}, mouseEvent);
|
|
60
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
61
|
+
});
|
|
62
|
+
it('should register hover event for relationship', () => {
|
|
63
|
+
const mouseEvent = new MouseEvent('mousemove', {
|
|
64
|
+
clientX: 150,
|
|
65
|
+
clientY: 150
|
|
66
|
+
});
|
|
67
|
+
hoverInteraction.handleHover(mouseEvent);
|
|
68
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '10', from: '0', to: '1', hovered: true }, {
|
|
69
|
+
nodes: [],
|
|
70
|
+
relationships: [
|
|
71
|
+
{
|
|
72
|
+
data: { id: '10', from: '0', to: '1', hovered: true },
|
|
73
|
+
distance: 0,
|
|
74
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
75
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
76
|
+
pointerCoordinates: { x: 150, y: 150 }
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}, mouseEvent);
|
|
80
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
81
|
+
});
|
|
82
|
+
it('should register un-hover event for node', () => {
|
|
83
|
+
const mouseEvent = new MouseEvent('mousemove', {
|
|
84
|
+
clientX: 100,
|
|
85
|
+
clientY: 100
|
|
86
|
+
});
|
|
87
|
+
hoverInteraction.handleHover(mouseEvent);
|
|
88
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', x: 100, y: 100, hovered: true }, {
|
|
89
|
+
nodes: [
|
|
90
|
+
{
|
|
91
|
+
data: { id: '0', x: 100, y: 100, hovered: true },
|
|
92
|
+
distance: 0,
|
|
93
|
+
targetCoordinates: { x: 100, y: 100 },
|
|
94
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
95
|
+
distanceVector: { x: 0, y: 0 },
|
|
96
|
+
insideNode: true
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
relationships: [
|
|
100
|
+
{
|
|
101
|
+
data: { id: '10', from: '0', to: '1' },
|
|
102
|
+
distance: 0,
|
|
103
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
104
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
105
|
+
pointerCoordinates: { x: 100, y: 100 }
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}, mouseEvent);
|
|
109
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
110
|
+
const mouseEvent2 = new MouseEvent('mousemove', {
|
|
111
|
+
clientX: 10,
|
|
112
|
+
clientY: 10
|
|
113
|
+
});
|
|
114
|
+
hoverInteraction.handleHover(mouseEvent2);
|
|
115
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', x: 100, y: 100, hovered: false }, {
|
|
116
|
+
nodes: [
|
|
117
|
+
{
|
|
118
|
+
data: { id: '0', x: 100, y: 100, hovered: false },
|
|
119
|
+
distance: 0,
|
|
120
|
+
targetCoordinates: { x: 100, y: 100 },
|
|
121
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
122
|
+
distanceVector: { x: 0, y: 0 },
|
|
123
|
+
insideNode: true
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
relationships: [
|
|
127
|
+
{
|
|
128
|
+
data: { id: '10', from: '0', to: '1' },
|
|
129
|
+
distance: 0,
|
|
130
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
131
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
132
|
+
pointerCoordinates: { x: 100, y: 100 }
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
}, mouseEvent2);
|
|
136
|
+
expect(callbackMock).toHaveBeenCalledWith(undefined, { nodes: [], relationships: [] }, mouseEvent2);
|
|
137
|
+
expect(callbackMock).toHaveBeenCalledTimes(2);
|
|
138
|
+
});
|
|
139
|
+
it('should register un-hover event for relationship', () => {
|
|
140
|
+
const mouseEvent = new MouseEvent('mousemove', {
|
|
141
|
+
clientX: 150,
|
|
142
|
+
clientY: 150
|
|
143
|
+
});
|
|
144
|
+
hoverInteraction.handleHover(mouseEvent);
|
|
145
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '10', from: '0', to: '1', hovered: true }, {
|
|
146
|
+
nodes: [],
|
|
147
|
+
relationships: [
|
|
148
|
+
{
|
|
149
|
+
data: { id: '10', from: '0', to: '1', hovered: true },
|
|
150
|
+
distance: 0,
|
|
151
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
152
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
153
|
+
pointerCoordinates: { x: 150, y: 150 }
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}, mouseEvent);
|
|
157
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
158
|
+
const mouseEvent2 = new MouseEvent('mousemove', {
|
|
159
|
+
clientX: 10,
|
|
160
|
+
clientY: 10
|
|
161
|
+
});
|
|
162
|
+
hoverInteraction.handleHover(mouseEvent2);
|
|
163
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '10', from: '0', to: '1', hovered: false }, {
|
|
164
|
+
nodes: [],
|
|
165
|
+
relationships: [
|
|
166
|
+
{
|
|
167
|
+
data: { id: '10', from: '0', to: '1', hovered: false },
|
|
168
|
+
distance: 0,
|
|
169
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
170
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
171
|
+
pointerCoordinates: { x: 150, y: 150 }
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
}, mouseEvent2);
|
|
175
|
+
expect(callbackMock).toHaveBeenCalledWith(undefined, { nodes: [], relationships: [] }, mouseEvent2);
|
|
176
|
+
expect(callbackMock).toHaveBeenCalledTimes(2);
|
|
177
|
+
});
|
|
178
|
+
it('should un-hover node and hover relationships when moving mouse from node to relationship', () => {
|
|
179
|
+
const mouseEvent = new MouseEvent('mousemove', {
|
|
180
|
+
clientX: 100,
|
|
181
|
+
clientY: 100
|
|
182
|
+
});
|
|
183
|
+
hoverInteraction.handleHover(mouseEvent);
|
|
184
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', x: 100, y: 100, hovered: true }, {
|
|
185
|
+
nodes: [
|
|
186
|
+
{
|
|
187
|
+
data: { id: '0', x: 100, y: 100, hovered: true },
|
|
188
|
+
distance: 0,
|
|
189
|
+
targetCoordinates: { x: 100, y: 100 },
|
|
190
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
191
|
+
distanceVector: { x: 0, y: 0 },
|
|
192
|
+
insideNode: true
|
|
193
|
+
}
|
|
194
|
+
],
|
|
195
|
+
relationships: [
|
|
196
|
+
{
|
|
197
|
+
data: { id: '10', from: '0', to: '1' },
|
|
198
|
+
distance: 0,
|
|
199
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
200
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
201
|
+
pointerCoordinates: { x: 100, y: 100 }
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
}, mouseEvent);
|
|
205
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
206
|
+
const mouseEvent2 = new MouseEvent('mousemove', {
|
|
207
|
+
clientX: 150,
|
|
208
|
+
clientY: 150
|
|
209
|
+
});
|
|
210
|
+
hoverInteraction.handleHover(mouseEvent2);
|
|
211
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', x: 100, y: 100, hovered: false }, {
|
|
212
|
+
nodes: [
|
|
213
|
+
{
|
|
214
|
+
data: { id: '0', x: 100, y: 100, hovered: false },
|
|
215
|
+
distance: 0,
|
|
216
|
+
targetCoordinates: { x: 100, y: 100 },
|
|
217
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
218
|
+
distanceVector: { x: 0, y: 0 },
|
|
219
|
+
insideNode: true
|
|
220
|
+
}
|
|
221
|
+
],
|
|
222
|
+
relationships: [
|
|
223
|
+
{
|
|
224
|
+
data: { id: '10', from: '0', to: '1', hovered: true },
|
|
225
|
+
distance: 0,
|
|
226
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
227
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
228
|
+
pointerCoordinates: { x: 100, y: 100 }
|
|
229
|
+
}
|
|
230
|
+
]
|
|
231
|
+
}, mouseEvent2);
|
|
232
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '10', from: '0', to: '1', hovered: true }, {
|
|
233
|
+
nodes: [],
|
|
234
|
+
relationships: [
|
|
235
|
+
{
|
|
236
|
+
data: { id: '10', from: '0', to: '1', hovered: true },
|
|
237
|
+
distance: 0,
|
|
238
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
239
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
240
|
+
pointerCoordinates: { x: 150, y: 150 }
|
|
241
|
+
}
|
|
242
|
+
]
|
|
243
|
+
}, mouseEvent2);
|
|
244
|
+
expect(callbackMock).toHaveBeenCalledTimes(2);
|
|
245
|
+
});
|
|
246
|
+
it('should un-hover relationship and hover node when moving mouse from relationship to node', () => {
|
|
247
|
+
const mouseEvent = new MouseEvent('mousemove', {
|
|
248
|
+
clientX: 150,
|
|
249
|
+
clientY: 150
|
|
250
|
+
});
|
|
251
|
+
hoverInteraction.handleHover(mouseEvent);
|
|
252
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '10', from: '0', to: '1', hovered: true }, {
|
|
253
|
+
nodes: [],
|
|
254
|
+
relationships: [
|
|
255
|
+
{
|
|
256
|
+
data: { id: '10', from: '0', to: '1', hovered: true },
|
|
257
|
+
distance: 0,
|
|
258
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
259
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
260
|
+
pointerCoordinates: { x: 150, y: 150 }
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
}, mouseEvent);
|
|
264
|
+
expect(callbackMock).toHaveBeenCalledTimes(1);
|
|
265
|
+
const mouseEvent2 = new MouseEvent('mousemove', {
|
|
266
|
+
clientX: 100,
|
|
267
|
+
clientY: 100
|
|
268
|
+
});
|
|
269
|
+
hoverInteraction.handleHover(mouseEvent2);
|
|
270
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '0', x: 100, y: 100, hovered: true }, {
|
|
271
|
+
nodes: [
|
|
272
|
+
{
|
|
273
|
+
data: { id: '0', x: 100, y: 100, hovered: true },
|
|
274
|
+
distance: 0,
|
|
275
|
+
targetCoordinates: { x: 100, y: 100 },
|
|
276
|
+
pointerCoordinates: { x: 100, y: 100 },
|
|
277
|
+
distanceVector: { x: 0, y: 0 },
|
|
278
|
+
insideNode: true
|
|
279
|
+
}
|
|
280
|
+
],
|
|
281
|
+
relationships: [
|
|
282
|
+
{
|
|
283
|
+
data: { id: '10', from: '0', to: '1', hovered: false },
|
|
284
|
+
distance: 0,
|
|
285
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
286
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
287
|
+
pointerCoordinates: { x: 100, y: 100 }
|
|
288
|
+
}
|
|
289
|
+
]
|
|
290
|
+
}, mouseEvent2);
|
|
291
|
+
expect(callbackMock).toHaveBeenCalledWith({ id: '10', from: '0', to: '1', hovered: false }, {
|
|
292
|
+
nodes: [],
|
|
293
|
+
relationships: [
|
|
294
|
+
{
|
|
295
|
+
data: { id: '10', from: '0', to: '1', hovered: false },
|
|
296
|
+
distance: 0,
|
|
297
|
+
fromTargetCoordinates: { x: 100, y: 100 },
|
|
298
|
+
toTargetCoordinates: { x: 200, y: 200 },
|
|
299
|
+
pointerCoordinates: { x: 150, y: 150 }
|
|
300
|
+
}
|
|
301
|
+
]
|
|
302
|
+
}, mouseEvent2);
|
|
303
|
+
expect(callbackMock).toHaveBeenCalledTimes(2);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import NVL from '@neo4j-nvl/base';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
import { LassoInteraction } from '../interaction-handlers/lasso-interaction';
|
|
4
|
+
jest.mock('@neo4j-nvl/layout-workers');
|
|
5
|
+
const testNodes = [
|
|
6
|
+
{ id: '0', x: 10, y: 10 },
|
|
7
|
+
{ id: '1', x: 200, y: 200 }
|
|
8
|
+
];
|
|
9
|
+
const testRels = [{ id: '10', from: '0', to: '1' }];
|
|
10
|
+
const createMouseEvent = (type, x, y) => {
|
|
11
|
+
return new MouseEvent(type, { button: 0, buttons: 1, clientX: x, clientY: y });
|
|
12
|
+
};
|
|
13
|
+
describe('LassoInteraction', () => {
|
|
14
|
+
let lassoInteraction;
|
|
15
|
+
let myNVL;
|
|
16
|
+
const startCallback = jest.fn();
|
|
17
|
+
const selectCallback = jest.fn();
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
myNVL = new NVL(document.createElement('div'), testNodes, testRels, {
|
|
20
|
+
disableWebGL: true,
|
|
21
|
+
initialZoom: 1,
|
|
22
|
+
layout: 'free'
|
|
23
|
+
});
|
|
24
|
+
lassoInteraction = new LassoInteraction(myNVL);
|
|
25
|
+
});
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
lassoInteraction.destroy();
|
|
28
|
+
myNVL.destroy();
|
|
29
|
+
startCallback.mockReset();
|
|
30
|
+
selectCallback.mockReset();
|
|
31
|
+
});
|
|
32
|
+
test('can select individual nodes', () => {
|
|
33
|
+
lassoInteraction.updateCallback('onLassoStarted', startCallback);
|
|
34
|
+
lassoInteraction.updateCallback('onLassoSelect', selectCallback);
|
|
35
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
36
|
+
const gesture1 = [
|
|
37
|
+
createMouseEvent('mousedown', 0, 0),
|
|
38
|
+
createMouseEvent('mousemove', 30, 0),
|
|
39
|
+
createMouseEvent('mousemove', 20, 20),
|
|
40
|
+
createMouseEvent('mouseup', 0, 0)
|
|
41
|
+
];
|
|
42
|
+
const gesture2 = [
|
|
43
|
+
createMouseEvent('mousedown', 200, 180),
|
|
44
|
+
createMouseEvent('mousemove', 210, 210),
|
|
45
|
+
createMouseEvent('mouseup', 190, 210)
|
|
46
|
+
];
|
|
47
|
+
const container = myNVL.getContainer();
|
|
48
|
+
gesture1.forEach((e) => container.dispatchEvent(e));
|
|
49
|
+
gesture2.forEach((e) => container.dispatchEvent(e));
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
expect(startCallback).toHaveBeenCalledTimes(2);
|
|
52
|
+
expect(selectCallback).toHaveBeenCalledTimes(2);
|
|
53
|
+
expect(selectCallback).toHaveBeenNthCalledWith(1, { nodes: [testNodes[0]], rels: [] }, gesture1[3]);
|
|
54
|
+
expect(selectCallback).toHaveBeenNthCalledWith(2, { nodes: [testNodes[1]], rels: [] }, gesture2[2]);
|
|
55
|
+
resolve();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
test('can select relationships', () => {
|
|
59
|
+
lassoInteraction.updateCallback('onLassoStarted', startCallback);
|
|
60
|
+
lassoInteraction.updateCallback('onLassoSelect', selectCallback);
|
|
61
|
+
expect(myNVL.getSelectedNodes()).toHaveLength(0);
|
|
62
|
+
const gesture = [
|
|
63
|
+
createMouseEvent('mousedown', 0, 0),
|
|
64
|
+
createMouseEvent('mousemove', 250, 0),
|
|
65
|
+
createMouseEvent('mousemove', 240, 240),
|
|
66
|
+
createMouseEvent('mousemove', 100, 200),
|
|
67
|
+
createMouseEvent('mousemove', 50, 0),
|
|
68
|
+
createMouseEvent('mouseup', 0, 0)
|
|
69
|
+
];
|
|
70
|
+
const container = myNVL.getContainer();
|
|
71
|
+
gesture.forEach((e) => container.dispatchEvent(e));
|
|
72
|
+
return new Promise((resolve) => {
|
|
73
|
+
expect(startCallback).toHaveBeenCalledTimes(1);
|
|
74
|
+
expect(selectCallback).toHaveBeenCalledTimes(1);
|
|
75
|
+
expect(selectCallback).toHaveBeenCalledWith({ nodes: [testNodes[0], testNodes[1]], rels: [testRels[0]] }, gesture[5]);
|
|
76
|
+
resolve();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -39,13 +39,13 @@ class BaseInteraction {
|
|
|
39
39
|
* @internal
|
|
40
40
|
*/
|
|
41
41
|
addEventListener = (type, listener, options) => {
|
|
42
|
-
this.container
|
|
42
|
+
this.container?.addEventListener(type, listener, options);
|
|
43
43
|
};
|
|
44
44
|
/**
|
|
45
45
|
* @internal
|
|
46
46
|
*/
|
|
47
47
|
removeEventListener = (type, listener, options) => {
|
|
48
|
-
this.container
|
|
48
|
+
this.container?.removeEventListener(type, listener, options);
|
|
49
49
|
};
|
|
50
50
|
/**
|
|
51
51
|
* @internal
|
|
@@ -33,12 +33,16 @@ export type BoxSelectInteractionCallbacks = {
|
|
|
33
33
|
*
|
|
34
34
|
* @example
|
|
35
35
|
* ```js
|
|
36
|
-
*
|
|
36
|
+
* import { BoxSelectInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
37
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
38
|
+
*
|
|
39
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
37
40
|
* const boxSelectInteraction = new BoxSelectInteraction(nvl)
|
|
38
41
|
*
|
|
39
42
|
* boxSelectInteraction.updateCallback('onBoxSelect', ({ nodes, rels }) => {
|
|
40
43
|
* console.log('Selected elements:', nodes, rels)
|
|
41
44
|
* })
|
|
45
|
+
* ```
|
|
42
46
|
*/
|
|
43
47
|
export declare class BoxSelectInteraction extends BaseInteraction<BoxSelectInteractionCallbacks, BoxSelectInteractionOptions> {
|
|
44
48
|
private mousePosition;
|
|
@@ -9,12 +9,16 @@ import { getCanvasPosition, getWorldPosition } from './utils';
|
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```js
|
|
12
|
-
*
|
|
12
|
+
* import { BoxSelectInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
13
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
14
|
+
*
|
|
15
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
13
16
|
* const boxSelectInteraction = new BoxSelectInteraction(nvl)
|
|
14
17
|
*
|
|
15
18
|
* boxSelectInteraction.updateCallback('onBoxSelect', ({ nodes, rels }) => {
|
|
16
19
|
* console.log('Selected elements:', nodes, rels)
|
|
17
20
|
* })
|
|
21
|
+
* ```
|
|
18
22
|
*/
|
|
19
23
|
export class BoxSelectInteraction extends BaseInteraction {
|
|
20
24
|
mousePosition;
|
|
@@ -81,7 +81,7 @@ export type ClickInteractionCallbacks = {
|
|
|
81
81
|
* import { ClickInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
82
82
|
* import { NVL } from '@neo4j-nvl/base'
|
|
83
83
|
*
|
|
84
|
-
* const nvl = new NVL(
|
|
84
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
85
85
|
* const clickInteraction = new ClickInteraction(nvl)
|
|
86
86
|
* clickInteraction.updateCallback('onNodeClick', (node) => {
|
|
87
87
|
* console.log('Node clicked', node)
|
|
@@ -9,7 +9,7 @@ import { isDraggingMovement } from './utils';
|
|
|
9
9
|
* import { ClickInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
10
10
|
* import { NVL } from '@neo4j-nvl/base'
|
|
11
11
|
*
|
|
12
|
-
* const nvl = new NVL(
|
|
12
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
13
13
|
* const clickInteraction = new ClickInteraction(nvl)
|
|
14
14
|
* clickInteraction.updateCallback('onNodeClick', (node) => {
|
|
15
15
|
* console.log('Node clicked', node)
|
|
@@ -30,7 +30,10 @@ export type DragNodeInteractionCallbacks = {
|
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
32
|
* ```js
|
|
33
|
-
*
|
|
33
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
34
|
+
* import { DragNodeInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
35
|
+
*
|
|
36
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
34
37
|
* const dragNodeInteraction = new DragNodeInteraction(nvl)
|
|
35
38
|
*
|
|
36
39
|
* dragNodeInteraction.updateCallback('onDrag', (nodes) => {
|
|
@@ -8,7 +8,10 @@ import { isDraggingMovement } from './utils';
|
|
|
8
8
|
*
|
|
9
9
|
* @example
|
|
10
10
|
* ```js
|
|
11
|
-
*
|
|
11
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
12
|
+
* import { DragNodeInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
13
|
+
*
|
|
14
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
12
15
|
* const dragNodeInteraction = new DragNodeInteraction(nvl)
|
|
13
16
|
*
|
|
14
17
|
* dragNodeInteraction.updateCallback('onDrag', (nodes) => {
|
|
@@ -29,7 +29,12 @@ export declare class DrawInteraction extends BaseInteraction<DrawInteractionCall
|
|
|
29
29
|
private newTempSelfReferredRelationship;
|
|
30
30
|
private newTargetNodeToAdd;
|
|
31
31
|
private newRelationshipToAdd;
|
|
32
|
+
private mouseOutsideOfNvlArea;
|
|
32
33
|
constructor(nvl: NVL, options?: DrawInteractionOptions);
|
|
34
|
+
private cancelDrawing;
|
|
35
|
+
private handleMouseUpGlobal;
|
|
36
|
+
private handleMouseLeaveNvl;
|
|
37
|
+
private handleMouseEnterNvl;
|
|
33
38
|
private handleMouseMove;
|
|
34
39
|
private setNewRegularRelationship;
|
|
35
40
|
private setNewRegularRelationshipToNewTempTargetNode;
|
|
@@ -27,6 +27,7 @@ export class DrawInteraction extends BaseInteraction {
|
|
|
27
27
|
newTempSelfReferredRelationship;
|
|
28
28
|
newTargetNodeToAdd;
|
|
29
29
|
newRelationshipToAdd;
|
|
30
|
+
mouseOutsideOfNvlArea;
|
|
30
31
|
constructor(nvl, options = {}) {
|
|
31
32
|
super(nvl, options);
|
|
32
33
|
this.isMoved = false;
|
|
@@ -36,7 +37,37 @@ export class DrawInteraction extends BaseInteraction {
|
|
|
36
37
|
this.addEventListener('mousemove', this.handleMouseMove, true);
|
|
37
38
|
this.addEventListener('mousedown', this.handleMouseDown, true);
|
|
38
39
|
this.addEventListener('mouseup', this.handleMouseUp, true);
|
|
40
|
+
this.containerInstance?.addEventListener('mouseleave', this.handleMouseLeaveNvl);
|
|
41
|
+
this.containerInstance?.addEventListener('mouseenter', this.handleMouseEnterNvl);
|
|
42
|
+
document.addEventListener('mouseup', this.handleMouseUpGlobal, true);
|
|
39
43
|
}
|
|
44
|
+
cancelDrawing = () => {
|
|
45
|
+
this.nvlInstance.removeRelationshipsWithIds([
|
|
46
|
+
this.newTempRegularRelationshipToNewTempTargetNode?.id,
|
|
47
|
+
this.newTempRegularRelationshipToExistingNode?.id,
|
|
48
|
+
this.newTempSelfReferredRelationship?.id
|
|
49
|
+
].filter((id) => Boolean(id)));
|
|
50
|
+
this.nvlInstance.removeNodesWithIds(this.newTempTargetNode?.id ? [this.newTempTargetNode?.id] : []);
|
|
51
|
+
this.newTempTargetNode = null;
|
|
52
|
+
this.newTempRegularRelationshipToNewTempTargetNode = null;
|
|
53
|
+
this.newTempRegularRelationshipToExistingNode = null;
|
|
54
|
+
this.newTempSelfReferredRelationship = null;
|
|
55
|
+
this.isMoved = false;
|
|
56
|
+
this.isDrawing = false;
|
|
57
|
+
this.isDraggingNode = false;
|
|
58
|
+
};
|
|
59
|
+
handleMouseUpGlobal = (event) => {
|
|
60
|
+
// If mouse up outside of nvl area while drawing, cancel drawing.
|
|
61
|
+
if (this.isDrawing && this.mouseOutsideOfNvlArea) {
|
|
62
|
+
this.cancelDrawing();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
handleMouseLeaveNvl = () => {
|
|
66
|
+
this.mouseOutsideOfNvlArea = true;
|
|
67
|
+
};
|
|
68
|
+
handleMouseEnterNvl = () => {
|
|
69
|
+
this.mouseOutsideOfNvlArea = false;
|
|
70
|
+
};
|
|
40
71
|
handleMouseMove = (event) => {
|
|
41
72
|
this.isMoved = true;
|
|
42
73
|
if (this.isDrawing) {
|
|
@@ -174,11 +205,19 @@ export class DrawInteraction extends BaseInteraction {
|
|
|
174
205
|
const hits = this.nvlInstance.getHits(event, ['node'], { hitNodeMarginWidth: NODE_EDGE_WIDTH });
|
|
175
206
|
const hitNodes = hits.nvlTargets.nodes.filter((node) => node.insideNode);
|
|
176
207
|
const hitNodeEdges = hits.nvlTargets.nodes.filter((node) => !node.insideNode);
|
|
177
|
-
|
|
208
|
+
const startDragging = hitNodes.length > 0;
|
|
209
|
+
const startDrawing = hitNodeEdges.length > 0;
|
|
210
|
+
if (startDragging || startDrawing) {
|
|
211
|
+
// Prevent default behavior to avoid interactions with other elements outside of nvl, like text selection,
|
|
212
|
+
// but still assign focus to nvl container on click
|
|
213
|
+
event.preventDefault();
|
|
214
|
+
this.containerInstance?.focus();
|
|
215
|
+
}
|
|
216
|
+
if (startDragging) {
|
|
178
217
|
this.isDraggingNode = true;
|
|
179
218
|
this.isDrawing = false;
|
|
180
219
|
}
|
|
181
|
-
else if (
|
|
220
|
+
else if (startDrawing) {
|
|
182
221
|
this.isDrawing = true;
|
|
183
222
|
this.isDraggingNode = false;
|
|
184
223
|
this.mouseDownNode = hitNodeEdges[0];
|
|
@@ -237,5 +276,8 @@ export class DrawInteraction extends BaseInteraction {
|
|
|
237
276
|
this.removeEventListener('mousemove', this.handleMouseMove, true);
|
|
238
277
|
this.removeEventListener('mousedown', this.handleMouseDown, true);
|
|
239
278
|
this.removeEventListener('mouseup', this.handleMouseUp, true);
|
|
279
|
+
this.containerInstance?.removeEventListener('mouseleave', this.handleMouseLeaveNvl);
|
|
280
|
+
this.containerInstance?.removeEventListener('mouseenter', this.handleMouseEnterNvl);
|
|
281
|
+
document.removeEventListener('mouseup', this.handleMouseUpGlobal, true);
|
|
240
282
|
};
|
|
241
283
|
}
|
|
@@ -28,8 +28,11 @@ export type HoverInteractionCallbacks = {
|
|
|
28
28
|
* Interaction handler for hovering nodes and relationships.
|
|
29
29
|
*
|
|
30
30
|
* @example
|
|
31
|
-
* ```
|
|
32
|
-
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
33
|
+
* import { HoverInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
34
|
+
*
|
|
35
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
33
36
|
* const hoverInteraction = new HoverInteraction(nvl)
|
|
34
37
|
*
|
|
35
38
|
* hoverInteraction.updateCallback('onHover', (element, hitElements, event) => {
|
|
@@ -3,8 +3,11 @@ import { BaseInteraction } from './base';
|
|
|
3
3
|
* Interaction handler for hovering nodes and relationships.
|
|
4
4
|
*
|
|
5
5
|
* @example
|
|
6
|
-
* ```
|
|
7
|
-
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
8
|
+
* import { HoverInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
9
|
+
*
|
|
10
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
8
11
|
* const hoverInteraction = new HoverInteraction(nvl)
|
|
9
12
|
*
|
|
10
13
|
* hoverInteraction.updateCallback('onHover', (element, hitElements, event) => {
|
|
@@ -33,7 +36,7 @@ export class HoverInteraction extends BaseInteraction {
|
|
|
33
36
|
handleHover = (event) => {
|
|
34
37
|
const { nvlTargets } = this.nvlInstance.getHits(event);
|
|
35
38
|
const { nodes = [], relationships = [] } = nvlTargets;
|
|
36
|
-
const mainTarget = nodes[0]
|
|
39
|
+
const mainTarget = nodes[0] ?? relationships[0];
|
|
37
40
|
const hoveredElement = mainTarget?.data;
|
|
38
41
|
if (this.currentElementNeedsUnHover(hoveredElement?.id)) {
|
|
39
42
|
this.unHoverCurrentElement();
|
|
@@ -32,13 +32,17 @@ export type LassoInteractionCallbacks = {
|
|
|
32
32
|
* area will be selected.
|
|
33
33
|
*
|
|
34
34
|
* @example
|
|
35
|
-
* ```
|
|
36
|
-
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
37
|
+
* import { LassoInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
38
|
+
*
|
|
39
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
37
40
|
* const lassoInteraction = new LassoInteraction(nvl)
|
|
38
41
|
*
|
|
39
42
|
* lassoInteraction.updateCallback('onLassoSelect', ({ nodes, rels }) => {
|
|
40
43
|
* console.log('Selected elements:', nodes, rels)
|
|
41
44
|
* })
|
|
45
|
+
* ```
|
|
42
46
|
*/
|
|
43
47
|
export declare class LassoInteraction extends BaseInteraction<LassoInteractionCallbacks, LassoInteractionOptions> {
|
|
44
48
|
private active;
|
|
@@ -10,13 +10,17 @@ const shapeShowTime = 500;
|
|
|
10
10
|
* area will be selected.
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
|
-
* ```
|
|
14
|
-
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
15
|
+
* import { LassoInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
16
|
+
*
|
|
17
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
15
18
|
* const lassoInteraction = new LassoInteraction(nvl)
|
|
16
19
|
*
|
|
17
20
|
* lassoInteraction.updateCallback('onLassoSelect', ({ nodes, rels }) => {
|
|
18
21
|
* console.log('Selected elements:', nodes, rels)
|
|
19
22
|
* })
|
|
23
|
+
* ```
|
|
20
24
|
*/
|
|
21
25
|
export class LassoInteraction extends BaseInteraction {
|
|
22
26
|
active;
|
|
@@ -30,12 +30,16 @@ export type PanInteractionCallbacks = {
|
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
32
|
* ```js
|
|
33
|
-
*
|
|
33
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
34
|
+
* import { PanInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
35
|
+
*
|
|
36
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
34
37
|
* const panInteraction = new PanInteraction(nvl)
|
|
35
38
|
*
|
|
36
39
|
* panInteraction.updateCallback('onPan', (panning) => {
|
|
37
40
|
* console.log('Panning:', panning)
|
|
38
41
|
* })
|
|
42
|
+
* ```
|
|
39
43
|
*/
|
|
40
44
|
export declare class PanInteraction extends BaseInteraction<PanInteractionCallbacks, PanInteractionOptions> {
|
|
41
45
|
private mousePosition;
|
|
@@ -54,6 +58,12 @@ export declare class PanInteraction extends BaseInteraction<PanInteractionCallba
|
|
|
54
58
|
*
|
|
55
59
|
* @example
|
|
56
60
|
* ```js
|
|
61
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
62
|
+
* import { PanInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
63
|
+
*
|
|
64
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
65
|
+
* const panInteraction = new PanInteraction(nvl)
|
|
66
|
+
*
|
|
57
67
|
* // Pan canvas even when dragging on nodes and relationships
|
|
58
68
|
* panInteraction.updateTargets([], true)
|
|
59
69
|
* ```
|
|
@@ -7,12 +7,16 @@ import { BaseInteraction } from './base';
|
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```js
|
|
10
|
-
*
|
|
10
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
11
|
+
* import { PanInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
12
|
+
*
|
|
13
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
11
14
|
* const panInteraction = new PanInteraction(nvl)
|
|
12
15
|
*
|
|
13
16
|
* panInteraction.updateCallback('onPan', (panning) => {
|
|
14
17
|
* console.log('Panning:', panning)
|
|
15
18
|
* })
|
|
19
|
+
* ```
|
|
16
20
|
*/
|
|
17
21
|
export class PanInteraction extends BaseInteraction {
|
|
18
22
|
mousePosition;
|
|
@@ -39,6 +43,12 @@ export class PanInteraction extends BaseInteraction {
|
|
|
39
43
|
*
|
|
40
44
|
* @example
|
|
41
45
|
* ```js
|
|
46
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
47
|
+
* import { PanInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
48
|
+
*
|
|
49
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
50
|
+
* const panInteraction = new PanInteraction(nvl)
|
|
51
|
+
*
|
|
42
52
|
* // Pan canvas even when dragging on nodes and relationships
|
|
43
53
|
* panInteraction.updateTargets([], true)
|
|
44
54
|
* ```
|
|
@@ -17,7 +17,10 @@ export type ZoomInteractionCallbacks = {
|
|
|
17
17
|
*
|
|
18
18
|
* @example
|
|
19
19
|
* ```js
|
|
20
|
-
*
|
|
20
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
21
|
+
* import { ZoomInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
22
|
+
*
|
|
23
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
21
24
|
* const zoomInteraction = new ZoomInteraction(nvl)
|
|
22
25
|
*
|
|
23
26
|
* zoomInteraction.updateCallback('onZoom', (zoomLevel) => {
|
|
@@ -7,7 +7,10 @@ import { getCanvasCenterOffset } from './utils';
|
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```js
|
|
10
|
-
*
|
|
10
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
11
|
+
* import { ZoomInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
12
|
+
*
|
|
13
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
11
14
|
* const zoomInteraction = new ZoomInteraction(nvl)
|
|
12
15
|
*
|
|
13
16
|
* zoomInteraction.updateCallback('onZoom', (zoomLevel) => {
|
|
@@ -18,15 +18,15 @@ export class OverlayRenderer {
|
|
|
18
18
|
canvas.style.right = '0';
|
|
19
19
|
// These are needed for touchpad zoom on Edge
|
|
20
20
|
canvas.style.touchAction = 'none';
|
|
21
|
-
canvasParent
|
|
21
|
+
canvasParent?.appendChild(canvas);
|
|
22
22
|
const context = canvas.getContext('2d');
|
|
23
23
|
this.ctx = context;
|
|
24
24
|
this.canvas = canvas;
|
|
25
25
|
const handleResize = () => {
|
|
26
26
|
this.fixCanvasSize(canvas);
|
|
27
27
|
};
|
|
28
|
-
canvasParent
|
|
29
|
-
this.removeResizeListener = () => canvasParent
|
|
28
|
+
canvasParent?.addEventListener('resize', handleResize);
|
|
29
|
+
this.removeResizeListener = () => canvasParent?.removeEventListener('resize', handleResize);
|
|
30
30
|
this.fixCanvasSize(canvas);
|
|
31
31
|
}
|
|
32
32
|
fixCanvasSize(canvas) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neo4j-nvl/interaction-handlers",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2-e0e72a58",
|
|
4
4
|
"license": "SEE LICENSE IN 'LICENSE.txt'",
|
|
5
|
+
"homepage": "https://neo4j.com/docs/nvl/current/",
|
|
6
|
+
"description": "Interaction handlers for the Neo4j Visualization Library",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"neo4j",
|
|
9
|
+
"visualization",
|
|
10
|
+
"graph"
|
|
11
|
+
],
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://community.neo4j.com/c/neo4j-graph-platform/neo4j-bloom"
|
|
14
|
+
},
|
|
5
15
|
"main": "lib/index.js",
|
|
6
16
|
"types": "lib/index.d.ts",
|
|
7
17
|
"files": [
|
|
@@ -10,9 +20,11 @@
|
|
|
10
20
|
],
|
|
11
21
|
"scripts": {
|
|
12
22
|
"build": "tsc",
|
|
23
|
+
"watch": "tsc -w",
|
|
13
24
|
"test": "jest",
|
|
14
25
|
"prepack": "cp ../../LICENSE.txt ./",
|
|
15
|
-
"postpack": "rm LICENSE.txt"
|
|
26
|
+
"postpack": "rm LICENSE.txt",
|
|
27
|
+
"eslint": "eslint ./src/"
|
|
16
28
|
},
|
|
17
29
|
"typedoc": {
|
|
18
30
|
"entryPoint": "./src/index.ts",
|
|
@@ -21,7 +33,7 @@
|
|
|
21
33
|
"tsconfig": "./tsconfig.json"
|
|
22
34
|
},
|
|
23
35
|
"dependencies": {
|
|
24
|
-
"@neo4j-nvl/base": "^0.3.
|
|
36
|
+
"@neo4j-nvl/base": "^0.3.2-e0e72a58",
|
|
25
37
|
"concaveman": "^1.2.1",
|
|
26
38
|
"lodash": "4.17.21"
|
|
27
39
|
},
|
|
@@ -30,11 +42,14 @@
|
|
|
30
42
|
"@testing-library/react": "^13.4.0",
|
|
31
43
|
"@types/concaveman": "1.1.6",
|
|
32
44
|
"@types/lodash": "4.14.202",
|
|
45
|
+
"eslint": "8.38.0",
|
|
33
46
|
"jest": "^29.7.0",
|
|
34
47
|
"typescript": "^5.4.5"
|
|
35
48
|
},
|
|
36
49
|
"peerDependencies": {
|
|
50
|
+
"eslint": "*",
|
|
37
51
|
"jest": "*",
|
|
38
52
|
"typescript": "*"
|
|
39
|
-
}
|
|
53
|
+
},
|
|
54
|
+
"stableVersion": "0.3.2"
|
|
40
55
|
}
|