@neo4j-nvl/interaction-handlers 0.2.11 → 0.2.13

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/lib/index.d.ts CHANGED
@@ -4,9 +4,9 @@ import { DragNodeInteraction } from './interaction-handlers/drag-node-interactio
4
4
  import type { DragNodeInteractionCallbacks } from './interaction-handlers/drag-node-interaction';
5
5
  import { DrawInteraction } from './interaction-handlers/draw-interaction';
6
6
  import type { DrawInteractionCallbacks } from './interaction-handlers/draw-interaction';
7
- import type { HoverInteractionOptions, HoverInteractionCallbacks } from './interaction-handlers/hover-interaction';
7
+ import type { HoverInteractionCallbacks, HoverInteractionOptions } from './interaction-handlers/hover-interaction';
8
8
  import { HoverInteraction } from './interaction-handlers/hover-interaction';
9
- import type { MultiSelectInteractionOptions, MultiSelectInteractionCallbacks } from './interaction-handlers/multi-select-interaction';
9
+ import type { MultiSelectInteractionCallbacks, MultiSelectInteractionOptions } from './interaction-handlers/multi-select-interaction';
10
10
  import { MultiSelectInteraction } from './interaction-handlers/multi-select-interaction';
11
11
  import type { PanInteractionCallbacks } from './interaction-handlers/pan-interaction';
12
12
  import { PanInteraction } from './interaction-handlers/pan-interaction';
@@ -7,8 +7,9 @@ export type DragNodeInteractionCallbacks = {
7
7
  /**
8
8
  * Called when node(s) are dragged
9
9
  * @param nodes - The node(s) being dragged
10
+ * @param event - The original mouse event
10
11
  */
11
- onDrag?: ((nodes: Node[]) => void) | boolean;
12
+ onDrag?: ((nodes: Node[], event: MouseEvent) => void) | boolean;
12
13
  };
13
14
  /**
14
15
  * Interaction handler for dragging nodes.
@@ -59,8 +59,8 @@ export class DragNodeInteraction extends BaseInteraction {
59
59
  value: (event) => {
60
60
  this.mousePosition = { x: event.clientX, y: event.clientY };
61
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);
62
+ const hitNodes = hits.nvlTargets.nodes.filter((node) => node.insideNode);
63
+ const hitNodeEdges = hits.nvlTargets.nodes.filter((node) => !node.insideNode);
64
64
  if (hitNodeEdges.length > 0) {
65
65
  this.isDrawing = true;
66
66
  this.mouseDownNode = null;
@@ -72,7 +72,7 @@ export class DragNodeInteraction extends BaseInteraction {
72
72
  this.mouseDownNode = null;
73
73
  }
74
74
  this.selectedNodes = this.nvlInstance.getSelectedNodes();
75
- if (this.mouseDownNode && this.selectedNodes.map(node => node.id).includes(this.mouseDownNode.data.id)) {
75
+ if (this.mouseDownNode && this.selectedNodes.map((node) => node.id).includes(this.mouseDownNode.data.id)) {
76
76
  this.moveSelectedNodes = true;
77
77
  }
78
78
  else {
@@ -89,16 +89,22 @@ export class DragNodeInteraction extends BaseInteraction {
89
89
  if (!this.mouseDownNode || event.buttons !== 1 || this.isDrawing)
90
90
  return;
91
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;
92
+ const dx = ((event.clientX - this.mousePosition.x) / zoom) * window.devicePixelRatio;
93
+ const dy = ((event.clientY - this.mousePosition.y) / zoom) * window.devicePixelRatio;
94
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);
95
+ this.nvlInstance.setNodePositions(this.selectedNodes.map((node) => ({ id: node.id, x: node.x + dx, y: node.y + dy, pinned: true })), true);
96
+ this.callCallbackIfRegistered('onDrag', this.selectedNodes, event);
98
97
  }
99
98
  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]);
99
+ this.nvlInstance.setNodePositions([
100
+ {
101
+ id: this.mouseDownNode.data.id,
102
+ x: this.mouseDownNode.targetCoordinates.x + dx,
103
+ y: this.mouseDownNode.targetCoordinates.y + dy,
104
+ pinned: true
105
+ }
106
+ ], true);
107
+ this.callCallbackIfRegistered('onDrag', [this.mouseDownNode.data], event);
102
108
  }
103
109
  }
104
110
  });
@@ -5,7 +5,7 @@ import { BaseInteraction } from './base';
5
5
  * @experimental
6
6
  */
