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