@neo4j-nvl/interaction-handlers 0.3.3 → 0.3.4-c75037f2
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 +4 -5
- package/lib/__tests__/lasso-interaction.test.js +54 -2
- package/lib/interaction-handlers/box-select-interaction.d.ts +3 -15
- package/lib/interaction-handlers/box-select-interaction.js +3 -15
- package/lib/interaction-handlers/click-interaction.d.ts +2 -12
- package/lib/interaction-handlers/click-interaction.js +2 -12
- package/lib/interaction-handlers/drag-node-interaction.d.ts +4 -15
- package/lib/interaction-handlers/drag-node-interaction.js +4 -15
- package/lib/interaction-handlers/draw-interaction.d.ts +2 -3
- package/lib/interaction-handlers/draw-interaction.js +2 -2
- package/lib/interaction-handlers/hover-interaction.d.ts +2 -15
- package/lib/interaction-handlers/hover-interaction.js +1 -14
- package/lib/interaction-handlers/lasso-interaction.d.ts +23 -16
- package/lib/interaction-handlers/lasso-interaction.js +63 -36
- package/lib/interaction-handlers/pan-interaction.d.ts +3 -15
- package/lib/interaction-handlers/pan-interaction.js +3 -15
- package/lib/interaction-handlers/zoom-interaction.d.ts +4 -16
- package/lib/interaction-handlers/zoom-interaction.js +4 -16
- package/package.json +4 -9
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Neo4j Visualization Library
|
|
2
2
|
|
|
3
|
-
Welcome to
|
|
3
|
+
Welcome to the Neo4j Visualization Library, NVL for short. NVL is a collection of libraries that can be used to build custom graph visualizations like those used in [Neo4j Bloom and Explore(powered by Bloom)](https://neo4j.com/product/bloom/). NVL is written in TypeScript and can be used in any JavaScript project. It is also available as a React component that can be used in React applications.
|
|
4
4
|
|
|
5
|
-
This module is a collection of decorator classes that can be used to add interaction events to an NVL instance. The decorators are applied to the NVL class. You can find more information about the NVL class in the base library
|
|
5
|
+
This module is a collection of decorator classes that can be used to add interaction events to an NVL instance. The decorators are applied to the NVL class. You can find more information about the NVL class in the [NVL base library](https://www.npmjs.com/package/@neo4j-nvl/base).
|
|
6
6
|
|
|
7
7
|
## Consuming the library
|
|
8
8
|
|
|
@@ -14,13 +14,12 @@ You can install the interaction handlers with your preferred package manager, fo
|
|
|
14
14
|
npm install @neo4j-nvl/interaction-handlers
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
If you are planning to use NVL in a React app, be sure to check out the NVL React wrappers.
|
|
17
|
+
If you are planning to use NVL in a React app, be sure to check out the [NVL React wrappers](https://www.npmjs.com/package/@neo4j-nvl/react).
|
|
18
18
|
|
|
19
19
|
### Using the library
|
|
20
20
|
|
|
21
21
|
Heres is an example on how to use an interaction handler with the NVL class:
|
|
22
22
|
|
|
23
|
-
|
|
24
23
|
```ts
|
|
25
24
|
import { ClickInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
26
25
|
import { NVL } from '@neo4j-nvl/base'
|
|
@@ -34,4 +33,4 @@ clickInteraction.updateCallback('onNodeClick', (node) => {
|
|
|
34
33
|
|
|
35
34
|
If you are using React and want to add interactivity to your graph, you can also make use of the InteractiveReactWrapper.
|
|
36
35
|
|
|
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/).
|
|
36
|
+
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/).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import NVL from '@neo4j-nvl/base';
|
|
2
2
|
import '@testing-library/jest-dom';
|
|
3
|
-
import { LassoInteraction } from '../interaction-handlers/lasso-interaction';
|
|
3
|
+
import { LassoInteraction, checkIntersection, checkLinesCrossing, checkPointInside } from '../interaction-handlers/lasso-interaction';
|
|
4
4
|
jest.mock('@neo4j-nvl/layout-workers');
|
|
5
5
|
const testNodes = [
|
|
6
6
|
{ id: '0', x: 10, y: 10 },
|
|
@@ -64,7 +64,7 @@ describe('LassoInteraction', () => {
|
|
|
64
64
|
createMouseEvent('mousemove', 250, 0),
|
|
65
65
|
createMouseEvent('mousemove', 240, 240),
|
|
66
66
|
createMouseEvent('mousemove', 100, 200),
|
|
67
|
-
createMouseEvent('mousemove',
|
|
67
|
+
createMouseEvent('mousemove', 0, 50),
|
|
68
68
|
createMouseEvent('mouseup', 0, 0)
|
|
69
69
|
];
|
|
70
70
|
const container = myNVL.getContainer();
|
|
@@ -76,4 +76,56 @@ describe('LassoInteraction', () => {
|
|
|
76
76
|
resolve();
|
|
77
77
|
});
|
|
78
78
|
});
|
|
79
|
+
test('test for line crossing utility function', () => {
|
|
80
|
+
const res1 = checkLinesCrossing([0, 0], [10, 10], [10, 0], [0, 10]);
|
|
81
|
+
expect(res1).toBeTruthy();
|
|
82
|
+
const res2 = checkLinesCrossing([10, 10], [227, 182], [390, 10], [100, 100]);
|
|
83
|
+
expect(res2).toBeTruthy();
|
|
84
|
+
const res3 = checkLinesCrossing([5, 5], [5, 20], [10, 10], [20, 10]);
|
|
85
|
+
expect(res3).toBeFalsy();
|
|
86
|
+
const res4 = checkLinesCrossing([10, 10], [20, 10], [15, 10], [25, 10]);
|
|
87
|
+
expect(res4).toBeFalsy();
|
|
88
|
+
const res5 = checkLinesCrossing([880, 416], [872, 404], [868, 392], [856, 378]);
|
|
89
|
+
expect(res5).toBeFalsy();
|
|
90
|
+
});
|
|
91
|
+
test('test for line segment crossing utility function', () => {
|
|
92
|
+
const res1 = checkIntersection([
|
|
93
|
+
[0, 0],
|
|
94
|
+
[10, 0],
|
|
95
|
+
[100, 10],
|
|
96
|
+
[50, 10],
|
|
97
|
+
[50, -10]
|
|
98
|
+
]);
|
|
99
|
+
expect(res1).toBeTruthy();
|
|
100
|
+
const res2 = checkIntersection([
|
|
101
|
+
[10, 10],
|
|
102
|
+
[227, 182],
|
|
103
|
+
[390, 10],
|
|
104
|
+
[500, 100]
|
|
105
|
+
]);
|
|
106
|
+
expect(res2).toBeTruthy();
|
|
107
|
+
const res3 = checkIntersection([
|
|
108
|
+
[50, 10],
|
|
109
|
+
[10, 10],
|
|
110
|
+
[10, 50],
|
|
111
|
+
[50, 50]
|
|
112
|
+
]);
|
|
113
|
+
expect(res3).toBeFalsy();
|
|
114
|
+
});
|
|
115
|
+
test('test for point inside polygon utility function', () => {
|
|
116
|
+
const res1 = checkPointInside(10, 10, [
|
|
117
|
+
{ x: 0, y: 0 },
|
|
118
|
+
{ x: 10, y: -10 },
|
|
119
|
+
{ x: 20, y: 0 },
|
|
120
|
+
{ x: 10, y: 20 }
|
|
121
|
+
]);
|
|
122
|
+
expect(res1).toBeTruthy();
|
|
123
|
+
const res2 = checkPointInside(10, 10, [
|
|
124
|
+
{ x: 0, y: 0 },
|
|
125
|
+
{ x: 10, y: -10 },
|
|
126
|
+
{ x: 20, y: 0 },
|
|
127
|
+
{ x: 10, y: 5 }
|
|
128
|
+
]);
|
|
129
|
+
expect(res2).toBeFalsy();
|
|
130
|
+
});
|
|
79
131
|
});
|
|
@@ -27,22 +27,10 @@ export type BoxSelectInteractionCallbacks = {
|
|
|
27
27
|
}, event: MouseEvent) => void) | boolean;
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
31
|
-
* When dragging, draws a box on the
|
|
32
|
-
* nodes and relationships that are inside the box.
|
|
30
|
+
* An interaction handler for multi-selecting nodes and relationships.
|
|
31
|
+
* When dragging the cursor, it draws a box on the scene and all nodes and relationships inside the box are selected.
|
|
33
32
|
*
|
|
34
|
-
* @
|
|
35
|
-
* ```js
|
|
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' }], [])
|
|
40
|
-
* const boxSelectInteraction = new BoxSelectInteraction(nvl)
|
|
41
|
-
*
|
|
42
|
-
* boxSelectInteraction.updateCallback('onBoxSelect', ({ nodes, rels }) => {
|
|
43
|
-
* console.log('Selected elements:', nodes, rels)
|
|
44
|
-
* })
|
|
45
|
-
* ```
|
|
33
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_boxselectinteraction Box Select Interaction documentation page}.
|
|
46
34
|
*/
|
|
47
35
|
export declare class BoxSelectInteraction extends BaseInteraction<BoxSelectInteractionCallbacks, BoxSelectInteractionOptions> {
|
|
48
36
|
private mousePosition;
|
|
@@ -3,22 +3,10 @@ import { OverlayRenderer } from '../overlay-renderer/overlay-renderer';
|
|
|
3
3
|
import { BaseInteraction } from './base';
|
|
4
4
|
import { getCanvasPosition, getWorldPosition } from './utils';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* When dragging, draws a box on the
|
|
8
|
-
* nodes and relationships that are inside the box.
|
|
6
|
+
* An interaction handler for multi-selecting nodes and relationships.
|
|
7
|
+
* When dragging the cursor, it draws a box on the scene and all nodes and relationships inside the box are selected.
|
|
9
8
|
*
|
|
10
|
-
* @
|
|
11
|
-
* ```js
|
|
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' }], [])
|
|
16
|
-
* const boxSelectInteraction = new BoxSelectInteraction(nvl)
|
|
17
|
-
*
|
|
18
|
-
* boxSelectInteraction.updateCallback('onBoxSelect', ({ nodes, rels }) => {
|
|
19
|
-
* console.log('Selected elements:', nodes, rels)
|
|
20
|
-
* })
|
|
21
|
-
* ```
|
|
9
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_boxselectinteraction Box Select Interaction documentation page}.
|
|
22
10
|
*/
|
|
23
11
|
export class BoxSelectInteraction extends BaseInteraction {
|
|
24
12
|
mousePosition;
|
|
@@ -74,19 +74,9 @@ export type ClickInteractionCallbacks = {
|
|
|
74
74
|
};
|
|
75
75
|
/**
|
|
76
76
|
* Click interaction handler that handles click, double click and right click events on
|
|
77
|
-
* nodes, relationships and
|
|
77
|
+
* nodes, relationships, and the scene.
|
|
78
78
|
*
|
|
79
|
-
* @
|
|
80
|
-
* ```ts
|
|
81
|
-
* import { ClickInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
82
|
-
* import { NVL } from '@neo4j-nvl/base'
|
|
83
|
-
*
|
|
84
|
-
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
85
|
-
* const clickInteraction = new ClickInteraction(nvl)
|
|
86
|
-
* clickInteraction.updateCallback('onNodeClick', (node) => {
|
|
87
|
-
* console.log('Node clicked', node)
|
|
88
|
-
* })
|
|
89
|
-
* ```
|
|
79
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_clickinteraction Click Interaction documentation page}.
|
|
90
80
|
*/
|
|
91
81
|
export declare class ClickInteraction extends BaseInteraction<ClickInteractionCallbacks, ClickInteractionOptions> {
|
|
92
82
|
private moved;
|
|
@@ -2,19 +2,9 @@ import { BaseInteraction } from './base';
|
|
|
2
2
|
import { isDraggingMovement } from './utils';
|
|
3
3
|
/**
|
|
4
4
|
* Click interaction handler that handles click, double click and right click events on
|
|
5
|
-
* nodes, relationships and
|
|
5
|
+
* nodes, relationships, and the scene.
|
|
6
6
|
*
|
|
7
|
-
* @
|
|
8
|
-
* ```ts
|
|
9
|
-
* import { ClickInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
10
|
-
* import { NVL } from '@neo4j-nvl/base'
|
|
11
|
-
*
|
|
12
|
-
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
13
|
-
* const clickInteraction = new ClickInteraction(nvl)
|
|
14
|
-
* clickInteraction.updateCallback('onNodeClick', (node) => {
|
|
15
|
-
* console.log('Node clicked', node)
|
|
16
|
-
* })
|
|
17
|
-
* ```
|
|
7
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_clickinteraction Click Interaction documentation page}.
|
|
18
8
|
*/
|
|
19
9
|
export class ClickInteraction extends BaseInteraction {
|
|
20
10
|
moved;
|
|
@@ -24,22 +24,11 @@ export type DragNodeInteractionCallbacks = {
|
|
|
24
24
|
onDragEnd?: ((nodes: Node[], evt: MouseEvent) => void) | boolean;
|
|
25
25
|
};
|
|
26
26
|
/**
|
|
27
|
-
* Interaction handler for dragging nodes
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
* Interaction handler for dragging nodes,
|
|
28
|
+
* which is achieved by clicking and moving the node.
|
|
29
|
+
* When multiple nodes are selected, they are all dragged.
|
|
30
30
|
*
|
|
31
|
-
* @
|
|
32
|
-
* ```js
|
|
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' }], [])
|
|
37
|
-
* const dragNodeInteraction = new DragNodeInteraction(nvl)
|
|
38
|
-
*
|
|
39
|
-
* dragNodeInteraction.updateCallback('onDrag', (nodes) => {
|
|
40
|
-
* console.log('Dragged nodes:', nodes)
|
|
41
|
-
* })
|
|
42
|
-
* ```
|
|
31
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_dragnodeinteraction Drag Node Interaction documentation page}.
|
|
43
32
|
*/
|
|
44
33
|
export declare class DragNodeInteraction extends BaseInteraction<DragNodeInteractionCallbacks, Record<string, never>> {
|
|
45
34
|
private mousePosition;
|
|
@@ -2,22 +2,11 @@ import { NODE_EDGE_WIDTH } from '../constants';
|
|
|
2
2
|
import { BaseInteraction } from './base';
|
|
3
3
|
import { isDraggingMovement } from './utils';
|
|
4
4
|
/**
|
|
5
|
-
* Interaction handler for dragging nodes
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Interaction handler for dragging nodes,
|
|
6
|
+
* which is achieved by clicking and moving the node.
|
|
7
|
+
* When multiple nodes are selected, they are all dragged.
|
|
8
8
|
*
|
|
9
|
-
* @
|
|
10
|
-
* ```js
|
|
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' }], [])
|
|
15
|
-
* const dragNodeInteraction = new DragNodeInteraction(nvl)
|
|
16
|
-
*
|
|
17
|
-
* dragNodeInteraction.updateCallback('onDrag', (nodes) => {
|
|
18
|
-
* console.log('Dragged nodes:', nodes)
|
|
19
|
-
* })
|
|
20
|
-
* ```
|
|
9
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_dragnodeinteraction Drag Node Interaction documentation page}.
|
|
21
10
|
*/
|
|
22
11
|
export class DragNodeInteraction extends BaseInteraction {
|
|
23
12
|
mousePosition;
|
|
@@ -2,11 +2,11 @@ import type { NVL, Node, Relationship } from '@neo4j-nvl/base';
|
|
|
2
2
|
import { BaseInteraction } from './base';
|
|
3
3
|
/**
|
|
4
4
|
* @internal
|
|
5
|
-
* @experimental
|
|
6
5
|
*/
|
|
7
6
|
export type DrawInteractionCallbacks = {
|
|
8
7
|
onHoverNodeMargin?: ((hoveredNode: Node | null, evt: MouseEvent) => void) | boolean;
|
|
9
|
-
|
|
8
|
+
onDrawEnded?: ((newRelationshipToAdd: Relationship | null, newTargetNodeToAdd: Node | null, event: MouseEvent) => void) | boolean;
|
|
9
|
+
onDrawStarted?: ((event: MouseEvent) => void) | boolean;
|
|
10
10
|
};
|
|
11
11
|
export type DrawInteractionOptions = {
|
|
12
12
|
ghostGraphStyling?: {
|
|
@@ -16,7 +16,6 @@ export type DrawInteractionOptions = {
|
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
18
|
* @internal
|
|
19
|
-
* @experimental
|
|
20
19
|
*/
|
|
21
20
|
export declare class DrawInteraction extends BaseInteraction<DrawInteractionCallbacks, DrawInteractionOptions> {
|
|
22
21
|
private isMoved;
|
|
@@ -14,7 +14,6 @@ const DefaultGhostGraphStyling = {
|
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
16
|
* @internal
|
|
17
|
-
* @experimental
|
|
18
17
|
*/
|
|
19
18
|
export class DrawInteraction extends BaseInteraction {
|
|
20
19
|
isMoved;
|
|
@@ -242,6 +241,7 @@ export class DrawInteraction extends BaseInteraction {
|
|
|
242
241
|
};
|
|
243
242
|
this.setNewRegularRelationshipToNewTempTargetNode();
|
|
244
243
|
this.nvlInstance.addAndUpdateElementsInGraph([this.newTempTargetNode], this.newTempRegularRelationshipToNewTempTargetNode ? [this.newTempRegularRelationshipToNewTempTargetNode] : []);
|
|
244
|
+
this.callCallbackIfRegistered('onDrawStarted', event);
|
|
245
245
|
}
|
|
246
246
|
else {
|
|
247
247
|
this.mouseDownNode = undefined;
|
|
@@ -262,7 +262,7 @@ export class DrawInteraction extends BaseInteraction {
|
|
|
262
262
|
}
|
|
263
263
|
// Avoid relationship glitch.
|
|
264
264
|
this.nvlInstance.addAndUpdateElementsInGraph(this.newTargetNodeToAdd ? [{ id: this.newTargetNodeToAdd.id }] : [], this.newRelationshipToAdd ? [this.newRelationshipToAdd] : []);
|
|
265
|
-
this.callCallbackIfRegistered('
|
|
265
|
+
this.callCallbackIfRegistered('onDrawEnded', this.newRelationshipToAdd, this.newTargetNodeToAdd, event);
|
|
266
266
|
}
|
|
267
267
|
this.newTempTargetNode = null;
|
|
268
268
|
this.newTempRegularRelationshipToNewTempTargetNode = null;
|
|
@@ -19,7 +19,7 @@ export type HoverInteractionCallbacks = {
|
|
|
19
19
|
* @param element - The node or relationship that was hovered
|
|
20
20
|
* @param hitElements - All elements that were hit by the hover
|
|
21
21
|
* @param event - The original mouse event
|
|
22
|
-
*
|
|
22
|
+
* This callback is called every time the mouse moves,
|
|
23
23
|
* even when no element is hovered or the current element is already hovered.
|
|
24
24
|
*/
|
|
25
25
|
onHover?: ((element: Node | Relationship, hitElements: HitTargets, event: MouseEvent) => void) | boolean;
|
|
@@ -27,20 +27,7 @@ export type HoverInteractionCallbacks = {
|
|
|
27
27
|
/**
|
|
28
28
|
* Interaction handler for hovering nodes and relationships.
|
|
29
29
|
*
|
|
30
|
-
* @
|
|
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' }], [])
|
|
36
|
-
* const hoverInteraction = new HoverInteraction(nvl)
|
|
37
|
-
*
|
|
38
|
-
* hoverInteraction.updateCallback('onHover', (element, hitElements, event) => {
|
|
39
|
-
* console.log('Hovered element:', element)
|
|
40
|
-
* console.log('Hit elements:', hitElements)
|
|
41
|
-
* console.log('Mouse event:', event)
|
|
42
|
-
* })
|
|
43
|
-
* ```
|
|
30
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_hoverinteraction Hover Interaction documentation page}.
|
|
44
31
|
*/
|
|
45
32
|
export declare class HoverInteraction extends BaseInteraction<HoverInteractionCallbacks, HoverInteractionOptions> {
|
|
46
33
|
private currentHoveredElement;
|
|
@@ -2,20 +2,7 @@ import { BaseInteraction } from './base';
|
|
|
2
2
|
/**
|
|
3
3
|
* Interaction handler for hovering nodes and relationships.
|
|
4
4
|
*
|
|
5
|
-
* @
|
|
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' }], [])
|
|
11
|
-
* const hoverInteraction = new HoverInteraction(nvl)
|
|
12
|
-
*
|
|
13
|
-
* hoverInteraction.updateCallback('onHover', (element, hitElements, event) => {
|
|
14
|
-
* console.log('Hovered element:', element)
|
|
15
|
-
* console.log('Hit elements:', hitElements)
|
|
16
|
-
* console.log('Mouse event:', event)
|
|
17
|
-
* })
|
|
18
|
-
* ```
|
|
5
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_hoverinteraction Hover Interaction documentation page}.
|
|
19
6
|
*/
|
|
20
7
|
export class HoverInteraction extends BaseInteraction {
|
|
21
8
|
currentHoveredElement;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NVL, Node, Relationship } from '@neo4j-nvl/base';
|
|
1
|
+
import type { NVL, Node, Point, Relationship } from '@neo4j-nvl/base';
|
|
2
2
|
import { BaseInteraction } from './base';
|
|
3
3
|
/**
|
|
4
4
|
* Options for the lasso interaction handler to customize its behavior.
|
|
@@ -27,22 +27,29 @@ export type LassoInteractionCallbacks = {
|
|
|
27
27
|
}, event: MouseEvent) => void) | boolean;
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
*
|
|
40
|
-
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export type Coords = [number, number];
|
|
33
|
+
/**
|
|
34
|
+
* Checks if two lines defined by p1->p2 and p3->p4 are crossing.
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export declare const checkLinesCrossing: (p1: Coords, p2: Coords, p3: Coords, p4: Coords) => boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Checks if any line segments in the polygon intersect.
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
export declare const checkIntersection: (polygon: Coords[]) => boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Checks if the point (x, y) is inside the polygon defined by vs.
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
export declare const checkPointInside: (x: number, y: number, vs: Point[]) => boolean;
|
|
48
|
+
/**
|
|
49
|
+
* An interaction handler that lets you select nodes and relationships by drawing a lasso around them.
|
|
50
|
+
* When dragging, a line is drawn on the scene and all elements inside are selected.
|
|
41
51
|
*
|
|
42
|
-
*
|
|
43
|
-
* console.log('Selected elements:', nodes, rels)
|
|
44
|
-
* })
|
|
45
|
-
* ```
|
|
52
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_lassointeraction Lasso Interaction documentation page}.
|
|
46
53
|
*/
|
|
47
54
|
export declare class LassoInteraction extends BaseInteraction<LassoInteractionCallbacks, LassoInteractionOptions> {
|
|
48
55
|
private active;
|
|
@@ -5,22 +5,67 @@ import { getCanvasPosition, getWorldPosition } from './utils';
|
|
|
5
5
|
const pointDist = 10;
|
|
6
6
|
const shapeShowTime = 500;
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*
|
|
8
|
+
* Checks if two lines defined by p1->p2 and p3->p4 are crossing.
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export const checkLinesCrossing = (p1, p2, p3, p4) => {
|
|
12
|
+
const denom = (p4[1] - p3[1]) * (p2[0] - p1[0]) - (p4[0] - p3[0]) * (p2[1] - p1[1]);
|
|
13
|
+
if (denom === 0) {
|
|
14
|
+
// This means lines are parallell
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const t1 = ((p1[1] - p3[1]) * (p4[0] - p3[0]) - (p1[0] - p3[0]) * (p4[1] - p3[1])) / denom;
|
|
18
|
+
const t2 = ((p3[0] - p1[0]) * (p2[1] - p1[1]) - (p3[1] - p1[1]) * (p2[0] - p1[0])) / denom;
|
|
19
|
+
return t1 > 0 && t1 < 1 && t2 > 0 && t2 < 1;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Checks if any line segments in the polygon intersect.
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export const checkIntersection = (polygon) => {
|
|
26
|
+
for (let i = 0; i < polygon.length - 1; i++) {
|
|
27
|
+
for (let j = i + 2; j < polygon.length; j++) {
|
|
28
|
+
const line1p1 = polygon[i] ?? [0, 0];
|
|
29
|
+
const line1p2 = polygon[i + 1] ?? [0, 0];
|
|
30
|
+
const line2p1 = polygon[j] ?? [0, 0];
|
|
31
|
+
// Handle segment from first to last point
|
|
32
|
+
const jNext = j < polygon.length - 1 ? j + 1 : 0;
|
|
33
|
+
const line2p2 = polygon[jNext] ?? [0, 0];
|
|
34
|
+
if (checkLinesCrossing(line1p1, line1p2, line2p1, line2p2)) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Checks if the point (x, y) is inside the polygon defined by vs.
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
export const checkPointInside = (x, y, vs) => {
|
|
46
|
+
// ray-casting algorithm based on
|
|
47
|
+
// https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
|
|
48
|
+
let isInside = false;
|
|
49
|
+
for (let i = 0, j = vs.length - 1; i < vs.length; j = i, i += 1) {
|
|
50
|
+
const vsI = vs[i];
|
|
51
|
+
const vsJ = vs[j];
|
|
52
|
+
if (vsI === undefined || vsJ === undefined) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const { x: xi, y: yi } = vsI;
|
|
56
|
+
const { x: xj, y: yj } = vsJ;
|
|
57
|
+
const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
|
|
58
|
+
if (intersect) {
|
|
59
|
+
isInside = !isInside;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return isInside;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* An interaction handler that lets you select nodes and relationships by drawing a lasso around them.
|
|
66
|
+
* When dragging, a line is drawn on the scene and all elements inside are selected.
|
|
19
67
|
*
|
|
20
|
-
*
|
|
21
|
-
* console.log('Selected elements:', nodes, rels)
|
|
22
|
-
* })
|
|
23
|
-
* ```
|
|
68
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_lassointeraction Lasso Interaction documentation page}.
|
|
24
69
|
*/
|
|
25
70
|
export class LassoInteraction extends BaseInteraction {
|
|
26
71
|
active;
|
|
@@ -70,25 +115,6 @@ export class LassoInteraction extends BaseInteraction {
|
|
|
70
115
|
this.endLasso(event);
|
|
71
116
|
};
|
|
72
117
|
getLassoItems = (points) => {
|
|
73
|
-
const inside = (x, y, vs) => {
|
|
74
|
-
// ray-casting algorithm based on
|
|
75
|
-
// https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
|
|
76
|
-
let isInside = false;
|
|
77
|
-
for (let i = 0, j = vs.length - 1; i < vs.length; j = i, i += 1) {
|
|
78
|
-
const vsI = vs[i];
|
|
79
|
-
const vsJ = vs[j];
|
|
80
|
-
if (vsI === undefined || vsJ === undefined) {
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
const { x: xi, y: yi } = vsI;
|
|
84
|
-
const { x: xj, y: yj } = vsJ;
|
|
85
|
-
const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
|
|
86
|
-
if (intersect) {
|
|
87
|
-
isInside = !isInside;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return isInside;
|
|
91
|
-
};
|
|
92
118
|
const worldPoints = points.map((p) => getWorldPosition(this.nvlInstance, p));
|
|
93
119
|
const nodePositions = this.nvlInstance.getNodePositions();
|
|
94
120
|
const hitNodes = new Set();
|
|
@@ -96,7 +122,7 @@ export class LassoInteraction extends BaseInteraction {
|
|
|
96
122
|
if (pos.x === undefined || pos.y === undefined || pos.id === undefined) {
|
|
97
123
|
continue;
|
|
98
124
|
}
|
|
99
|
-
if (
|
|
125
|
+
if (checkPointInside(pos.x, pos.y, worldPoints)) {
|
|
100
126
|
hitNodes.add(pos.id);
|
|
101
127
|
}
|
|
102
128
|
}
|
|
@@ -119,7 +145,8 @@ export class LassoInteraction extends BaseInteraction {
|
|
|
119
145
|
}
|
|
120
146
|
this.active = false;
|
|
121
147
|
const pointArrays = this.points.map((p) => [p.x, p.y]);
|
|
122
|
-
const
|
|
148
|
+
const hasCrossings = checkIntersection(pointArrays);
|
|
149
|
+
const hull = (hasCrossings ? concaveman(pointArrays, 2) : pointArrays)
|
|
123
150
|
.map((p) => ({ x: p[0], y: p[1] }))
|
|
124
151
|
.filter((point) => point.x !== undefined && point.y !== undefined);
|
|
125
152
|
this.overlayRenderer.drawLasso(hull, false, true);
|
|
@@ -25,21 +25,9 @@ export type PanInteractionCallbacks = {
|
|
|
25
25
|
}, event: MouseEvent) => void) | boolean;
|
|
26
26
|
};
|
|
27
27
|
/**
|
|
28
|
-
* Interaction handler for panning the
|
|
29
|
-
* Panning is achieved by clicking and dragging on the canvas.
|
|
28
|
+
* Interaction handler for panning the scene, which is achieved by clicking and moving the scene.
|
|
30
29
|
*
|
|
31
|
-
* @
|
|
32
|
-
* ```js
|
|
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' }], [])
|
|
37
|
-
* const panInteraction = new PanInteraction(nvl)
|
|
38
|
-
*
|
|
39
|
-
* panInteraction.updateCallback('onPan', (panning) => {
|
|
40
|
-
* console.log('Panning:', panning)
|
|
41
|
-
* })
|
|
42
|
-
* ```
|
|
30
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_paninteraction Pan Interaction documentation page}.
|
|
43
31
|
*/
|
|
44
32
|
export declare class PanInteraction extends BaseInteraction<PanInteractionCallbacks, PanInteractionOptions> {
|
|
45
33
|
private mousePosition;
|
|
@@ -54,7 +42,7 @@ export declare class PanInteraction extends BaseInteraction<PanInteractionCallba
|
|
|
54
42
|
* Updates which type of graph elements should hinder panning.
|
|
55
43
|
* @param targets - The graph elements that should hinder panning
|
|
56
44
|
* @param excludeNodeMargin - If true, the node margin will not hinder panning
|
|
57
|
-
*
|
|
45
|
+
* By default, panning is hindered by nodes and relationships.
|
|
58
46
|
*
|
|
59
47
|
* @example
|
|
60
48
|
* ```js
|
|
@@ -2,21 +2,9 @@ import { difference } from 'lodash';
|
|
|
2
2
|
import { NODE_EDGE_WIDTH } from '../constants';
|
|
3
3
|
import { BaseInteraction } from './base';
|
|
4
4
|
/**
|
|
5
|
-
* Interaction handler for panning the
|
|
6
|
-
* Panning is achieved by clicking and dragging on the canvas.
|
|
5
|
+
* Interaction handler for panning the scene, which is achieved by clicking and moving the scene.
|
|
7
6
|
*
|
|
8
|
-
* @
|
|
9
|
-
* ```js
|
|
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' }], [])
|
|
14
|
-
* const panInteraction = new PanInteraction(nvl)
|
|
15
|
-
*
|
|
16
|
-
* panInteraction.updateCallback('onPan', (panning) => {
|
|
17
|
-
* console.log('Panning:', panning)
|
|
18
|
-
* })
|
|
19
|
-
* ```
|
|
7
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_paninteraction Pan Interaction documentation page}.
|
|
20
8
|
*/
|
|
21
9
|
export class PanInteraction extends BaseInteraction {
|
|
22
10
|
mousePosition;
|
|
@@ -39,7 +27,7 @@ export class PanInteraction extends BaseInteraction {
|
|
|
39
27
|
* Updates which type of graph elements should hinder panning.
|
|
40
28
|
* @param targets - The graph elements that should hinder panning
|
|
41
29
|
* @param excludeNodeMargin - If true, the node margin will not hinder panning
|
|
42
|
-
*
|
|
30
|
+
* By default, panning is hindered by nodes and relationships.
|
|
43
31
|
*
|
|
44
32
|
* @example
|
|
45
33
|
* ```js
|
|
@@ -12,21 +12,9 @@ export type ZoomInteractionCallbacks = {
|
|
|
12
12
|
onZoom?: ((zoomLevel: number, event: WheelEvent) => void) | boolean;
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
|
-
* Interaction handler for zooming the canvas.
|
|
16
|
-
* Zooming is achieved by scrolling the mouse wheel on the canvas.
|
|
15
|
+
* Interaction handler for zooming the canvas, which is achieved by scrolling the mouse wheel on the canvas.
|
|
17
16
|
*
|
|
18
|
-
* @
|
|
19
|
-
* ```js
|
|
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' }], [])
|
|
24
|
-
* const zoomInteraction = new ZoomInteraction(nvl)
|
|
25
|
-
*
|
|
26
|
-
* zoomInteraction.updateCallback('onZoom', (zoomLevel) => {
|
|
27
|
-
* console.log('Zoom level:', zoomLevel)
|
|
28
|
-
* })
|
|
29
|
-
* ```
|
|
17
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_zoominteraction Zoom Interaction documentation page}.
|
|
30
18
|
*/
|
|
31
19
|
export declare class ZoomInteraction extends BaseInteraction<ZoomInteractionCallbacks, Record<string, never>> {
|
|
32
20
|
/**
|
|
@@ -37,13 +25,13 @@ export declare class ZoomInteraction extends BaseInteraction<ZoomInteractionCall
|
|
|
37
25
|
/**
|
|
38
26
|
* Throttled zoom function to avoid events happening too fast.
|
|
39
27
|
* @param event - The original mouse wheel event
|
|
40
|
-
*
|
|
28
|
+
* "Wheel" with a touchpad, the wheel is triggered event a lot,
|
|
41
29
|
* especially a lot of very small values.
|
|
42
30
|
* However, updating values in NVL instance takes time.
|
|
43
31
|
* Sometimes it lost the track of multiple events happening too soon.
|
|
44
32
|
* As a result, the zoom might lose its anchor point under touch pad.
|
|
45
33
|
* Therefore, the throttle is needed to avoid events happening too fast.
|
|
46
|
-
*
|
|
34
|
+
* The throttle is set to 25ms.
|
|
47
35
|
*/
|
|
48
36
|
private throttledZoom;
|
|
49
37
|
private handleWheel;
|
|
@@ -2,21 +2,9 @@ import { throttle } from 'lodash';
|
|
|
2
2
|
import { BaseInteraction } from './base';
|
|
3
3
|
import { getCanvasCenterOffset } from './utils';
|
|
4
4
|
/**
|
|
5
|
-
* Interaction handler for zooming the canvas.
|
|
6
|
-
* Zooming is achieved by scrolling the mouse wheel on the canvas.
|
|
5
|
+
* Interaction handler for zooming the canvas, which is achieved by scrolling the mouse wheel on the canvas.
|
|
7
6
|
*
|
|
8
|
-
* @
|
|
9
|
-
* ```js
|
|
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' }], [])
|
|
14
|
-
* const zoomInteraction = new ZoomInteraction(nvl)
|
|
15
|
-
*
|
|
16
|
-
* zoomInteraction.updateCallback('onZoom', (zoomLevel) => {
|
|
17
|
-
* console.log('Zoom level:', zoomLevel)
|
|
18
|
-
* })
|
|
19
|
-
* ```
|
|
7
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_zoominteraction Zoom Interaction documentation page}.
|
|
20
8
|
*/
|
|
21
9
|
export class ZoomInteraction extends BaseInteraction {
|
|
22
10
|
/**
|
|
@@ -30,13 +18,13 @@ export class ZoomInteraction extends BaseInteraction {
|
|
|
30
18
|
/**
|
|
31
19
|
* Throttled zoom function to avoid events happening too fast.
|
|
32
20
|
* @param event - The original mouse wheel event
|
|
33
|
-
*
|
|
21
|
+
* "Wheel" with a touchpad, the wheel is triggered event a lot,
|
|
34
22
|
* especially a lot of very small values.
|
|
35
23
|
* However, updating values in NVL instance takes time.
|
|
36
24
|
* Sometimes it lost the track of multiple events happening too soon.
|
|
37
25
|
* As a result, the zoom might lose its anchor point under touch pad.
|
|
38
26
|
* Therefore, the throttle is needed to avoid events happening too fast.
|
|
39
|
-
*
|
|
27
|
+
* The throttle is set to 25ms.
|
|
40
28
|
*/
|
|
41
29
|
throttledZoom = throttle((event) => {
|
|
42
30
|
const zoom = this.nvlInstance.getScale();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neo4j-nvl/interaction-handlers",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4-c75037f2",
|
|
4
4
|
"license": "SEE LICENSE IN 'LICENSE.txt'",
|
|
5
5
|
"homepage": "https://neo4j.com/docs/nvl/current/",
|
|
6
6
|
"description": "Interaction handlers for the Neo4j Visualization Library",
|
|
@@ -26,14 +26,8 @@
|
|
|
26
26
|
"postpack": "rm LICENSE.txt",
|
|
27
27
|
"eslint": "eslint ./src/"
|
|
28
28
|
},
|
|
29
|
-
"typedoc": {
|
|
30
|
-
"entryPoint": "./src/index.ts",
|
|
31
|
-
"readmeFile": "./README.md",
|
|
32
|
-
"displayName": "Interaction Handlers",
|
|
33
|
-
"tsconfig": "./tsconfig.json"
|
|
34
|
-
},
|
|
35
29
|
"dependencies": {
|
|
36
|
-
"@neo4j-nvl/base": "0.3.
|
|
30
|
+
"@neo4j-nvl/base": "0.3.4-c75037f2",
|
|
37
31
|
"concaveman": "^1.2.1",
|
|
38
32
|
"lodash": "4.17.21"
|
|
39
33
|
},
|
|
@@ -50,5 +44,6 @@
|
|
|
50
44
|
"eslint": "*",
|
|
51
45
|
"jest": "*",
|
|
52
46
|
"typescript": "*"
|
|
53
|
-
}
|
|
47
|
+
},
|
|
48
|
+
"stableVersion": "0.3.4"
|
|
54
49
|
}
|