7
7
  export type DrawInteractionCallbacks = {
8
- onDrawEnd?: ((newRelationshipToAdd: Relationship | null, newTargetNodeToAdd: Node | null) => void) | boolean;
8
+ onDrawEnd?: ((newRelationshipToAdd: Relationship | null, newTargetNodeToAdd: Node | null, event: MouseEvent) => void) | boolean;
9
9
  };
10
10
  /**
11
11
  * @internal
@@ -1,7 +1,7 @@
1
- import { OverlayRenderer } from '../overlay-renderer/overlay-renderer';
2
- import { generateUniqueId } from './utils';
3
1
  import { NODE_EDGE_WIDTH } from '../constants';
2
+ import { OverlayRenderer } from '../overlay-renderer/overlay-renderer';
4
3
  import { BaseInteraction } from './base';
4
+ import { generateUniqueId } from './utils';
5
5
  /**
6
6
  * @internal
7
7
  * @experimental
@@ -87,14 +87,26 @@ export class DrawInteraction extends BaseInteraction {
87
87
  // Rename to getMousePosition in world coordinate
88
88
  const pos = this.nvlInstance.getMousePosition(event);
89
89
  const hits = this.nvlInstance.getHits(event, ['node']);
90
- const hitNode = hits.nvlTargets.nodes.filter(n => n.data.id !== this.newTempTargetNode.id)[0];
91
- const targetNode = hitNode ? { id: hitNode.data.id, x: hitNode.targetCoordinates.x, y: hitNode.targetCoordinates.y, size: hitNode.data.size } : undefined;
90
+ const hitNode = hits.nvlTargets.nodes.filter((n) => n.data.id !== this.newTempTargetNode.id)[0];
91
+ const targetNode = hitNode
92
+ ? {
93
+ id: hitNode.data.id,
94
+ x: hitNode.targetCoordinates.x,
95
+ y: hitNode.targetCoordinates.y,
96
+ size: hitNode.data.size
97
+ }
98
+ : undefined;
92
99
  // ArrowBundler has race-condition to update the dataset, if we remove the node with the same ID after mouse releases, the same node will be removed then be added again, which will cause the issue.
93
100
  // So always make sure the new node id to be added to the dataset after mouse releasing is a new id.
94
101
  const newTargetNodeId = generateUniqueId(13);
95
102
  const newTargetNode = targetNode ? null : { id: newTargetNodeId, size: 25, selected: false, x: pos.x, y: pos.y };
96
103
  const newRelationshipId = generateUniqueId(13);
97
- const relationship = { id: newRelationshipId, from: this.mouseDownNode.data.id, to: targetNode ? targetNode.id : newTargetNodeId, captions: [{ value: 'TEST' }] };
104
+ const relationship = {
105
+ id: newRelationshipId,
106
+ from: this.mouseDownNode.data.id,
107
+ to: targetNode ? targetNode.id : newTargetNodeId,
108
+ captions: [{ value: 'TEST' }]
109
+ };
98
110
  let x = pos.x;
99
111
  let y = pos.y;
100
112
  let size = 25;
@@ -103,14 +115,20 @@ export class DrawInteraction extends BaseInteraction {
103
115
  y = hitNode.targetCoordinates.y;
104
116
  size = hitNode.data.size;
105
117
  if (hitNode.data.id === this.mouseDownNode.data.id && !this.newTempSelfReferredRelationship) {
106
- this.nvlInstance.removeRelationshipsWithIds([(_a = this.newTempRegularRelationshipToNewTempTargetNode) === null || _a === void 0 ? void 0 : _a.id, (_b = this.newTempRegularRelationshipToExistingNode) === null || _b === void 0 ? void 0 : _b.id]);
118
+ this.nvlInstance.removeRelationshipsWithIds([
119
+ (_a = this.newTempRegularRelationshipToNewTempTargetNode) === null || _a === void 0 ? void 0 : _a.id,
120
+ (_b = this.newTempRegularRelationshipToExistingNode) === null || _b === void 0 ? void 0 : _b.id
121
+ ]);
107
122
  this.newTempRegularRelationshipToNewTempTargetNode = null;
108
123
  this.newTempRegularRelationshipToExistingNode = null;
109
124
  this.setNewSelfReferredRelationship();
110
125
  this.nvlInstance.addElementsToGraph([], [this.newTempSelfReferredRelationship]);
111
126
  }
112
127
  else if (hitNode.data.id !== this.mouseDownNode.data.id && !this.newTempRegularRelationshipToExistingNode) {
113
- this.nvlInstance.removeRelationshipsWithIds([(_c = this.newTempSelfReferredRelationship) === null || _c === void 0 ? void 0 : _c.id, (_d = this.newTempRegularRelationshipToNewTempTargetNode) === null || _d === void 0 ? void 0 : _d.id]);
128
+ this.nvlInstance.removeRelationshipsWithIds([
129
+ (_c = this.newTempSelfReferredRelationship) === null || _c === void 0 ? void 0 : _c.id,
130
+ (_d = this.newTempRegularRelationshipToNewTempTargetNode) === null || _d === void 0 ? void 0 : _d.id
131
+ ]);
114
132
  this.newTempSelfReferredRelationship = null;
115
133
  this.newTempRegularRelationshipToNewTempTargetNode = null;
116
134
  this.setNewRegularRelationshipToExistingNode(hitNode.data.id);
@@ -118,7 +136,10 @@ export class DrawInteraction extends BaseInteraction {
118
136
  }
119
137
  }
120
138
  else if (!this.newTempRegularRelationshipToNewTempTargetNode) {
121
- this.nvlInstance.removeRelationshipsWithIds([(_e = this.newTempSelfReferredRelationship) === null || _e === void 0 ? void 0 : _e.id, (_f = this.newTempRegularRelationshipToExistingNode) === null || _f === void 0 ? void 0 : _f.id]);
139
+ this.nvlInstance.removeRelationshipsWithIds([
140
+ (_e = this.newTempSelfReferredRelationship) === null || _e === void 0 ? void 0 : _e.id,
141
+ (_f = this.newTempRegularRelationshipToExistingNode) === null || _f === void 0 ? void 0 : _f.id
142
+ ]);
122
143
  this.newTempSelfReferredRelationship = null;
123
144
  this.newTempRegularRelationshipToExistingNode = null;
124
145
  this.setNewRegularRelationshipToNewTempTargetNode();
@@ -133,7 +154,7 @@ export class DrawInteraction extends BaseInteraction {
133
154
  this.newRelationshipToAdd = null;
134
155
  this.newTargetNodeToAdd = null;
135
156
  const hits = this.nvlInstance.getHits(event, ['node'], { hitNodeMarginWidth: NODE_EDGE_WIDTH });
136
- const hitNodeEdges = hits.nvlTargets.nodes.filter(node => !node.insideNode);
157
+ const hitNodeEdges = hits.nvlTargets.nodes.filter((node) => !node.insideNode);
137
158
  if (hitNodeEdges.length > 0) {
138
159
  const node = hitNodeEdges[0];
139
160
  const zoom = this.nvlInstance.getScale();
@@ -163,8 +184,8 @@ export class DrawInteraction extends BaseInteraction {
163
184
  this.newRelationshipToAdd = null;
164
185
  this.newTargetNodeToAdd = null;
165
186
  const hits = this.nvlInstance.getHits(event, ['node'], { hitNodeMarginWidth: NODE_EDGE_WIDTH });
166
- const hitNodes = hits.nvlTargets.nodes.filter(node => node.insideNode);
167
- const hitNodeEdges = hits.nvlTargets.nodes.filter(node => !node.insideNode);
187
+ const hitNodes = hits.nvlTargets.nodes.filter((node) => node.insideNode);
188
+ const hitNodeEdges = hits.nvlTargets.nodes.filter((node) => !node.insideNode);
168
189
  if (hitNodes.length > 0) {
169
190
  this.isDraggingNode = true;
170
191
  this.isDrawing = false;
@@ -174,7 +195,14 @@ export class DrawInteraction extends BaseInteraction {
174
195
  this.isDraggingNode = false;
175
196
  this.mouseDownNode = hitNodeEdges[0];
176
197
  const pos = this.nvlInstance.getMousePosition(event);
177
- this.newTempTargetNode = { id: generateUniqueId(13), size: 25, selected: false, x: pos.x, y: pos.y, color: 'black' };
198
+ this.newTempTargetNode = {
199
+ id: generateUniqueId(13),
200
+ size: 25,
201
+ selected: false,
202
+ x: pos.x,
203
+ y: pos.y,
204
+ color: 'black'
205
+ };
178
206
  this.setNewRegularRelationshipToNewTempTargetNode();
179
207
  this.nvlInstance.addAndUpdateElementsInGraph([this.newTempTargetNode], [this.newTempRegularRelationshipToNewTempTargetNode]);
180
208
  }
@@ -189,15 +217,19 @@ export class DrawInteraction extends BaseInteraction {
189
217
  enumerable: true,
190
218
  configurable: true,
191
219
  writable: true,
192
- value: () => {
220
+ value: (event) => {
193
221
  var _a, _b, _c, _d;
194
- this.nvlInstance.removeRelationshipsWithIds([(_a = this.newTempRegularRelationshipToNewTempTargetNode) === null || _a === void 0 ? void 0 : _a.id, (_b = this.newTempRegularRelationshipToExistingNode) === null || _b === void 0 ? void 0 : _b.id, (_c = this.newTempSelfReferredRelationship) === null || _c === void 0 ? void 0 : _c.id]);
222
+ this.nvlInstance.removeRelationshipsWithIds([
223
+ (_a = this.newTempRegularRelationshipToNewTempTargetNode) === null || _a === void 0 ? void 0 : _a.id,
224
+ (_b = this.newTempRegularRelationshipToExistingNode) === null || _b === void 0 ? void 0 : _b.id,
225
+ (_c = this.newTempSelfReferredRelationship) === null || _c === void 0 ? void 0 : _c.id
226
+ ]);
195
227
  this.nvlInstance.removeNodesWithIds([(_d = this.newTempTargetNode) === null || _d === void 0 ? void 0 : _d.id]);
196
228
  if (this.isDrawing && this.isMoved) {
197
229
  this.newTargetNodeToAdd && this.nvlInstance.setNodePositions([this.newTargetNodeToAdd]);
198
230
  // Avoid relationship glitch
199
231
  this.nvlInstance.addAndUpdateElementsInGraph(this.newTargetNodeToAdd ? [{ id: this.newTargetNodeToAdd.id }] : [], [this.newRelationshipToAdd]);
200
- this.callCallbackIfRegistered('onDrawEnd', this.newRelationshipToAdd, this.newTargetNodeToAdd);
232
+ this.callCallbackIfRegistered('onDrawEnd', this.newRelationshipToAdd, this.newTargetNodeToAdd, event);
201
233
  }
202
234
  this.newTempTargetNode = null;
203
235
  this.newTempRegularRelationshipToNewTempTargetNode = null;
@@ -235,7 +267,13 @@ export class DrawInteraction extends BaseInteraction {
235
267
  if (!this.mouseDownNode) {
236
268
  return;
237
269
  }
238
- return { id: generateUniqueId(13), from: this.mouseDownNode.data.id, to: targetId, captions: [{ value: 'TEST' }], color: 'red' };
270
+ return {
271
+ id: generateUniqueId(13),
272
+ from: this.mouseDownNode.data.id,
273
+ to: targetId,
274
+ captions: [{ value: 'TEST' }],
275
+ color: 'red'
276
+ };
239
277
  }
240
278
  setNewRegularRelationshipToNewTempTargetNode() {
241
279
  if (!this.mouseDownNode || !this.newTempTargetNode) {
@@ -253,6 +291,12 @@ export class DrawInteraction extends BaseInteraction {
253
291
  if (!this.mouseDownNode) {
254
292
  return;
255
293
  }
256
- this.newTempSelfReferredRelationship = { id: generateUniqueId(13), from: this.mouseDownNode.data.id, to: this.mouseDownNode.data.id, captions: [{ value: 'TEST' }], color: 'red' };
294
+ this.newTempSelfReferredRelationship = {
295
+ id: generateUniqueId(13),
296
+ from: this.mouseDownNode.data.id,
297
+ to: this.mouseDownNode.data.id,
298
+ captions: [{ value: 'TEST' }],
299
+ color: 'red'
300
+ };
257
301
  }
258
302
  }
@@ -13,13 +13,13 @@ export type MultiSelectInteractionOptions = {
13
13
  export type MultiSelectInteractionCallbacks = {
14
14
  /**
15
15
  * Called after once the user releases the mouse after multi-selecting.
16
- * @param nodes - The nodes that were selected
17
- * @param rels - The relationships that were selected
16
+ * @param selectionObject - The selected nodes and relationships
17
+ * @param event - The original mouse event
18
18
  */
