@neo4j-nvl/interaction-handlers 2.0.0 → 2.1.0
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/CHANGELOG.md +25 -1
- package/README.md +8 -0
- package/lib/constants.d.ts +1 -1
- package/lib/constants.js +4 -2
- package/lib/index.d.ts +10 -20
- package/lib/index.js +10 -10
- package/lib/interaction-handlers/base.d.ts +67 -67
- package/lib/interaction-handlers/base.js +98 -104
- package/lib/interaction-handlers/box-select-interaction.d.ts +44 -44
- package/lib/interaction-handlers/box-select-interaction.js +133 -127
- package/lib/interaction-handlers/click-interaction.d.ts +111 -111
- package/lib/interaction-handlers/click-interaction.js +116 -131
- package/lib/interaction-handlers/drag-node-interaction.d.ts +40 -40
- package/lib/interaction-handlers/drag-node-interaction.js +102 -111
- package/lib/interaction-handlers/draw-interaction.d.ts +37 -37
- package/lib/interaction-handlers/draw-interaction.js +245 -278
- package/lib/interaction-handlers/hover-interaction.d.ts +34 -30
- package/lib/interaction-handlers/hover-interaction.js +83 -89
- package/lib/interaction-handlers/keyboard-interaction.d.ts +149 -97
- package/lib/interaction-handlers/keyboard-interaction.js +255 -201
- package/lib/interaction-handlers/lasso-interaction.d.ts +45 -45
- package/lib/interaction-handlers/lasso-interaction.js +174 -196
- package/lib/interaction-handlers/pan-interaction.d.ts +62 -61
- package/lib/interaction-handlers/pan-interaction.js +111 -100
- package/lib/interaction-handlers/utils.d.ts +2 -2
- package/lib/interaction-handlers/utils.js +39 -38
- package/lib/interaction-handlers/zoom-interaction.d.ts +52 -48
- package/lib/interaction-handlers/zoom-interaction.js +73 -71
- package/lib/overlay-renderer/overlay-renderer.d.ts +13 -13
- package/lib/overlay-renderer/overlay-renderer.js +96 -111
- package/package.json +19 -6
- package/lib/__tests__/box-select-interaction.test.d.ts +0 -1
- package/lib/__tests__/box-select-interaction.test.js +0 -149
- package/lib/__tests__/click-interaction.test.d.ts +0 -1
- package/lib/__tests__/click-interaction.test.js +0 -505
- package/lib/__tests__/drag-node-interaction.test.d.ts +0 -1
- package/lib/__tests__/drag-node-interaction.test.js +0 -247
- package/lib/__tests__/hover-interaction.test.d.ts +0 -1
- package/lib/__tests__/hover-interaction.test.js +0 -374
- package/lib/__tests__/keyboard-interaction.test.d.ts +0 -1
- package/lib/__tests__/keyboard-interaction.test.js +0 -322
- package/lib/__tests__/lasso-interaction.test.d.ts +0 -1
- package/lib/__tests__/lasso-interaction.test.js +0 -219
- package/lib/__tests__/pan-interaction.test.d.ts +0 -1
- package/lib/__tests__/pan-interaction.test.js +0 -223
- package/lib/__tests__/utils.test.d.ts +0 -1
- package/lib/__tests__/utils.test.js +0 -19
- package/lib/__tests__/zoom-interaction.test.d.ts +0 -1
- package/lib/__tests__/zoom-interaction.test.js +0 -185
|
@@ -1,101 +1,112 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import "../constants.js";
|
|
2
|
+
import { BaseInteraction } from "./base.js";
|
|
3
|
+
import { difference } from "lodash-es";
|
|
4
|
+
// src/interaction-handlers/pan-interaction.ts
|
|
4
5
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
6
|
+
* Interaction handler for panning the scene, which is achieved by clicking and moving the scene.
|
|
7
|
+
*
|
|
8
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_paninteraction Pan Interaction documentation page}.
|
|
9
|
+
*/
|
|
10
|
+
var PanInteraction = class extends BaseInteraction {
|
|
11
|
+
initialMousePosition = {
|
|
12
|
+
x: 0,
|
|
13
|
+
y: 0
|
|
14
|
+
};
|
|
15
|
+
initialPan = {
|
|
16
|
+
x: 0,
|
|
17
|
+
y: 0
|
|
18
|
+
};
|
|
19
|
+
targets = [];
|
|
20
|
+
shouldPan = false;
|
|
21
|
+
isPanning = false;
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new instance of the pan interaction handler.
|
|
24
|
+
* @param nvl - The NVL instance to attach the interaction handler to.
|
|
25
|
+
*/
|
|
26
|
+
constructor(nvl, options = { excludeNodeMargin: false }) {
|
|
27
|
+
super(nvl, options);
|
|
28
|
+
this.addEventListener("mousedown", this.handleMouseDown, true);
|
|
29
|
+
this.addEventListener("mousemove", this.handleMouseMove, true);
|
|
30
|
+
this.addEventListener("mouseup", this.handleMouseUp, true);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Updates which type of graph elements should hinder panning.
|
|
34
|
+
* @param targets - The graph elements that should hinder panning.
|
|
35
|
+
* @param excludeNodeMargin - If true, the node margin will not hinder panning.
|
|
36
|
+
* By default, panning is hindered by nodes and relationships.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { NVL } from '@neo4j-nvl/base'
|
|
41
|
+
* import { PanInteraction } from '@neo4j-nvl/interaction-handlers'
|
|
42
|
+
*
|
|
43
|
+
* const nvl = new NVL(document.createElement('div'), [{ id: '0' }], [])
|
|
44
|
+
*
|
|
45
|
+
* const panInteraction = new PanInteraction(nvl)
|
|
46
|
+
*
|
|
47
|
+
* // Pan canvas even when dragging on nodes and relationships
|
|
48
|
+
* panInteraction.updateTargets([], true)
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
updateTargets = (targets, excludeNodeMargin) => {
|
|
52
|
+
this.targets = targets;
|
|
53
|
+
this.currentOptions.excludeNodeMargin = excludeNodeMargin;
|
|
54
|
+
};
|
|
55
|
+
handleMouseDown = (event) => {
|
|
56
|
+
const hits = this.nvlInstance.getHits(event, difference(["node", "relationship"], this.targets), { hitNodeMarginWidth: this.currentOptions.excludeNodeMargin === true ? 10 : 0 });
|
|
57
|
+
if (hits.nvlTargets.nodes.length > 0 || hits.nvlTargets.relationships.length > 0) this.shouldPan = false;
|
|
58
|
+
else {
|
|
59
|
+
this.initialMousePosition = {
|
|
60
|
+
x: event.clientX,
|
|
61
|
+
y: event.clientY
|
|
62
|
+
};
|
|
63
|
+
this.initialPan = this.nvlInstance.getPan();
|
|
64
|
+
this.shouldPan = true;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
handleMouseMove = (evt) => {
|
|
68
|
+
if (!this.shouldPan || evt.buttons !== 1) return;
|
|
69
|
+
if (!this.isPanning) {
|
|
70
|
+
this.toggleGlobalTextSelection(false, this.handleMouseUp);
|
|
71
|
+
this.isPanning = true;
|
|
72
|
+
}
|
|
73
|
+
const zoom = this.nvlInstance.getScale();
|
|
74
|
+
const { x, y } = this.initialPan;
|
|
75
|
+
const dx = (evt.clientX - this.initialMousePosition.x) / zoom * window.devicePixelRatio;
|
|
76
|
+
const dy = (evt.clientY - this.initialMousePosition.y) / zoom * window.devicePixelRatio;
|
|
77
|
+
const newPanX = x - dx;
|
|
78
|
+
const newPanY = y - dy;
|
|
79
|
+
if (this.currentOptions.controlledPan !== true) this.nvlInstance.setPan(newPanX, newPanY);
|
|
80
|
+
this.callCallbackIfRegistered("onPan", {
|
|
81
|
+
x: newPanX,
|
|
82
|
+
y: newPanY
|
|
83
|
+
}, evt);
|
|
84
|
+
};
|
|
85
|
+
handleMouseUp = () => {
|
|
86
|
+
if (this.isPanning) this.toggleGlobalTextSelection(true, this.handleMouseUp);
|
|
87
|
+
this.resetPanState();
|
|
88
|
+
};
|
|
89
|
+
resetPanState = () => {
|
|
90
|
+
this.isPanning = false;
|
|
91
|
+
this.shouldPan = false;
|
|
92
|
+
this.initialMousePosition = {
|
|
93
|
+
x: 0,
|
|
94
|
+
y: 0
|
|
95
|
+
};
|
|
96
|
+
this.initialPan = {
|
|
97
|
+
x: 0,
|
|
98
|
+
y: 0
|
|
99
|
+
};
|
|
100
|
+
this.targets = [];
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Removes the related event listeners from the canvas.
|
|
104
|
+
*/
|
|
105
|
+
destroy() {
|
|
106
|
+
this.toggleGlobalTextSelection(true, this.handleMouseUp);
|
|
107
|
+
this.removeEventListener("mousedown", this.handleMouseDown, true);
|
|
108
|
+
this.removeEventListener("mousemove", this.handleMouseMove, true);
|
|
109
|
+
this.removeEventListener("mouseup", this.handleMouseUp, true);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
export { PanInteraction };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { NVL, Point } from "@neo4j-nvl/base";
|
|
2
2
|
export declare const generateUniqueId: (digit: number) => string;
|
|
3
3
|
export declare const isDraggingDistance: (startPoint: Point, endPoint: Point) => boolean;
|
|
4
4
|
export declare const isDraggingMovement: (event: MouseEvent, point: Point) => boolean;
|
|
5
5
|
export declare const getCanvasPosition: (canvas: HTMLElement, mouseEvent: MouseEvent) => Point;
|
|
6
6
|
export declare const getCanvasCenterOffset: (canvas: HTMLElement, mouseEvent: MouseEvent) => Point;
|
|
7
|
-
export declare const getWorldPosition: (nvl: NVL, pos: Point) => Point;
|
|
7
|
+
export declare const getWorldPosition: (nvl: NVL, pos: Point) => Point;
|
|
@@ -1,43 +1,44 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const distanceSquared = Math.pow(diffX, 2) + Math.pow(diffY, 2);
|
|
10
|
-
return distanceSquared > DRAG_THRESHOLD;
|
|
1
|
+
import "../constants.js";
|
|
2
|
+
// src/interaction-handlers/utils.ts
|
|
3
|
+
const generateUniqueId = (digit) => Math.floor(Math.random() * Math.pow(10, digit)).toString();
|
|
4
|
+
const isDraggingDistance = (startPoint, endPoint) => {
|
|
5
|
+
const diffX = Math.abs(endPoint.x - startPoint.x);
|
|
6
|
+
const diffY = Math.abs(endPoint.y - startPoint.y);
|
|
7
|
+
if (diffX > 10 || diffY > 10) return true;
|
|
8
|
+
return Math.pow(diffX, 2) + Math.pow(diffY, 2) > 10;
|
|
11
9
|
};
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const isDraggingMovement = (event, point) => {
|
|
11
|
+
return isDraggingDistance(point, {
|
|
12
|
+
x: event.clientX,
|
|
13
|
+
y: event.clientY
|
|
14
|
+
});
|
|
14
15
|
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
const getCanvasPosition = (canvas, mouseEvent) => {
|
|
17
|
+
const rect = canvas.getBoundingClientRect();
|
|
18
|
+
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
19
|
+
return {
|
|
20
|
+
x: (mouseEvent.clientX - rect.left) * devicePixelRatio,
|
|
21
|
+
y: (mouseEvent.clientY - rect.top) * devicePixelRatio
|
|
22
|
+
};
|
|
22
23
|
};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
const getCanvasCenterOffset = (canvas, mouseEvent) => {
|
|
25
|
+
const rect = canvas.getBoundingClientRect();
|
|
26
|
+
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
27
|
+
return {
|
|
28
|
+
x: (mouseEvent.clientX - rect.left - rect.width * .5) * devicePixelRatio,
|
|
29
|
+
y: (mouseEvent.clientY - rect.top - rect.height * .5) * devicePixelRatio
|
|
30
|
+
};
|
|
30
31
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
32
|
+
const getWorldPosition = (nvl, pos) => {
|
|
33
|
+
const scale = nvl.getScale();
|
|
34
|
+
const pan = nvl.getPan();
|
|
35
|
+
const { width, height } = nvl.getContainer().getBoundingClientRect();
|
|
36
|
+
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
37
|
+
const x = pos.x - width * .5 * devicePixelRatio;
|
|
38
|
+
const y = pos.y - height * .5 * devicePixelRatio;
|
|
39
|
+
return {
|
|
40
|
+
x: pan.x + x / scale,
|
|
41
|
+
y: pan.y + y / scale
|
|
42
|
+
};
|
|
43
43
|
};
|
|
44
|
+
export { generateUniqueId, getCanvasCenterOffset, getCanvasPosition, getWorldPosition, isDraggingDistance, isDraggingMovement };
|
|
@@ -1,66 +1,70 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { BaseInteraction } from "./base.js";
|
|
2
|
+
import { NVL } from "@neo4j-nvl/base";
|
|
3
3
|
/**
|
|
4
4
|
* Options for the zoom interaction handler to customize its behavior.
|
|
5
5
|
*/
|
|
6
6
|
export type ZoomInteractionOptions = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
/**
|
|
8
|
+
* If true, the interaction handler will not update the NVL instance directly.
|
|
9
|
+
* Instead, it will only call the onZoomAndPan callback with the calculated values,
|
|
10
|
+
* allowing the parent application to control when and how to apply the zoom update.
|
|
11
|
+
* @defaultValue false
|
|
12
|
+
*/
|
|
13
|
+
controlledZoom?: boolean;
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
16
|
* Callbacks for the zoom interaction handler.
|
|
17
17
|
*/
|
|
18
18
|
export type ZoomInteractionCallbacks = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Called when the canvas is zoomed and panned.
|
|
21
|
+
* @param zoomLevel - The zoom level.
|
|
22
|
+
* @param panX - The new pan X coordinate.
|
|
23
|
+
* @param panY - The new pan Y coordinate.
|
|
24
|
+
* @param event - The original mouse wheel event.
|
|
25
|
+
*/
|
|
26
|
+
onZoomAndPan?: ((zoomLevel: number, panX: number, panY: number, event: WheelEvent) => void) | boolean;
|
|
27
27
|
};
|
|
28
28
|
/**
|
|
29
29
|
* Interaction handler for zooming the canvas, which is achieved by:
|
|
30
30
|
* - Scrolling the mouse wheel on the canvas
|
|
31
31
|
* - Using trackpad pinch gestures (equivalent to Ctrl/Cmd + scroll)
|
|
32
32
|
*
|
|
33
|
+
* @remarks
|
|
34
|
+
* {@link ZoomInteractionCallbacks.onZoomAndPan} is the only callback. Zooming also changes the pan so the
|
|
35
|
+
* point under the pointer stays fixed. Zoom limits come from {@link NVL.getZoomLimits}.
|
|
36
|
+
*
|
|
33
37
|
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_zoominteraction Zoom Interaction documentation page}.
|
|
34
38
|
*/
|
|
35
39
|
export declare class ZoomInteraction extends BaseInteraction<ZoomInteractionOptions> {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
40
|
+
private zoomLimits;
|
|
41
|
+
/**
|
|
42
|
+
* Creates a new instance of the zoom interaction handler.
|
|
43
|
+
* @param nvl - The NVL instance to attach the interaction handler to.
|
|
44
|
+
* @param options - Options to customize the zoom interaction behavior.
|
|
45
|
+
*/
|
|
46
|
+
constructor(nvl: NVL, options?: ZoomInteractionOptions);
|
|
47
|
+
/**
|
|
48
|
+
* The function to be called on mouse wheel event on the canvas.
|
|
49
|
+
* @param evt - The mouse wheel event.
|
|
50
|
+
*/
|
|
51
|
+
private handleWheel;
|
|
52
|
+
/**
|
|
53
|
+
* Throttled zoom function to avoid events happening too fast.
|
|
54
|
+
* @param event - The original mouse wheel event.
|
|
55
|
+
*
|
|
56
|
+
* @remarks
|
|
57
|
+
* "Wheel" with a touchpad, the wheel is triggered event a lot,
|
|
58
|
+
* especially a lot of very small values.
|
|
59
|
+
* However, updating values in NVL instance takes time.
|
|
60
|
+
* Sometimes it lost the track of multiple events happening too soon.
|
|
61
|
+
* As a result, the zoom might lose its anchor point under touch pad.
|
|
62
|
+
* Therefore, the throttle is needed to avoid events happening too fast.
|
|
63
|
+
* The throttle is set to 25ms.
|
|
64
|
+
*/
|
|
65
|
+
private throttledZoom;
|
|
66
|
+
/**
|
|
67
|
+
* Removes the relevant event listeners from the canvas.
|
|
68
|
+
*/
|
|
69
|
+
destroy: () => void;
|
|
70
|
+
}
|
|
@@ -1,72 +1,74 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { BaseInteraction } from "./base.js";
|
|
2
|
+
import { getCanvasCenterOffset } from "./utils.js";
|
|
3
|
+
import { throttle } from "lodash-es";
|
|
4
|
+
// src/interaction-handlers/zoom-interaction.ts
|
|
4
5
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
6
|
+
* Interaction handler for zooming the canvas, which is achieved by:
|
|
7
|
+
* - Scrolling the mouse wheel on the canvas
|
|
8
|
+
* - Using trackpad pinch gestures (equivalent to Ctrl/Cmd + scroll)
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* {@link ZoomInteractionCallbacks.onZoomAndPan} is the only callback. Zooming also changes the pan so the
|
|
12
|
+
* point under the pointer stays fixed. Zoom limits come from {@link NVL.getZoomLimits}.
|
|
13
|
+
*
|
|
14
|
+
* For examples, head to the {@link https://neo4j.com/docs/nvl/current/interaction-handlers/#_zoominteraction Zoom Interaction documentation page}.
|
|
15
|
+
*/
|
|
16
|
+
var ZoomInteraction = class extends BaseInteraction {
|
|
17
|
+
zoomLimits;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new instance of the zoom interaction handler.
|
|
20
|
+
* @param nvl - The NVL instance to attach the interaction handler to.
|
|
21
|
+
* @param options - Options to customize the zoom interaction behavior.
|
|
22
|
+
*/
|
|
23
|
+
constructor(nvl, options = {}) {
|
|
24
|
+
super(nvl, options);
|
|
25
|
+
this.zoomLimits = nvl.getZoomLimits();
|
|
26
|
+
this.addEventListener("wheel", this.handleWheel);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The function to be called on mouse wheel event on the canvas.
|
|
30
|
+
* @param evt - The mouse wheel event.
|
|
31
|
+
*/
|
|
32
|
+
handleWheel = (evt) => {
|
|
33
|
+
evt.preventDefault();
|
|
34
|
+
this.throttledZoom(evt);
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Throttled zoom function to avoid events happening too fast.
|
|
38
|
+
* @param event - The original mouse wheel event.
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* "Wheel" with a touchpad, the wheel is triggered event a lot,
|
|
42
|
+
* especially a lot of very small values.
|
|
43
|
+
* However, updating values in NVL instance takes time.
|
|
44
|
+
* Sometimes it lost the track of multiple events happening too soon.
|
|
45
|
+
* As a result, the zoom might lose its anchor point under touch pad.
|
|
46
|
+
* Therefore, the throttle is needed to avoid events happening too fast.
|
|
47
|
+
* The throttle is set to 25ms.
|
|
48
|
+
*/
|
|
49
|
+
throttledZoom = throttle((event) => {
|
|
50
|
+
const zoom = this.nvlInstance.getScale();
|
|
51
|
+
const { x, y } = this.nvlInstance.getPan();
|
|
52
|
+
this.zoomLimits = this.nvlInstance.getZoomLimits();
|
|
53
|
+
const speedFactor = event.ctrlKey || event.metaKey ? 75 : 500;
|
|
54
|
+
const baseSpeed = event.deltaY / speedFactor;
|
|
55
|
+
const newZoomTarget = zoom - (zoom >= 1 ? baseSpeed * zoom : baseSpeed) * Math.min(1, zoom);
|
|
56
|
+
const zoomIsAtLimit = newZoomTarget > this.zoomLimits.maxZoom || newZoomTarget < this.zoomLimits.minZoom;
|
|
57
|
+
const offs = getCanvasCenterOffset(this.containerInstance, event);
|
|
58
|
+
let newPanX = x;
|
|
59
|
+
let newPanY = y;
|
|
60
|
+
if (!zoomIsAtLimit) {
|
|
61
|
+
newPanX = x + (offs.x / zoom - offs.x / newZoomTarget);
|
|
62
|
+
newPanY = y + (offs.y / zoom - offs.y / newZoomTarget);
|
|
63
|
+
}
|
|
64
|
+
if (this.currentOptions.controlledZoom !== true) this.nvlInstance.setZoomAndPan(newZoomTarget, newPanX, newPanY);
|
|
65
|
+
this.callCallbackIfRegistered("onZoomAndPan", newZoomTarget, newPanX, newPanY, event);
|
|
66
|
+
}, 25, { leading: true });
|
|
67
|
+
/**
|
|
68
|
+
* Removes the relevant event listeners from the canvas.
|
|
69
|
+
*/
|
|
70
|
+
destroy = () => {
|
|
71
|
+
this.removeEventListener("wheel", this.handleWheel);
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
export { ZoomInteraction };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export declare class OverlayRenderer {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
2
|
+
private ctx;
|
|
3
|
+
private canvas;
|
|
4
|
+
private removeResizeListener;
|
|
5
|
+
constructor(canvasParent: HTMLElement);
|
|
6
|
+
private fixCanvasSize;
|
|
7
|
+
drawBox(startX: number, startY: number, endX: number, endY: number): void;
|
|
8
|
+
drawLasso(points: {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
}[], stroke: boolean, fill: boolean): void;
|
|
12
|
+
clear(): void;
|
|
13
|
+
destroy(): void;
|
|
14
|
+
}
|