diff --git a/example/src/UseZoomPanHelper/index.js b/example/src/UseZoomPanHelper/index.js
new file mode 100644
index 00000000..bb415cea
--- /dev/null
+++ b/example/src/UseZoomPanHelper/index.js
@@ -0,0 +1,60 @@
+import React, { useState, useCallback } from 'react';
+
+import ReactFlow, {
+ removeElements,
+ addEdge,
+ Background,
+ MiniMap,
+ useZoomPanHelper,
+ ReactFlowProvider,
+} from 'react-flow-renderer';
+
+const initialElements = [
+ { id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light' },
+ { id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
+ { id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
+ { id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' },
+ { id: 'e1-2', source: '1', target: '2', animated: true },
+ { id: 'e1-3', source: '1', target: '3' },
+];
+
+let id = 5;
+const getId = () => `${id++}`;
+
+const UseZoomPanHelperFlow = () => {
+ const [elements, setElements] = useState(initialElements);
+ const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
+ const onConnect = (params) => setElements((els) => addEdge(params, els));
+ const { project } = useZoomPanHelper();
+
+ const onPaneClick = useCallback(
+ (evt) => {
+ const projectedPosition = project({ x: evt.clientX, y: evt.clientY - 40 });
+
+ setElements((els) =>
+ els.concat({
+ id: getId(),
+ position: projectedPosition,
+ data: {
+ label: `${projectedPosition.x}-${projectedPosition.y}`,
+ },
+ })
+ );
+ },
+ [project]
+ );
+ console.log(elements);
+
+ return (
+
+
+
+
+ );
+};
+
+export default () => (
+
+
+
+);
diff --git a/example/src/index.js b/example/src/index.js
index 37f5f178..7dfe4028 100644
--- a/example/src/index.js
+++ b/example/src/index.js
@@ -21,6 +21,7 @@ import SaveRestore from './SaveRestore';
import DragNDrop from './DragNDrop';
import Layout from './Layouting';
import SwitchFlows from './Switch';
+import UseZoomPanHelper from './UseZoomPanHelper';
import './index.css';
@@ -101,6 +102,10 @@ const routes = [
path: '/switch',
component: SwitchFlows,
},
+ {
+ path: '/usezoompanhelper',
+ component: UseZoomPanHelper,
+ },
];
const Header = withRouter(({ history, location }) => {
diff --git a/src/hooks/useZoomPanHelper.ts b/src/hooks/useZoomPanHelper.ts
index 1c470e0c..06281fb3 100644
--- a/src/hooks/useZoomPanHelper.ts
+++ b/src/hooks/useZoomPanHelper.ts
@@ -3,8 +3,8 @@ import { zoomIdentity } from 'd3-zoom';
import { useStoreState, useStore } from '../store/hooks';
import { clamp } from '../utils';
-import { getRectOfNodes } from '../utils/graph';
-import { FitViewParams, FlowTransform, ZoomPanHelperFunctions, Rect, Transform } from '../types';
+import { getRectOfNodes, pointToRendererPoint } from '../utils/graph';
+import { FitViewParams, FlowTransform, ZoomPanHelperFunctions, Rect, Transform, XYPosition } from '../types';
const DEFAULT_PADDING = 0.1;
@@ -16,6 +16,7 @@ const initialZoomPanHelper: ZoomPanHelperFunctions = {
fitView: (_: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => {},
setCenter: (_: number, __: number) => {},
fitBounds: (_: Rect) => {},
+ project: (position: XYPosition) => position,
initialized: false,
};
@@ -86,6 +87,10 @@ const useZoomPanHelper = (): ZoomPanHelperFunctions => {
d3Zoom.transform(d3Selection, transform);
},
+ project: (position: XYPosition) => {
+ const { transform, snapToGrid, snapGrid } = store.getState();
+ return pointToRendererPoint(position, transform, snapToGrid, snapGrid);
+ },
initialized: true,
};
}
diff --git a/src/types/index.ts b/src/types/index.ts
index f8a78efb..4ae5c45a 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -361,6 +361,7 @@ export interface ZoomPanHelperFunctions {
fitView: FitViewFunc;
setCenter: (x: number, y: number, zoom?: number) => void;
fitBounds: (bounds: Rect, padding?: number) => void;
+ project: (position: XYPosition) => XYPosition;
initialized: boolean;
}