19
19
  onMultiSelect?: (({ nodes, rels }: {
20
20
  nodes: Node[];
21
21
  rels: Relationship[];
22
- }) => void) | boolean;
22
+ }, event: MouseEvent) => void) | boolean;
23
23
  };
24
24
  /**
25
25
  * Interaction handler for multi-selecting nodes and relationships.
@@ -93,7 +93,7 @@ export class MultiSelectInteraction extends BaseInteraction {
93
93
  if (this.options.selectOnRelease) {
94
94
  this.nvlInstance.updateElementsInGraph(nodes.map((node) => ({ id: node.id, selected: true })), rels.map((rel) => ({ id: rel.id, selected: true })));
95
95
  }
96
- this.callCallbackIfRegistered('onMultiSelect', { nodes, rels });
96
+ this.callCallbackIfRegistered('onMultiSelect', { nodes, rels }, event);
97
97
  }
98
98
  });
99
99
  this.mousePosition = { x: 0, y: 0 };
@@ -7,11 +7,12 @@ export type PanInteractionCallbacks = {
7
7
  /**
8
8
  * Called when the canvas is panned.
9
9
  * @param panning - The panning coordinates
10
+ * @param event - The original mouse event
10
11
  */
11
12
  onPan?: ((panning: {
12
13
  x: number;
13
14
  y: number;
14
- }) => void) | boolean;
15
+ }, event: MouseEvent) => void) | boolean;
15
16
  };
