@neo4j-nvl/interaction-handlers 0.2.1
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/Neo4j Early Access Agreement - Visualization Library.pdf +0 -0
- package/README.md +1 -0
- package/lib/constants.d.ts +1 -0
- package/lib/constants.js +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +8 -0
- package/lib/interaction-handlers/base.d.ts +54 -0
- package/lib/interaction-handlers/base.js +110 -0
- package/lib/interaction-handlers/click-interaction.d.ts +109 -0
- package/lib/interaction-handlers/click-interaction.js +162 -0
- package/lib/interaction-handlers/drag-node-interaction.d.ts +46 -0
- package/lib/interaction-handlers/drag-node-interaction.js +137 -0
- package/lib/interaction-handlers/draw-interaction.d.ts +30 -0
- package/lib/interaction-handlers/draw-interaction.js +257 -0
- package/lib/interaction-handlers/hover-interaction.d.ts +57 -0
- package/lib/interaction-handlers/hover-interaction.js +113 -0
- package/lib/interaction-handlers/multi-select-interaction.d.ts +58 -0
- package/lib/interaction-handlers/multi-select-interaction.js +133 -0
- package/lib/interaction-handlers/pan-interaction.d.ts +58 -0
- package/lib/interaction-handlers/pan-interaction.js +115 -0
- package/lib/interaction-handlers/utils.d.ts +1 -0
- package/lib/interaction-handlers/utils.js +1 -0
- package/lib/interaction-handlers/zoom-interaction.d.ts +52 -0
- package/lib/interaction-handlers/zoom-interaction.js +91 -0
- package/lib/overlay-renderer/overlay-renderer.d.ts +12 -0
- package/lib/overlay-renderer/overlay-renderer.js +111 -0
- package/package.json +36 -0
|
Binary file
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
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 documentation for the decorators in the usage documentation of each class.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const NODE_EDGE_WIDTH = 10;
|
package/lib/constants.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const NODE_EDGE_WIDTH = 10;
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ClickInteractionCallbacks, ClickInteractionOptions } from './interaction-handlers/click-interaction';
|
|
2
|
+
import { ClickInteraction } from './interaction-handlers/click-interaction';
|
|
3
|
+
import { DragNodeInteraction } from './interaction-handlers/drag-node-interaction';
|
|
4
|
+
import type { DragNodeInteractionCallbacks } from './interaction-handlers/drag-node-interaction';
|
|
5
|
+
import { DrawInteraction } from './interaction-handlers/draw-interaction';
|
|
6
|
+
import type { HoverInteractionOptions, HoverInteractionCallbacks } from './interaction-handlers/hover-interaction';
|
|
7
|
+
import { HoverInteraction } from './interaction-handlers/hover-interaction';
|
|
8
|
+
import type { MultiSelectInteractionOptions } from './interaction-handlers/multi-select-interaction';
|
|
9
|
+
import { MultiSelectInteraction } from './interaction-handlers/multi-select-interaction';
|
|
10
|
+
import type { PanInteractionCallbacks } from './interaction-handlers/pan-interaction';
|
|
11
|
+
import { PanInteraction } from './interaction-handlers/pan-interaction';
|
|
12
|
+
import type { ZoomInteractionCallbacks } from './interaction-handlers/zoom-interaction';
|
|
13
|
+
import { ZoomInteraction } from './interaction-handlers/zoom-interaction';
|
|
14
|
+
export type { MultiSelectInteractionOptions, ClickInteractionOptions, HoverInteractionOptions, HoverInteractionCallbacks, DragNodeInteractionCallbacks, ClickInteractionCallbacks, PanInteractionCallbacks, ZoomInteractionCallbacks };
|
|
15
|
+
export { ZoomInteraction, PanInteraction, MultiSelectInteraction, ClickInteraction, HoverInteraction, DragNodeInteraction, DrawInteraction };
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ClickInteraction } from './interaction-handlers/click-interaction';
|
|
2
|
+
import { DragNodeInteraction } from './interaction-handlers/drag-node-interaction';
|
|
3
|
+
import { DrawInteraction } from './interaction-handlers/draw-interaction';
|
|
4
|
+
import { HoverInteraction } from './interaction-handlers/hover-interaction';
|
|
5
|
+
import { MultiSelectInteraction } from './interaction-handlers/multi-select-interaction';
|
|
6
|
+
import { PanInteraction } from './interaction-handlers/pan-interaction';
|
|
7
|
+
import { ZoomInteraction } from './interaction-handlers/zoom-interaction';
|
|
8
|
+
export { ZoomInteraction, PanInteraction, MultiSelectInteraction, ClickInteraction, HoverInteraction, DragNodeInteraction, DrawInteraction };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { NVL } from '@neo4j-nvl/core';
|
|
2
|
+
/**
|
|
3
|
+
* Base class for all interactions.
|
|
4
|
+
* @abstract
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
declare abstract class BaseInteraction<T extends Record<string, (...args: unknown[]) => void>> {
|
|
8
|
+
private readonly nvl;
|
|
9
|
+
private readonly container;
|
|
10
|
+
/**
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
callbackMap: Map<keyof T, T[keyof T]>;
|
|
14
|
+
/**
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
constructor(nvl: NVL);
|
|
18
|
+
/**
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
get nvlInstance(): NVL;
|
|
22
|
+
/**
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
get containerInstance(): HTMLElement;
|
|
26
|
+
/**
|
|
27
|
+
* @internal
|
|
28
|
+
*/
|
|
29
|
+
addEventListener: (type: keyof HTMLElementEventMap, listener: (event: Event) => void, options?: boolean | AddEventListenerOptions) => void;
|
|
30
|
+
/**
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
removeEventListener: (type: keyof HTMLElementEventMap, listener: (event: Event) => void, options?: boolean | EventListenerOptions) => void;
|
|
34
|
+
/**
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
callCallbackIfRegistered: (name: keyof T, ...args: Parameters<T[keyof T]>) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Add or update a callback for a given event of type.
|
|
40
|
+
* @param name - The name of the event
|
|
41
|
+
* @param callback - The callback to be called when the event is triggered
|
|
42
|
+
*/
|
|
43
|
+
updateCallback: (name: keyof T, callback: T[keyof T]) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Remove a callback for a given event of type.
|
|
46
|
+
* @param name - The name of the event
|
|
47
|
+
*/
|
|
48
|
+
removeCallback: (name: keyof T) => void;
|
|
49
|
+
/**
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
52
|
+
abstract destroy(): void;
|
|
53
|
+
}
|
|
54
|
+
export { BaseInteraction };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base class for all interactions.
|
|
3
|
+
* @abstract
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
class BaseInteraction {
|
|
7
|
+
/**
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
constructor(nvl) {
|
|
11
|
+
Object.defineProperty(this, "nvl", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true,
|
|
14
|
+
writable: true,
|
|
15
|
+
value: void 0
|
|
16
|
+
});
|
|
17
|
+
Object.defineProperty(this, "container", {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
configurable: true,
|
|
20
|
+
writable: true,
|
|
21
|
+
value: void 0
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(this, "callbackMap", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
configurable: true,
|
|
29
|
+
writable: true,
|
|
30
|
+
value: void 0
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
Object.defineProperty(this, "addEventListener", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
writable: true,
|
|
39
|
+
value: (type, listener, options) => {
|
|
40
|
+
this.container.addEventListener(type, listener, options);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
46
|
+
Object.defineProperty(this, "removeEventListener", {
|
|
47
|
+
enumerable: true,
|
|
48
|
+
configurable: true,
|
|
49
|
+
writable: true,
|
|
50
|
+
value: (type, listener, options) => {
|
|
51
|
+
this.container.removeEventListener(type, listener, options);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
Object.defineProperty(this, "callCallbackIfRegistered", {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
configurable: true,
|
|
60
|
+
writable: true,
|
|
61
|
+
value: (name, ...args) => {
|
|
62
|
+
const callback = this.callbackMap.get(name);
|
|
63
|
+
if (callback) {
|
|
64
|
+
callback(...args);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* Add or update a callback for a given event of type.
|
|
70
|
+
* @param name - The name of the event
|
|
71
|
+
* @param callback - The callback to be called when the event is triggered
|
|
72
|
+
*/
|
|
73
|
+
Object.defineProperty(this, "updateCallback", {
|
|
74
|
+
enumerable: true,
|
|
75
|
+
configurable: true,
|
|
76
|
+
writable: true,
|
|
77
|
+
value: (name, callback) => {
|
|
78
|
+
this.callbackMap.set(name, callback);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* Remove a callback for a given event of type.
|
|
83
|
+
* @param name - The name of the event
|
|
84
|
+
*/
|
|
85
|
+
Object.defineProperty(this, "removeCallback", {
|
|
86
|
+
enumerable: true,
|
|
87
|
+
configurable: true,
|
|
88
|
+
writable: true,
|
|
89
|
+
value: (name) => {
|
|
90
|
+
this.callbackMap.delete(name);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
this.nvl = nvl;
|
|
94
|
+
this.container = this.nvl.getContainer();
|
|
95
|
+
this.callbackMap = new Map();
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* @internal
|
|
99
|
+
*/
|
|
100
|
+
get nvlInstance() {
|
|
101
|
+
return this.nvl;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* @internal
|
|
105
|
+
*/
|
|
106
|
+
get containerInstance() {
|
|
107
|
+
return this.container;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export { BaseInteraction };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { HitTargets, NVL, Node, Relationship } from '@neo4j-nvl/core';
|
|
2
|
+
import { BaseInteraction } from './base';
|
|
3
|
+
/**
|
|
4
|
+
* Options for the click interaction handler to customize its behavior.
|
|
5
|
+
*/
|
|
6
|
+
export type ClickInteractionOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* Whether to select the node or relationship on click
|
|
9
|
+
* @defaultValue false
|
|
10
|
+
*/
|
|
11
|
+
selectOnClick?: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Callbacks for the click interaction handler.
|
|
15
|
+
*/
|
|
16
|
+
export type ClickInteractionCallbacks = {
|
|
17
|
+
/**
|
|
18
|
+
* Called when a node is clicked
|
|
19
|
+
* @param nodes - The node that was clicked
|
|
20
|
+
* @param hitElements - All elements that were hit by the click
|
|
21
|
+
* @param event - The original mouse event
|
|
22
|
+
*/
|
|
23
|
+
onNodeClick: (nodes: Node, hitElements: HitTargets, event: MouseEvent) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Called when a relationship is clicked
|
|
26
|
+
* @param relationship - The relationship that was clicked
|
|
27
|
+
* @param hitElements - All elements that were hit by the click
|
|
28
|
+
* @param event - The original mouse event
|
|
29
|
+
*/
|
|
30
|
+
onRelationshipClick: (relationship: Relationship, hitElements: HitTargets, event: MouseEvent) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Called when the canvas is clicked
|
|
33
|
+
* @param event - The original mouse event
|
|
34
|
+
*/
|
|
35
|
+
onCanvasClick: (event: MouseEvent) => void;
|
|
36
|
+
/**
|
|
37
|
+
* Called when a node is double clicked
|
|
38
|
+
* @param event - The original mouse event
|
|
39
|
+
*/
|
|
40
|
+
onCanvasDoubleClick: (event: MouseEvent) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Called when a relationship is right-clicked
|
|
43
|
+
* @param event - The original mouse event
|
|
44
|
+
*/
|
|
45
|
+
onCanvasRightClick: (event: MouseEvent) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Called when a node is double-clicked
|
|
48
|
+
* @param nodes - The node that was double-clicked
|
|
49
|
+
* @param hitElements - All elements that were hit by the double-click
|
|
50
|
+
* @param event - The original mouse event
|
|
51
|
+
*/
|
|
52
|
+
onNodeDoubleClick: (node: Node, hitElements: HitTargets, event: MouseEvent) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Called when a node is right-clicked
|
|
55
|
+
* @param nodes - The node that was right-clicked
|
|
56
|
+
* @param hitElements - All elements that were hit by the right-click
|
|
57
|
+
* @param event - The original mouse event
|
|
58
|
+
*/
|
|
59
|
+
onNodeRightClick: (node: Node, hitElements: HitTargets, event: MouseEvent) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Called when a relationship is double-clicked
|
|
62
|
+
* @param relationship - The relationship that was double-clicked
|
|
63
|
+
* @param hitElements - All elements that were hit by the double-click
|
|
64
|
+
* @param event - The original mouse event
|
|
65
|
+
*/
|
|
66
|
+
onRelationshipDoubleClick: (relationship: Relationship, hitElements: HitTargets, event: MouseEvent) => void;
|
|
67
|
+
/**
|
|
68
|
+
* Called when a relationship is right-clicked
|
|
69
|
+
* @param relationship - The relationship that was right-clicked
|
|
70
|
+
* @param hitElements - All elements that were hit by the right-click
|
|
71
|
+
* @param event - The original mouse event
|
|
72
|
+
*/
|
|
73
|
+
onRelationshipRightClick: (relationship: Relationship, hitElements: HitTargets, event: MouseEvent) => void;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Click interaction handler that handles click, double click and right click events on
|
|
77
|
+
* nodes, relationships and canvas.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* import { ClickInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
82
|
+
* import { NVL } from '@neo4j-nvl/core'
|
|
83
|
+
*
|
|
84
|
+
* const nvl = new NVL(nodes, relationships, options)
|
|
85
|
+
* const clickInteraction = new ClickInteraction(nvl)
|
|
86
|
+
* clickInteraction.updateCallback('onNodeClick', (node) => {
|
|
87
|
+
* console.log('Node clicked', node)
|
|
88
|
+
* })
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare class ClickInteraction extends BaseInteraction<ClickInteractionCallbacks> {
|
|
92
|
+
private moved;
|
|
93
|
+
private readonly options;
|
|
94
|
+
/**
|
|
95
|
+
* Creates a new click interaction handler.
|
|
96
|
+
* @param nvl - The NVL instance to attach the interaction handler to
|
|
97
|
+
* @param options - Options for the click interaction handler
|
|
98
|
+
*/
|
|
99
|
+
constructor(nvl: NVL, options?: ClickInteractionOptions);
|
|
100
|
+
private handleMouseDown;
|
|
101
|
+
private handleMouseMove;
|
|
102
|
+
private handleRightClick;
|
|
103
|
+
private handleDoubleClick;
|
|
104
|
+
private handleMouseUp;
|
|
105
|
+
/**
|
|
106
|
+
* Removes all related event listeners from the container.
|
|
107
|
+
*/
|
|
108
|
+
destroy: () => void;
|
|
109
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { BaseInteraction } from './base';
|
|
2
|
+
/**
|
|
3
|
+
* Click interaction handler that handles click, double click and right click events on
|
|
4
|
+
* nodes, relationships and canvas.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { ClickInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
9
|
+
* import { NVL } from '@neo4j-nvl/core'
|
|
10
|
+
*
|
|
11
|
+
* const nvl = new NVL(nodes, relationships, options)
|
|
12
|
+
* const clickInteraction = new ClickInteraction(nvl)
|
|
13
|
+
* clickInteraction.updateCallback('onNodeClick', (node) => {
|
|
14
|
+
* console.log('Node clicked', node)
|
|
15
|
+
* })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export class ClickInteraction extends BaseInteraction {
|
|
19
|
+
/**
|
|
20
|
+
* Creates a new click interaction handler.
|
|
21
|
+
* @param nvl - The NVL instance to attach the interaction handler to
|
|
22
|
+
* @param options - Options for the click interaction handler
|
|
23
|
+
*/
|
|
24
|
+
constructor(nvl, options = { selectOnClick: false }) {
|
|
25
|
+
super(nvl);
|
|
26
|
+
Object.defineProperty(this, "moved", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
configurable: true,
|
|
29
|
+
writable: true,
|
|
30
|
+
value: void 0
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(this, "options", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: void 0
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(this, "handleMouseDown", {
|
|
39
|
+
enumerable: true,
|
|
40
|
+
configurable: true,
|
|
41
|
+
writable: true,
|
|
42
|
+
value: () => {
|
|
43
|
+
this.moved = false;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
Object.defineProperty(this, "handleMouseMove", {
|
|
47
|
+
enumerable: true,
|
|
48
|
+
configurable: true,
|
|
49
|
+
writable: true,
|
|
50
|
+
value: () => {
|
|
51
|
+
this.moved = true;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(this, "handleRightClick", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
configurable: true,
|
|
57
|
+
writable: true,
|
|
58
|
+
value: (event) => {
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
const { nvlTargets } = this.nvlInstance.getHits(event);
|
|
61
|
+
const { nodes = [], relationships = [] } = nvlTargets;
|
|
62
|
+
if (nodes.length === 0 && relationships.length === 0) {
|
|
63
|
+
this.callCallbackIfRegistered('onCanvasRightClick', event);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (nodes.length > 0) {
|
|
67
|
+
this.callCallbackIfRegistered('onNodeRightClick', nodes[0].data, nvlTargets, event);
|
|
68
|
+
}
|
|
69
|
+
else if (relationships.length > 0) {
|
|
70
|
+
this.callCallbackIfRegistered('onRelationshipRightClick', relationships[0].data, nvlTargets, event);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
Object.defineProperty(this, "handleDoubleClick", {
|
|
75
|
+
enumerable: true,
|
|
76
|
+
configurable: true,
|
|
77
|
+
writable: true,
|
|
78
|
+
value: (event) => {
|
|
79
|
+
const { nvlTargets } = this.nvlInstance.getHits(event);
|
|
80
|
+
const { nodes = [], relationships = [] } = nvlTargets;
|
|
81
|
+
if (nodes.length === 0 && relationships.length === 0) {
|
|
82
|
+
this.callCallbackIfRegistered('onCanvasDoubleClick', event);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (nodes.length > 0) {
|
|
86
|
+
this.callCallbackIfRegistered('onNodeDoubleClick', nodes[0].data, nvlTargets, event);
|
|
87
|
+
}
|
|
88
|
+
else if (relationships.length > 0) {
|
|
89
|
+
this.callCallbackIfRegistered('onRelationshipDoubleClick', relationships[0].data, nvlTargets, event);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
Object.defineProperty(this, "handleMouseUp", {
|
|
94
|
+
enumerable: true,
|
|
95
|
+
configurable: true,
|
|
96
|
+
writable: true,
|
|
97
|
+
value: (event) => {
|
|
98
|
+
if (this.moved) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const { nvlTargets } = this.nvlInstance.getHits(event);
|
|
102
|
+
const { nodes = [], relationships = [] } = nvlTargets;
|
|
103
|
+
if (nodes.length === 0 && relationships.length === 0) {
|
|
104
|
+
if (this.options.selectOnClick) {
|
|
105
|
+
this.nvlInstance.deselectAll();
|
|
106
|
+
}
|
|
107
|
+
this.callCallbackIfRegistered('onCanvasClick', event);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (nodes.length > 0) {
|
|
111
|
+
const hitNodeData = nodes.map((node) => node.data);
|
|
112
|
+
if (this.options.selectOnClick) {
|
|
113
|
+
const selectedNodes = this.nvlInstance.getSelectedNodes();
|
|
114
|
+
const selectedRelationships = this.nvlInstance.getSelectedRelationships();
|
|
115
|
+
const nodeUpdates = [
|
|
116
|
+
...selectedNodes.map((node) => ({ id: node.id, selected: false })),
|
|
117
|
+
{ id: hitNodeData[0].id, selected: true }
|
|
118
|
+
];
|
|
119
|
+
const relationshipUpdates = selectedRelationships.map((relationship) => (Object.assign(Object.assign({}, relationship), { selected: false })));
|
|
120
|
+
this.nvlInstance.updateElementsInGraph(nodeUpdates, relationshipUpdates);
|
|
121
|
+
}
|
|
122
|
+
this.callCallbackIfRegistered('onNodeClick', nodes[0].data, nvlTargets, event);
|
|
123
|
+
}
|
|
124
|
+
else if (relationships.length > 0) {
|
|
125
|
+
const hitRelationshipData = relationships.map((relationship) => relationship.data);
|
|
126
|
+
if (this.options.selectOnClick) {
|
|
127
|
+
const selectedNodes = this.nvlInstance.getSelectedNodes();
|
|
128
|
+
const selectedRelationships = this.nvlInstance.getSelectedRelationships();
|
|
129
|
+
const nodeUpdates = selectedNodes.map((node) => ({ id: node.id, selected: false }));
|
|
130
|
+
const relationshipUpdates = [
|
|
131
|
+
{ id: hitRelationshipData[0].id, selected: true },
|
|
132
|
+
...selectedRelationships.map((relationship) => (Object.assign(Object.assign({}, relationship), { selected: false })))
|
|
133
|
+
];
|
|
134
|
+
this.nvlInstance.updateElementsInGraph(nodeUpdates, relationshipUpdates);
|
|
135
|
+
}
|
|
136
|
+
this.callCallbackIfRegistered('onRelationshipClick', relationships[0].data, nvlTargets, event);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
/**
|
|
141
|
+
* Removes all related event listeners from the container.
|
|
142
|
+
*/
|
|
143
|
+
Object.defineProperty(this, "destroy", {
|
|
144
|
+
enumerable: true,
|
|
145
|
+
configurable: true,
|
|
146
|
+
writable: true,
|
|
147
|
+
value: () => {
|
|
148
|
+
this.removeEventListener('mousedown', this.handleMouseDown, true);
|
|
149
|
+
this.removeEventListener('mousemove', this.handleMouseMove, true);
|
|
150
|
+
this.removeEventListener('mouseup', this.handleMouseUp, true);
|
|
151
|
+
this.removeEventListener('dblclick', this.handleMouseUp, true);
|
|
152
|
+
this.removeEventListener('contextmenu', this.handleRightClick, true);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
this.options = options;
|
|
156
|
+
this.addEventListener('mousedown', this.handleMouseDown, true);
|
|
157
|
+
this.addEventListener('mousemove', this.handleMouseMove, true);
|
|
158
|
+
this.addEventListener('mouseup', this.handleMouseUp, true);
|
|
159
|
+
this.addEventListener('dblclick', this.handleDoubleClick, true);
|
|
160
|
+
this.addEventListener('contextmenu', this.handleRightClick, true);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { NVL, Node } from '@neo4j-nvl/core';
|
|
2
|
+
import { BaseInteraction } from './base';
|
|
3
|
+
/**
|
|
4
|
+
* Callbacks for the drag node interaction handler.
|
|
5
|
+
*/
|
|
6
|
+
export type DragNodeInteractionCallbacks = {
|
|
7
|
+
/**
|
|
8
|
+
* Called when node(s) are dragged
|
|
9
|
+
* @param nodes - The node(s) being dragged
|
|
10
|
+
*/
|
|
11
|
+
onDrag: (nodes: Node[]) => void;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Interaction handler for dragging nodes.
|
|
15
|
+
* Dragging is achieved by clicking and dragging on the node.
|
|
16
|
+
* @note When more than one node is selected, all selected nodes will be dragged.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```js
|
|
20
|
+
* const nvl = new NVL(container, nodes, relationships)
|
|
21
|
+
* const dragNodeInteraction = new DragNodeInteraction(nvl)
|
|
22
|
+
*
|
|
23
|
+
* dragNodeInteraction.updateCallback('onDrag', (nodes) => {
|
|
24
|
+
* console.log('Dragged nodes:', nodes)
|
|
25
|
+
* })
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare class DragNodeInteraction extends BaseInteraction<DragNodeInteractionCallbacks> {
|
|
29
|
+
private mousePosition;
|
|
30
|
+
private mouseDownNode;
|
|
31
|
+
private isDrawing;
|
|
32
|
+
private selectedNodes;
|
|
33
|
+
private moveSelectedNodes;
|
|
34
|
+
/**
|
|
35
|
+
* Creates a new instance of the drag node interaction handler.
|
|
36
|
+
* @param nvl - The NVL instance to attach the interaction handler to
|
|
37
|
+
*/
|
|
38
|
+
constructor(nvl: NVL);
|
|
39
|
+
private handleMouseDown;
|
|
40
|
+
private handleMouseMove;
|
|
41
|
+
private handleMouseUp;
|
|
42
|
+
/**
|
|
43
|
+
* Removes all related event listeners from the container.
|
|
44
|
+
*/
|
|
45
|
+
destroy: () => void;
|
|
46
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { NODE_EDGE_WIDTH } from '../constants';
|
|
2
|
+
import { BaseInteraction } from './base';
|
|
3
|
+
/**
|
|
4
|
+
* Interaction handler for dragging nodes.
|
|
5
|
+
* Dragging is achieved by clicking and dragging on the node.
|
|
6
|
+
* @note When more than one node is selected, all selected nodes will be dragged.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```js
|
|
10
|
+
* const nvl = new NVL(container, nodes, relationships)
|
|
11
|
+
* const dragNodeInteraction = new DragNodeInteraction(nvl)
|
|
12
|
+
*
|
|
13
|
+
* dragNodeInteraction.updateCallback('onDrag', (nodes) => {
|
|
14
|
+
* console.log('Dragged nodes:', nodes)
|
|
15
|
+
* })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export class DragNodeInteraction extends BaseInteraction {
|
|
19
|
+
/**
|
|
20
|
+
* Creates a new instance of the drag node interaction handler.
|
|
21
|
+
* @param nvl - The NVL instance to attach the interaction handler to
|
|
22
|
+
*/
|
|
23
|
+
constructor(nvl) {
|
|
24
|
+
super(nvl);
|
|
25
|
+
Object.defineProperty(this, "mousePosition", {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
configurable: true,
|
|
28
|
+
writable: true,
|
|
29
|
+
value: void 0
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(this, "mouseDownNode", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
writable: true,
|
|
35
|
+
value: void 0
|
|
36
|
+
});
|
|
37
|
+
Object.defineProperty(this, "isDrawing", {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
configurable: true,
|
|
40
|
+
writable: true,
|
|
41
|
+
value: void 0
|
|
42
|
+
});
|
|
43
|
+
Object.defineProperty(this, "selectedNodes", {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true,
|
|
46
|
+
writable: true,
|
|
47
|
+
value: void 0
|
|
48
|
+
});
|
|
49
|
+
Object.defineProperty(this, "moveSelectedNodes", {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
configurable: true,
|
|
52
|
+
writable: true,
|
|
53
|
+
value: void 0
|
|
54
|
+
});
|
|
55
|
+
Object.defineProperty(this, "handleMouseDown", {
|
|
56
|
+
enumerable: true,
|
|
57
|
+
configurable: true,
|
|
58
|
+
writable: true,
|
|
59
|
+
value: (event) => {
|
|
60
|
+
this.mousePosition = { x: event.clientX, y: event.clientY };
|
|
61
|
+
const hits = this.nvlInstance.getHits(event, ['node'], { hitNodeMarginWidth: NODE_EDGE_WIDTH });
|
|
62
|
+
const hitNodes = hits.nvlTargets.nodes.filter(node => node.insideNode);
|
|
63
|
+
const hitNodeEdges = hits.nvlTargets.nodes.filter(node => !node.insideNode);
|
|
64
|
+
if (hitNodeEdges.length > 0) {
|
|
65
|
+
this.isDrawing = true;
|
|
66
|
+
this.mouseDownNode = null;
|
|
67
|
+
}
|
|
68
|
+
else if (hitNodes.length > 0) {
|
|
69
|
+
this.mouseDownNode = hits.nvlTargets.nodes[0];
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this.mouseDownNode = null;
|
|
73
|
+
}
|
|
74
|
+
this.selectedNodes = this.nvlInstance.getSelectedNodes();
|
|
75
|
+
if (this.mouseDownNode && this.selectedNodes.map(node => node.id).includes(this.mouseDownNode.data.id)) {
|
|
76
|
+
this.moveSelectedNodes = true;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.moveSelectedNodes = false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
Object.defineProperty(this, "handleMouseMove", {
|
|
84
|
+
enumerable: true,
|
|
85
|
+
configurable: true,
|
|
86
|
+
writable: true,
|
|
87
|
+
value: (event) => {
|
|
88
|
+
// Avoid conflicts on moving node position in drawing process.
|
|
89
|
+
if (!this.mouseDownNode || event.buttons !== 1 || this.isDrawing)
|
|
90
|
+
return;
|
|
91
|
+
const zoom = this.nvlInstance.getScale();
|
|
92
|
+
const dx = (event.clientX - this.mousePosition.x) / zoom * window.devicePixelRatio;
|
|
93
|
+
const dy = (event.clientY - this.mousePosition.y) / zoom * window.devicePixelRatio;
|
|
94
|
+
if (this.moveSelectedNodes) {
|
|
95
|
+
this.nvlInstance.setNodePositions(this.selectedNodes.map((node) => ({ id: node.id, x: node.x +
|
|
96
|
+
dx, y: node.y + dy, pinned: true })), true);
|
|
97
|
+
this.callCallbackIfRegistered('onDrag', this.selectedNodes);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
this.nvlInstance.setNodePositions([{ id: this.mouseDownNode.data.id, x: this.mouseDownNode.targetCoordinates.x + dx, y: this.mouseDownNode.targetCoordinates.y + dy, pinned: true }], true);
|
|
101
|
+
this.callCallbackIfRegistered('onDrag', [this.mouseDownNode.data]);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
Object.defineProperty(this, "handleMouseUp", {
|
|
106
|
+
enumerable: true,
|
|
107
|
+
configurable: true,
|
|
108
|
+
writable: true,
|
|
109
|
+
value: () => {
|
|
110
|
+
this.mouseDownNode = null;
|
|
111
|
+
this.isDrawing = false;
|
|
112
|
+
this.selectedNodes = [];
|
|
113
|
+
this.moveSelectedNodes = false;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
/**
|
|
117
|
+
* Removes all related event listeners from the container.
|
|
118
|
+
*/
|
|
119
|
+
Object.defineProperty(this, "destroy", {
|
|
120
|
+
enumerable: true,
|
|
121
|
+
configurable: true,
|
|
122
|
+
writable: true,
|
|
123
|
+
value: () => {
|
|
124
|
+
this.removeEventListener('mousedown', this.handleMouseDown);
|
|
125
|
+
this.removeEventListener('mousemove', this.handleMouseMove);
|
|
126
|
+
this.removeEventListener('mouseup', this.handleMouseUp);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
this.mousePosition = { x: 0, y: 0 };
|
|
130
|
+
this.isDrawing = false;
|
|
131
|
+
this.selectedNodes = [];
|
|
132
|
+
this.moveSelectedNodes = false;
|
|
133
|
+
this.addEventListener('mousedown', this.handleMouseDown);
|
|
134
|
+
this.addEventListener('mousemove', this.handleMouseMove);
|
|
135
|
+
this.addEventListener('mouseup', this.handleMouseUp);
|
|
136
|
+
}
|
|
137
|
+
}
|