@neo4j-nvl/interaction-handlers 0.2.53 → 0.2.55

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.
@@ -2,242 +2,33 @@
2
2
  import { NODE_EDGE_WIDTH } from '../constants';
3
3
  import { BaseInteraction } from './base';
4
4
  import { generateUniqueId, getCanvasPosition, getWorldPosition } from './utils';
5
+ const DefaultGhostGraphStyling = {
6
+ node: {
7
+ color: 'black',
8
+ size: 25
9
+ },
10
+ relationship: {
11
+ color: 'red',
12
+ width: 1
13
+ }
14
+ };
5
15
  /**
6
16
  * @internal
7
17
  * @experimental
8
18
  */
9
19
  export class DrawInteraction extends BaseInteraction {
20
+ isMoved;
21
+ isDrawing;
22
+ isDraggingNode;
23
+ mouseDownNode;
24
+ newTempTargetNode;
25
+ newTempRegularRelationshipToNewTempTargetNode;
26
+ newTempRegularRelationshipToExistingNode;
27
+ newTempSelfReferredRelationship;
28
+ newTargetNodeToAdd;
29
+ newRelationshipToAdd;
10
30
  constructor(nvl, options = {}) {
11
31
  super(nvl, options);
12
- Object.defineProperty(this, "isMoved", {
13
- enumerable: true,
14
- configurable: true,
15
- writable: true,
16
- value: void 0
17
- });
18
- Object.defineProperty(this, "isDrawing", {
19
- enumerable: true,
20
- configurable: true,
21
- writable: true,
22
- value: void 0
23
- });
24
- Object.defineProperty(this, "isDraggingNode", {
25
- enumerable: true,
26
- configurable: true,
27
- writable: true,
28
- value: void 0
29
- });
30
- Object.defineProperty(this, "mouseDownNode", {
31
- enumerable: true,
32
- configurable: true,
33
- writable: true,
34
- value: void 0
35
- });
36
- Object.defineProperty(this, "newTempTargetNode", {
37
- enumerable: true,
38
- configurable: true,
39
- writable: true,
40
- value: void 0
41
- });
42
- Object.defineProperty(this, "newTempRegularRelationshipToNewTempTargetNode", {
43
- enumerable: true,
44
- configurable: true,
45
- writable: true,
46
- value: void 0
47
- });
48
- Object.defineProperty(this, "newTempRegularRelationshipToExistingNode", {
49
- enumerable: true,
50
- configurable: true,
51
- writable: true,
52
- value: void 0
53
- });
54
- Object.defineProperty(this, "newTempSelfReferredRelationship", {
55
- enumerable: true,
56
- configurable: true,
57
- writable: true,
58
- value: void 0
59
- });
60
- Object.defineProperty(this, "newTargetNodeToAdd", {
61
- enumerable: true,
62
- configurable: true,
63
- writable: true,
64
- value: void 0
65
- });
66
- Object.defineProperty(this, "newRelationshipToAdd", {
67
- enumerable: true,
68
- configurable: true,
69
- writable: true,
70
- value: void 0
71
- });
72
- Object.defineProperty(this, "handleMouseMove", {
73
- enumerable: true,
74
- configurable: true,
75
- writable: true,
76
- value: (event) => {
77
- var _a, _b, _c, _d, _e, _f;
78
- this.isMoved = true;
79
- if (this.isDrawing) {
80
- const canvasPos = getCanvasPosition(this.containerInstance, event);
81
- const pos = getWorldPosition(this.nvlInstance, canvasPos);
82
- const hits = this.nvlInstance.getHits(event, ['node']);
83
- const [hitNode] = hits.nvlTargets.nodes.filter((n) => n.data.id !== this.newTempTargetNode.id);
84
- const targetNode = hitNode
85
- ? {
86
- id: hitNode.data.id,
87
- x: hitNode.targetCoordinates.x,
88
- y: hitNode.targetCoordinates.y,
89
- size: hitNode.data.size
90
- }
91
- : undefined;
92
- // ArrowBundler has race-condition to update the dataset,
93
- // if we remove the node with the same ID after mouse releases,
94
- // the same node will be removed then be added again, which will cause the issue.
95
- // So always make sure the new node id to be added to the dataset after mouse releasing is a new id.
96
- const newTargetNodeId = generateUniqueId(13);
97
- const newTargetNode = targetNode ? null : { id: newTargetNodeId, size: 25, selected: false, x: pos.x, y: pos.y };
98
- const newRelationshipId = generateUniqueId(13);
99
- const relationship = {
100
- id: newRelationshipId,
101
- from: this.mouseDownNode.data.id,
102
- to: targetNode ? targetNode.id : newTargetNodeId,
103
- captions: [{ value: 'TEST' }]
104
- };
105
- let { x, y } = pos;
106
- let size = 25;
107
- if (hitNode) {
108
- x = hitNode.targetCoordinates.x;
109
- y = hitNode.targetCoordinates.y;
110
- size = hitNode.data.size;
111
- if (hitNode.data.id === this.mouseDownNode.data.id && !this.newTempSelfReferredRelationship) {
112
- this.nvlInstance.removeRelationshipsWithIds([
113
- (_a = this.newTempRegularRelationshipToNewTempTargetNode) === null || _a === void 0 ? void 0 : _a.id,
114
- (_b = this.newTempRegularRelationshipToExistingNode) === null || _b === void 0 ? void 0 : _b.id
115
- ]);
116
- this.newTempRegularRelationshipToNewTempTargetNode = null;
117
- this.newTempRegularRelationshipToExistingNode = null;
118
- this.setNewSelfReferredRelationship();
119
- this.nvlInstance.addElementsToGraph([], [this.newTempSelfReferredRelationship]);
120
- }
121
- else if (hitNode.data.id !== this.mouseDownNode.data.id && !this.newTempRegularRelationshipToExistingNode) {
122
- this.nvlInstance.removeRelationshipsWithIds([
123
- (_c = this.newTempSelfReferredRelationship) === null || _c === void 0 ? void 0 : _c.id,
124
- (_d = this.newTempRegularRelationshipToNewTempTargetNode) === null || _d === void 0 ? void 0 : _d.id
125
- ]);
126
- this.newTempSelfReferredRelationship = null;
127
- this.newTempRegularRelationshipToNewTempTargetNode = null;
128
- this.setNewRegularRelationshipToExistingNode(hitNode.data.id);
129
- this.nvlInstance.addElementsToGraph([], [this.newTempRegularRelationshipToExistingNode]);
130
- }
131
- }
132
- else if (!this.newTempRegularRelationshipToNewTempTargetNode) {
133
- this.nvlInstance.removeRelationshipsWithIds([
134
- (_e = this.newTempSelfReferredRelationship) === null || _e === void 0 ? void 0 : _e.id,
135
- (_f = this.newTempRegularRelationshipToExistingNode) === null || _f === void 0 ? void 0 : _f.id
136
- ]);
137
- this.newTempSelfReferredRelationship = null;
138
- this.newTempRegularRelationshipToExistingNode = null;
139
- this.setNewRegularRelationshipToNewTempTargetNode();
140
- this.nvlInstance.addElementsToGraph([], [this.newTempRegularRelationshipToNewTempTargetNode]);
141
- }
142
- this.nvlInstance.setNodePositions([{ id: this.newTempTargetNode.id, x, y }]);
143
- this.nvlInstance.updateElementsInGraph([{ id: this.newTempTargetNode.id, x, y, size }], []);
144
- this.newRelationshipToAdd = relationship;
145
- this.newTargetNodeToAdd = newTargetNode;
146
- }
147
- else if (!this.isDraggingNode) {
148
- this.newRelationshipToAdd = null;
149
- this.newTargetNodeToAdd = null;
150
- const hits = this.nvlInstance.getHits(event, ['node'], { hitNodeMarginWidth: NODE_EDGE_WIDTH });
151
- const hitNodeEdges = hits.nvlTargets.nodes.filter((node) => !node.insideNode);
152
- if (hitNodeEdges.length > 0) {
153
- const [node] = hitNodeEdges;
154
- this.callCallbackIfRegistered('onHoverNodeMargin', node.data);
155
- }
156
- else {
157
- this.callCallbackIfRegistered('onHoverNodeMargin', null);
158
- }
159
- }
160
- }
161
- });
162
- Object.defineProperty(this, "handleMouseDown", {
163
- enumerable: true,
164
- configurable: true,
165
- writable: true,
166
- value: (event) => {
167
- this.callCallbackIfRegistered('onHoverNodeMargin', null);
168
- this.isMoved = false;
169
- this.newRelationshipToAdd = null;
170
- this.newTargetNodeToAdd = null;
171
- const hits = this.nvlInstance.getHits(event, ['node'], { hitNodeMarginWidth: NODE_EDGE_WIDTH });
172
- const hitNodes = hits.nvlTargets.nodes.filter((node) => node.insideNode);
173
- const hitNodeEdges = hits.nvlTargets.nodes.filter((node) => !node.insideNode);
174
- if (hitNodes.length > 0) {
175
- this.isDraggingNode = true;
176
- this.isDrawing = false;
177
- }
178
- else if (hitNodeEdges.length > 0) {
179
- this.isDrawing = true;
180
- this.isDraggingNode = false;
181
- this.mouseDownNode = hitNodeEdges[0];
182
- const canvasPos = getCanvasPosition(this.containerInstance, event);
183
- const pos = getWorldPosition(this.nvlInstance, canvasPos);
184
- this.newTempTargetNode = {
185
- id: generateUniqueId(13),
186
- size: 25,
187
- selected: false,
188
- x: pos.x,
189
- y: pos.y,
190
- color: 'black'
191
- };
192
- this.setNewRegularRelationshipToNewTempTargetNode();
193
- this.nvlInstance.addAndUpdateElementsInGraph([this.newTempTargetNode], [this.newTempRegularRelationshipToNewTempTargetNode]);
194
- }
195
- else {
196
- this.mouseDownNode = undefined;
197
- this.isDrawing = false;
198
- this.isDraggingNode = false;
199
- }
200
- }
201
- });
202
- Object.defineProperty(this, "handleMouseUp", {
203
- enumerable: true,
204
- configurable: true,
205
- writable: true,
206
- value: (event) => {
207
- var _a, _b, _c, _d;
208
- this.nvlInstance.removeRelationshipsWithIds([
209
- (_a = this.newTempRegularRelationshipToNewTempTargetNode) === null || _a === void 0 ? void 0 : _a.id,
210
- (_b = this.newTempRegularRelationshipToExistingNode) === null || _b === void 0 ? void 0 : _b.id,
211
- (_c = this.newTempSelfReferredRelationship) === null || _c === void 0 ? void 0 : _c.id
212
- ]);
213
- this.nvlInstance.removeNodesWithIds([(_d = this.newTempTargetNode) === null || _d === void 0 ? void 0 : _d.id]);
214
- if (this.isDrawing && this.isMoved) {
215
- if (this.newTargetNodeToAdd) {
216
- this.nvlInstance.setNodePositions([this.newTargetNodeToAdd]);
217
- }
218
- // Avoid relationship glitch.
219
- this.nvlInstance.addAndUpdateElementsInGraph(this.newTargetNodeToAdd ? [{ id: this.newTargetNodeToAdd.id }] : [], [this.newRelationshipToAdd]);
220
- this.callCallbackIfRegistered('onDrawEnd', this.newRelationshipToAdd, this.newTargetNodeToAdd, event);
221
- }
222
- this.newTempTargetNode = null;
223
- this.newTempRegularRelationshipToNewTempTargetNode = null;
224
- this.newTempRegularRelationshipToExistingNode = null;
225
- this.newTempSelfReferredRelationship = null;
226
- this.isMoved = false;
227
- this.isDrawing = false;
228
- this.isDraggingNode = false;
229
- }
230
- });
231
- Object.defineProperty(this, "destroy", {
232
- enumerable: true,
233
- configurable: true,
234
- writable: true,
235
- value: () => {
236
- this.removeEventListener('mousemove', this.handleMouseMove, true);
237
- this.removeEventListener('mousedown', this.handleMouseDown, true);
238
- this.removeEventListener('mouseup', this.handleMouseUp, true);
239
- }
240
- });
241
32
  this.isMoved = false;
242
33
  this.isDrawing = false;
243
34
  this.isDraggingNode = false;
@@ -246,6 +37,99 @@ export class DrawInteraction extends BaseInteraction {
246
37
  this.addEventListener('mousedown', this.handleMouseDown, true);
247
38
  this.addEventListener('mouseup', this.handleMouseUp, true);
248
39
  }
40
+ handleMouseMove = (event) => {
41
+ this.isMoved = true;
42
+ if (this.isDrawing) {
43
+ const canvasPos = getCanvasPosition(this.containerInstance, event);
44
+ const pos = getWorldPosition(this.nvlInstance, canvasPos);
45
+ const hits = this.nvlInstance.getHits(event, ['node']);
46
+ const [hitNode] = hits.nvlTargets.nodes.filter((n) => n.data.id !== this.newTempTargetNode?.id);
47
+ const targetNode = hitNode
48
+ ? {
49
+ id: hitNode.data.id,
50
+ x: hitNode.targetCoordinates.x,
51
+ y: hitNode.targetCoordinates.y,
52
+ size: hitNode.data.size
53
+ }
54
+ : undefined;
55
+ // ArrowBundler has race-condition to update the dataset,
56
+ // if we remove the node with the same ID after mouse releases,
57
+ // the same node will be removed then be added again, which will cause the issue.
58
+ // So always make sure the new node id to be added to the dataset after mouse releasing is a new id.
59
+ const newTargetNodeId = generateUniqueId(13);
60
+ const newTargetNode = targetNode
61
+ ? null
62
+ : {
63
+ id: newTargetNodeId,
64
+ size: this.currentOptions.ghostGraphStyling?.node?.size ?? DefaultGhostGraphStyling.node.size,
65
+ selected: false,
66
+ x: pos.x,
67
+ y: pos.y
68
+ };
69
+ const newRelationshipId = generateUniqueId(13);
70
+ const relationship = this.mouseDownNode?.data
71
+ ? {
72
+ id: newRelationshipId,
73
+ from: this.mouseDownNode.data.id,
74
+ to: targetNode ? targetNode.id : newTargetNodeId
75
+ }
76
+ : null;
77
+ let { x, y } = pos;
78
+ let size = this.currentOptions.ghostGraphStyling?.node?.size ?? DefaultGhostGraphStyling.node.size;
79
+ if (hitNode) {
80
+ x = hitNode.targetCoordinates.x;
81
+ y = hitNode.targetCoordinates.y;
82
+ size = hitNode.data.size ?? size;
83
+ if (hitNode.data.id === this.mouseDownNode?.data.id && !this.newTempSelfReferredRelationship) {
84
+ this.nvlInstance.removeRelationshipsWithIds([
85
+ this.newTempRegularRelationshipToNewTempTargetNode?.id,
86
+ this.newTempRegularRelationshipToExistingNode?.id
87
+ ].filter((id) => Boolean(id)));
88
+ this.newTempRegularRelationshipToNewTempTargetNode = null;
89
+ this.newTempRegularRelationshipToExistingNode = null;
90
+ this.setNewSelfReferredRelationship();
91
+ if (this.newTempSelfReferredRelationship) {
92
+ this.nvlInstance.addElementsToGraph([], [this.newTempSelfReferredRelationship]);
93
+ }
94
+ }
95
+ else if (hitNode.data.id !== this.mouseDownNode?.data.id && !this.newTempRegularRelationshipToExistingNode) {
96
+ this.nvlInstance.removeRelationshipsWithIds([this.newTempSelfReferredRelationship?.id, this.newTempRegularRelationshipToNewTempTargetNode?.id].filter((id) => Boolean(id)));
97
+ this.newTempSelfReferredRelationship = null;
98
+ this.newTempRegularRelationshipToNewTempTargetNode = null;
99
+ this.setNewRegularRelationshipToExistingNode(hitNode.data.id);
100
+ if (this.newTempRegularRelationshipToExistingNode) {
101
+ this.nvlInstance.addElementsToGraph([], [this.newTempRegularRelationshipToExistingNode]);
102
+ }
103
+ }
104
+ }
105
+ else if (!this.newTempRegularRelationshipToNewTempTargetNode) {
106
+ this.nvlInstance.removeRelationshipsWithIds([this.newTempSelfReferredRelationship?.id, this.newTempRegularRelationshipToExistingNode?.id].filter((id) => Boolean(id)));
107
+ this.newTempSelfReferredRelationship = null;
108
+ this.newTempRegularRelationshipToExistingNode = null;
109
+ this.setNewRegularRelationshipToNewTempTargetNode();
110
+ this.nvlInstance.addElementsToGraph([], this.newTempRegularRelationshipToNewTempTargetNode ? [this.newTempRegularRelationshipToNewTempTargetNode] : []);
111
+ }
112
+ if (this.newTempTargetNode) {
113
+ this.nvlInstance.setNodePositions([{ id: this.newTempTargetNode.id, x, y }]);
114
+ this.nvlInstance.updateElementsInGraph([{ id: this.newTempTargetNode.id, x, y, size }], []);
115
+ }
116
+ this.newRelationshipToAdd = relationship;
117
+ this.newTargetNodeToAdd = newTargetNode;
118
+ }
119
+ else if (!this.isDraggingNode) {
120
+ this.newRelationshipToAdd = null;
121
+ this.newTargetNodeToAdd = null;
122
+ const hits = this.nvlInstance.getHits(event, ['node'], { hitNodeMarginWidth: NODE_EDGE_WIDTH });
123
+ const hitNodeEdges = hits.nvlTargets.nodes.filter((node) => !node.insideNode);
124
+ if (hitNodeEdges.length > 0) {
125
+ const [node] = hitNodeEdges;
126
+ this.callCallbackIfRegistered('onHoverNodeMargin', node?.data);
127
+ }
128
+ else {
129
+ this.callCallbackIfRegistered('onHoverNodeMargin', null);
130
+ }
131
+ }
132
+ };
249
133
  setNewRegularRelationship(targetId) {
250
134
  if (!this.mouseDownNode) {
251
135
  return null;
@@ -254,7 +138,8 @@ export class DrawInteraction extends BaseInteraction {
254
138
  id: generateUniqueId(13),
255
139
  from: this.mouseDownNode.data.id,
256
140
  to: targetId,
257
- color: 'red'
141
+ color: this.currentOptions.ghostGraphStyling?.relationship?.color ?? DefaultGhostGraphStyling.relationship.color,
142
+ width: this.currentOptions.ghostGraphStyling?.relationship?.width ?? DefaultGhostGraphStyling.relationship.width
258
143
  };
259
144
  }
260
145
  setNewRegularRelationshipToNewTempTargetNode() {
@@ -277,7 +162,71 @@ export class DrawInteraction extends BaseInteraction {
277
162
  id: generateUniqueId(13),
278
163
  from: this.mouseDownNode.data.id,
279
164
  to: this.mouseDownNode.data.id,
280
- color: 'red'
165
+ color: this.currentOptions.ghostGraphStyling?.relationship?.color ?? DefaultGhostGraphStyling.relationship.color,
166
+ width: this.currentOptions.ghostGraphStyling?.relationship?.width ?? DefaultGhostGraphStyling.relationship.width
281
167
  };
282
168
  }
169
+ handleMouseDown = (event) => {
170
+ this.callCallbackIfRegistered('onHoverNodeMargin', null);
171
+ this.isMoved = false;
172
+ this.newRelationshipToAdd = null;
173
+ this.newTargetNodeToAdd = null;
174
+ const hits = this.nvlInstance.getHits(event, ['node'], { hitNodeMarginWidth: NODE_EDGE_WIDTH });
175
+ const hitNodes = hits.nvlTargets.nodes.filter((node) => node.insideNode);
176
+ const hitNodeEdges = hits.nvlTargets.nodes.filter((node) => !node.insideNode);
177
+ if (hitNodes.length > 0) {
178
+ this.isDraggingNode = true;
179
+ this.isDrawing = false;
180
+ }
181
+ else if (hitNodeEdges.length > 0) {
182
+ this.isDrawing = true;
183
+ this.isDraggingNode = false;
184
+ this.mouseDownNode = hitNodeEdges[0];
185
+ const canvasPos = getCanvasPosition(this.containerInstance, event);
186
+ const pos = getWorldPosition(this.nvlInstance, canvasPos);
187
+ this.newTempTargetNode = {
188
+ id: generateUniqueId(13),
189
+ size: this.currentOptions.ghostGraphStyling?.node?.size ?? DefaultGhostGraphStyling.node.size,
190
+ selected: false,
191
+ x: pos.x,
192
+ y: pos.y,
193
+ color: this.currentOptions.ghostGraphStyling?.node?.color ?? DefaultGhostGraphStyling.node.color
194
+ };
195
+ this.setNewRegularRelationshipToNewTempTargetNode();
196
+ this.nvlInstance.addAndUpdateElementsInGraph([this.newTempTargetNode], this.newTempRegularRelationshipToNewTempTargetNode ? [this.newTempRegularRelationshipToNewTempTargetNode] : []);
197
+ }
198
+ else {
199
+ this.mouseDownNode = undefined;
200
+ this.isDrawing = false;
201
+ this.isDraggingNode = false;
202
+ }
203
+ };
204
+ handleMouseUp = (event) => {
205
+ this.nvlInstance.removeRelationshipsWithIds([
206
+ this.newTempRegularRelationshipToNewTempTargetNode?.id,
207
+ this.newTempRegularRelationshipToExistingNode?.id,
208
+ this.newTempSelfReferredRelationship?.id
209
+ ].filter((id) => Boolean(id)));
210
+ this.nvlInstance.removeNodesWithIds(this.newTempTargetNode?.id ? [this.newTempTargetNode?.id] : []);
211
+ if (this.isDrawing && this.isMoved) {
212
+ if (this.newTargetNodeToAdd) {
213
+ this.nvlInstance.setNodePositions([this.newTargetNodeToAdd]);
214
+ }
215
+ // Avoid relationship glitch.
216
+ this.nvlInstance.addAndUpdateElementsInGraph(this.newTargetNodeToAdd ? [{ id: this.newTargetNodeToAdd.id }] : [], this.newRelationshipToAdd ? [this.newRelationshipToAdd] : []);
217
+ this.callCallbackIfRegistered('onDrawEnd', this.newRelationshipToAdd, this.newTargetNodeToAdd, event);
218
+ }
219
+ this.newTempTargetNode = null;
220
+ this.newTempRegularRelationshipToNewTempTargetNode = null;
221
+ this.newTempRegularRelationshipToExistingNode = null;
222
+ this.newTempSelfReferredRelationship = null;
223
+ this.isMoved = false;
224
+ this.isDrawing = false;
225
+ this.isDraggingNode = false;
226
+ };
227
+ destroy = () => {
228
+ this.removeEventListener('mousemove', this.handleMouseMove, true);
229
+ this.removeEventListener('mousedown', this.handleMouseDown, true);
230
+ this.removeEventListener('mouseup', this.handleMouseUp, true);
231
+ };
283
232
  }
@@ -15,76 +15,56 @@ import { BaseInteraction } from './base';
15
15
  * ```
16
16
  */
17
17
  export class HoverInteraction extends BaseInteraction {
18
+ currentHoveredElement;
19
+ currentHoveredElementIsNode;
20
+ updates;
18
21
  constructor(nvl, options = { drawShadowOnHover: false }) {
19
22
  super(nvl, options);
20
- Object.defineProperty(this, "currentHoveredElement", {
21
- enumerable: true,
22
- configurable: true,
23
- writable: true,
24
- value: void 0
25
- });
26
- Object.defineProperty(this, "currentHoveredElementIsNode", {
27
- enumerable: true,
28
- configurable: true,
29
- writable: true,
30
- value: void 0
31
- });
32
- Object.defineProperty(this, "updates", {
33
- enumerable: true,
34
- configurable: true,
35
- writable: true,
36
- value: void 0
37
- });
38
- /**
39
- * Handle mouse hover events
40
- * @param {MouseEvent} event - The mouse event
41
- */
42
- Object.defineProperty(this, "handleHover", {
43
- enumerable: true,
44
- configurable: true,
45
- writable: true,
46
- value: (event) => {
47
- const { nvlTargets } = this.nvlInstance.getHits(event);
48
- const { nodes = [], relationships = [] } = nvlTargets;
49
- const mainTarget = nodes[0] !== undefined ? nodes[0] : relationships[0];
50
- const hoveredElement = mainTarget === null || mainTarget === void 0 ? void 0 : mainTarget.data;
51
- if (this.currentElementNeedsUnHover(hoveredElement === null || hoveredElement === void 0 ? void 0 : hoveredElement.id)) {
52
- this.unHoverCurrentElement();
53
- }
54
- const currentHoveredElementIsNode = hoveredElement !== undefined && nodes[0] !== undefined;
55
- if (currentHoveredElementIsNode) {
56
- this.updates.nodes.push({ id: hoveredElement.id, hovered: true });
57
- this.currentHoveredElement = hoveredElement;
58
- this.currentHoveredElementIsNode = true;
59
- }
60
- else if (mainTarget !== undefined) {
61
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
62
- const { id, from, to } = hoveredElement;
63
- this.updates.relationships.push({ id, from, to, hovered: true });
64
- this.currentHoveredElement = hoveredElement;
65
- this.currentHoveredElementIsNode = false;
66
- }
67
- else {
68
- this.currentHoveredElement = undefined;
69
- this.currentHoveredElementIsNode = undefined;
70
- }
71
- this.callCallbackIfRegistered('onHover', this.currentHoveredElement, nvlTargets, event);
72
- // Use pure update API to avoid the previous removed node to be re-added to the scene.
73
- if (this.currentOptions.drawShadowOnHover) {
74
- const currentNodes = this.nvlInstance.getNodes();
75
- if (currentNodes.length > 0) {
76
- this.nvlInstance.updateElementsInGraph(this.updates.nodes, this.updates.relationships);
77
- }
78
- }
79
- this.clearUpdates();
80
- }
81
- });
82
23
  this.updates = {
83
24
  nodes: [],
84
25
  relationships: []
85
26
  };
86
27
  this.addEventListener('mousemove', this.handleHover, true);
87
28
  }
29
+ /**
30
+ * Handle mouse hover events
31
+ * @param {MouseEvent} event - The mouse event
32
+ */
33
+ handleHover = (event) => {
34
+ const { nvlTargets } = this.nvlInstance.getHits(event);
35
+ const { nodes = [], relationships = [] } = nvlTargets;
36
+ const mainTarget = nodes[0] !== undefined ? nodes[0] : relationships[0];
37
+ const hoveredElement = mainTarget?.data;
38
+ if (this.currentElementNeedsUnHover(hoveredElement?.id)) {
39
+ this.unHoverCurrentElement();
40
+ }
41
+ const currentHoveredElementIsNode = hoveredElement !== undefined && nodes[0] !== undefined;
42
+ if (currentHoveredElementIsNode) {
43
+ this.updates.nodes.push({ id: hoveredElement.id, hovered: true });
44
+ this.currentHoveredElement = hoveredElement;
45
+ this.currentHoveredElementIsNode = true;
46
+ }
47
+ else if (mainTarget !== undefined) {
48
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
49
+ const { id, from, to } = hoveredElement;
50
+ this.updates.relationships.push({ id, from, to, hovered: true });
51
+ this.currentHoveredElement = hoveredElement;
52
+ this.currentHoveredElementIsNode = false;
53
+ }
54
+ else {
55
+ this.currentHoveredElement = undefined;
56
+ this.currentHoveredElementIsNode = undefined;
57
+ }
58
+ this.callCallbackIfRegistered('onHover', this.currentHoveredElement, nvlTargets, event);
59
+ // Use pure update API to avoid the previous removed node to be re-added to the scene.
60
+ if (this.currentOptions.drawShadowOnHover === true) {
61
+ const currentNodes = this.nvlInstance.getNodes();
62
+ if (currentNodes.length > 0) {
63
+ this.nvlInstance.updateElementsInGraph(this.updates.nodes, this.updates.relationships);
64
+ }
65
+ }
66
+ this.clearUpdates();
67
+ };
88
68
  clearUpdates() {
89
69
  this.updates.nodes = [];
90
70
  this.updates.relationships = [];
@@ -93,17 +73,20 @@ export class HoverInteraction extends BaseInteraction {
93
73
  return this.currentHoveredElement !== undefined && this.currentHoveredElement.id !== newHoveredElementId;
94
74
  }
95
75
  unHoverCurrentElement() {
76
+ if (this.currentHoveredElement === undefined) {
77
+ return;
78
+ }
96
79
  const update = {
97
80
  id: this.currentHoveredElement.id,
98
81
  hovered: false
99
82
  };
100
- if (this.currentHoveredElementIsNode) {
83
+ if (this.currentHoveredElementIsNode === true) {
101
84
  this.updates.nodes.push(update);
102
85
  }
103
86
  else {
104
87
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
105
88
  const { from, to } = this.currentHoveredElement;
106
- this.updates.relationships.push(Object.assign(Object.assign({}, update), { from, to }));
89
+ this.updates.relationships.push({ ...update, from, to });
107
90
  }
108
91
  }
109
92
  destroy() {