16
17
  /**
17
18
  * Interaction handler for panning the canvas.
@@ -71,7 +71,9 @@ export class PanInteraction extends BaseInteraction {
71
71
  configurable: true,
72
72
  writable: true,
73
73
  value: (event) => {
74
- const hits = this.nvlInstance.getHits(event, difference(['node', 'relationship'], this.targets), { hitNodeMarginWidth: this.excludeNodeMargin ? NODE_EDGE_WIDTH : 0 });
74
+ const hits = this.nvlInstance.getHits(event, difference(['node', 'relationship'], this.targets), {
75
+ hitNodeMarginWidth: this.excludeNodeMargin ? NODE_EDGE_WIDTH : 0
76
+ });
75
77
  if (hits.nvlTargets.nodes.length > 0 || hits.nvlTargets.relationships.length > 0) {
76
78
  this.shouldPan = false;
77
79
  }
@@ -91,10 +93,10 @@ export class PanInteraction extends BaseInteraction {
91
93
  }
92
94
  const zoom = this.nvlInstance.getScale();
93
95
  const { x, y } = this.nvlInstance.getPan();
94
- const dx = (evt.clientX - this.mousePosition.x) / zoom * window.devicePixelRatio;
95
- const dy = (evt.clientY - this.mousePosition.y) / zoom * window.devicePixelRatio;
96
+ const dx = ((evt.clientX - this.mousePosition.x) / zoom) * window.devicePixelRatio;
97
+ const dy = ((evt.clientY - this.mousePosition.y) / zoom) * window.devicePixelRatio;
96
98
  this.nvlInstance.setPan(x - dx, y - dy);
97
- this.callCallbackIfRegistered('onPan', { x: x - dx, y: y - dy });
99
+ this.callCallbackIfRegistered('onPan', { x: x - dx, y: y - dy }, evt);
98
100
  this.mousePosition = { x: evt.clientX, y: evt.clientY };
99
101
  }
100
102
  });
@@ -1 +1 @@
1
- export const generateUniqueId = (digit) => Math.floor((Math.random() * Math.pow(10, digit))).toString();
1
+ export const generateUniqueId = (digit) => Math.floor(Math.random() * Math.pow(10, digit)).toString();
@@ -7,8 +7,9 @@ export type ZoomInteractionCallbacks = {
7
7
  /**
8
8
  * Called when the canvas is zoomed.
9
9
  * @param zoomLevel - The zoom level
10
+ * @param event - The original mouse wheel event
10
11
  */
11
- onZoom?: (zoomLevel: number) => void | boolean;
12
+ onZoom?: (zoomLevel: number, event: WheelEvent) => void | boolean;
12
13
  };
13
14
  /**
14
15
  * Interaction handler for zooming the canvas.
@@ -60,7 +60,7 @@ export class ZoomInteraction extends BaseInteraction {
60
60
  const newPanX = x + (offsetX / zoom - offsetX / newZoomTarget);
61
61
  const newPanY = y + (offsetY / zoom - offsetY / newZoomTarget);
62
62
  this.nvlInstance.setZoomAndPan(newZoomTarget, newPanX, newPanY);
63
- this.callCallbackIfRegistered('onZoom', newZoomTarget);
63
+ this.callCallbackIfRegistered('onZoom', newZoomTarget, event);
64
64
  }, 25, { leading: true })
65
65
  });
66
66
  Object.defineProperty(this, "handleWheel", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neo4j-nvl/interaction-handlers",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "license": "SEE LICENSE IN 'Neo4j Early Access Agreement - Visualization Library.pdf'",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",