diff --git a/examples/react/src/examples/Stress/index.tsx b/examples/react/src/examples/Stress/index.tsx
index 9020ddd6..5fd6f9e9 100644
--- a/examples/react/src/examples/Stress/index.tsx
+++ b/examples/react/src/examples/Stress/index.tsx
@@ -224,6 +224,7 @@ const StressFlow = () => {
onEdgesChange={onEdgeChange}
minZoom={0.2}
fitView
+ panOnDrag={false}
>
diff --git a/packages/react/src/hooks/useViewportHelper.ts b/packages/react/src/hooks/useViewportHelper.ts
index 245fafd7..2bfea817 100644
--- a/packages/react/src/hooks/useViewportHelper.ts
+++ b/packages/react/src/hooks/useViewportHelper.ts
@@ -21,17 +21,33 @@ const useViewportHelper = (): ViewportHelperFunctions => {
return useMemo(() => {
return {
- zoomIn: (options) => store.getState().panZoom?.scaleBy(1.2, { duration: options?.duration }),
- zoomOut: (options) => store.getState().panZoom?.scaleBy(1 / 1.2, { duration: options?.duration }),
- zoomTo: (zoomLevel, options) => store.getState().panZoom?.scaleTo(zoomLevel, { duration: options?.duration }),
+ zoomIn: (options) => {
+ const { panZoom } = store.getState();
+
+ return panZoom ? panZoom.scaleBy(1.2, { duration: options?.duration }) : Promise.resolve(false);
+ },
+ zoomOut: (options) => {
+ const { panZoom } = store.getState();
+
+ return panZoom ? panZoom.scaleBy(1 / 1.2, { duration: options?.duration }) : Promise.resolve(false);
+ },
+ zoomTo: (zoomLevel, options) => {
+ const { panZoom } = store.getState();
+
+ return panZoom ? panZoom.scaleTo(zoomLevel, { duration: options?.duration }) : Promise.resolve(false);
+ },
getZoom: () => store.getState().transform[2],
- setViewport: (viewport, options) => {
+ setViewport: async (viewport, options) => {
const {
transform: [tX, tY, tZoom],
panZoom,
} = store.getState();
- panZoom?.setViewport(
+ if (!panZoom) {
+ return Promise.resolve(false);
+ }
+
+ await panZoom.setViewport(
{
x: viewport.x ?? tX,
y: viewport.y ?? tY,
@@ -39,6 +55,8 @@ const useViewportHelper = (): ViewportHelperFunctions => {
},
{ duration: options?.duration }
);
+
+ return Promise.resolve(true);
},
getViewport: () => {
const [x, y, zoom] = store.getState().transform;
@@ -47,29 +65,31 @@ const useViewportHelper = (): ViewportHelperFunctions => {
fitView: (options) => {
const { nodeLookup, width, height, minZoom, maxZoom, panZoom } = store.getState();
- if (!panZoom) {
- return false;
- }
-
- return fitView(
- {
- nodeLookup,
- width,
- height,
- minZoom,
- maxZoom,
- panZoom,
- },
- options
- );
+ return panZoom
+ ? fitView(
+ {
+ nodeLookup,
+ width,
+ height,
+ minZoom,
+ maxZoom,
+ panZoom,
+ },
+ options
+ )
+ : Promise.resolve(false);
},
- setCenter: (x, y, options) => {
+ setCenter: async (x, y, options) => {
const { width, height, maxZoom, panZoom } = store.getState();
const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom;
const centerX = width / 2 - x * nextZoom;
const centerY = height / 2 - y * nextZoom;
- panZoom?.setViewport(
+ if (!panZoom) {
+ return Promise.resolve(false);
+ }
+
+ await panZoom.setViewport(
{
x: centerX,
y: centerY,
@@ -77,12 +97,20 @@ const useViewportHelper = (): ViewportHelperFunctions => {
},
{ duration: options?.duration }
);
+
+ return Promise.resolve(true);
},
- fitBounds: (bounds, options) => {
+ fitBounds: async (bounds, options) => {
const { width, height, minZoom, maxZoom, panZoom } = store.getState();
const viewport = getViewportForBounds(bounds, width, height, minZoom, maxZoom, options?.padding ?? 0.1);
- panZoom?.setViewport(viewport, { duration: options?.duration });
+ if (!panZoom) {
+ return Promise.resolve(false);
+ }
+
+ await panZoom.setViewport(viewport, { duration: options?.duration });
+
+ return Promise.resolve(true);
},
screenToFlowPosition: (clientPosition: XYPosition, options: { snapToGrid: boolean } = { snapToGrid: true }) => {
const { transform, snapGrid, domNode } = store.getState();
diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts
index 57beb3f9..11245bb5 100644
--- a/packages/react/src/store/index.ts
+++ b/packages/react/src/store/index.ts
@@ -287,15 +287,15 @@ const createStore = ({
nodeExtent,
});
},
- panBy: (delta): boolean => {
+ panBy: (delta): Promise => {
const { transform, width, height, panZoom, translateExtent } = get();
return panBySystem({ delta, panZoom, transform, translateExtent, width, height });
},
- fitView: (options?: FitViewOptions): boolean => {
+ fitView: (options?: FitViewOptions): Promise => {
const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get();
if (!panZoom) {
- return false;
+ return Promise.resolve(false);
}
return fitViewSystem(
diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts
index 2f518dca..48e5b2fe 100644
--- a/packages/react/src/types/general.ts
+++ b/packages/react/src/types/general.ts
@@ -65,7 +65,7 @@ export type OnSelectionChangeFunc = (params: OnSelectionChangeParams) => void;
export type FitViewParams = FitViewParamsBase;
export type FitViewOptions = FitViewOptionsBase;
-export type FitView = (fitViewOptions?: FitViewOptions) => boolean;
+export type FitView = (fitViewOptions?: FitViewOptions) => Promise;
export type OnInit = (
reactFlowInstance: ReactFlowInstance
) => void;
diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts
index 2e86ade0..30da6e64 100644
--- a/packages/react/src/types/store.ts
+++ b/packages/react/src/types/store.ts
@@ -168,7 +168,7 @@ export type ReactFlowActions = {
triggerNodeChanges: (changes: NodeChange[]) => void;
triggerEdgeChanges: (changes: EdgeChange[]) => void;
panBy: PanBy;
- fitView: (options?: FitViewOptions) => boolean;
+ fitView: (options?: FitViewOptions) => Promise;
};
export type ReactFlowState = ReactFlowStore<
diff --git a/packages/svelte/src/lib/hooks/useSvelteFlow.ts b/packages/svelte/src/lib/hooks/useSvelteFlow.ts
index be40af64..f46c1757 100644
--- a/packages/svelte/src/lib/hooks/useSvelteFlow.ts
+++ b/packages/svelte/src/lib/hooks/useSvelteFlow.ts
@@ -80,7 +80,7 @@ export function useSvelteFlow(): {
* @param zoomLevel - the zoom level to set
* @param options.duration - optional duration. If set, a transition will be applied
*/
- setZoom: (zoomLevel: number, options?: ViewportHelperFunctionOptions) => void;
+ setZoom: (zoomLevel: number, options?: ViewportHelperFunctionOptions) => Promise;
/**
* Returns the current zoom level.
*
@@ -94,14 +94,14 @@ export function useSvelteFlow(): {
* @param y - y position
* @param options.zoom - optional zoom
*/
- setCenter: (x: number, y: number, options?: SetCenterOptions) => void;
+ setCenter: (x: number, y: number, options?: SetCenterOptions) => Promise;
/**
* Sets the current viewport.
*
* @param viewport - the viewport to set
* @param options.duration - optional duration. If set, a transition will be applied
*/
- setViewport: (viewport: Viewport, options?: ViewportHelperFunctionOptions) => void;
+ setViewport: (viewport: Viewport, options?: ViewportHelperFunctionOptions) => Promise;
/**
* Returns the current viewport.
*
@@ -118,7 +118,7 @@ export function useSvelteFlow(): {
* @param options.duration - optional duration. If set, a transition will be applied
* @param options.nodes - optional nodes to fit the view to
*/
- fitView: (options?: FitViewOptions) => void;
+ fitView: (options?: FitViewOptions) => Promise;
/**
* Returns all nodes that intersect with the given node or rect.
*
@@ -153,7 +153,7 @@ export function useSvelteFlow(): {
* @param bounds - the bounds ({ x: number, y: number, width: number, height: number }) to fit the view to
* @param options.padding - optional padding
*/
- fitBounds: (bounds: Rect, options?: FitBoundsOptions) => void;
+ fitBounds: (bounds: Rect, options?: FitBoundsOptions) => Promise;
/**
* Deletes nodes and edges.
*
@@ -298,26 +298,41 @@ export function useSvelteFlow(): {
getEdge: (id) => get(edgeLookup).get(id),
getEdges: (ids) => (ids === undefined ? get(edges) : getElements(get(edgeLookup), ids)),
setZoom: (zoomLevel, options) => {
- get(panZoom)?.scaleTo(zoomLevel, { duration: options?.duration });
+ const currentPanZoom = get(panZoom);
+ return currentPanZoom
+ ? currentPanZoom.scaleTo(zoomLevel, { duration: options?.duration })
+ : Promise.resolve(false);
},
getZoom: () => get(viewport).zoom,
- setViewport: (vieport, options) => {
+ setViewport: async (nextViewport, options) => {
const currentViewport = get(viewport);
+ const currentPanZoom = get(panZoom);
- get(panZoom)?.setViewport(
+ if (!currentPanZoom) {
+ return Promise.resolve(false);
+ }
+
+ await currentPanZoom.setViewport(
{
- x: vieport.x ?? currentViewport.x,
- y: vieport.y ?? currentViewport.y,
- zoom: vieport.zoom ?? currentViewport.zoom
+ x: nextViewport.x ?? currentViewport.x,
+ y: nextViewport.y ?? currentViewport.y,
+ zoom: nextViewport.zoom ?? currentViewport.zoom
},
{ duration: options?.duration }
);
+
+ return Promise.resolve(true);
},
getViewport: () => get(viewport),
- setCenter: (x, y, options) => {
+ setCenter: async (x, y, options) => {
const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : get(maxZoom);
+ const currentPanZoom = get(panZoom);
- get(panZoom)?.setViewport(
+ if (!currentPanZoom) {
+ return Promise.resolve(false);
+ }
+
+ await currentPanZoom.setViewport(
{
x: get(width) / 2 - x * nextZoom,
y: get(height) / 2 - y * nextZoom,
@@ -325,9 +340,17 @@ export function useSvelteFlow(): {
},
{ duration: options?.duration }
);
+
+ return Promise.resolve(true);
},
fitView,
- fitBounds: (bounds: Rect, options?: FitBoundsOptions) => {
+ fitBounds: async (bounds: Rect, options?: FitBoundsOptions) => {
+ const currentPanZoom = get(panZoom);
+
+ if (!currentPanZoom) {
+ return Promise.resolve(false);
+ }
+
const viewport = getViewportForBounds(
bounds,
get(width),
@@ -337,7 +360,9 @@ export function useSvelteFlow(): {
options?.padding ?? 0.1
);
- get(panZoom)?.setViewport(viewport, { duration: options?.duration });
+ await currentPanZoom.setViewport(viewport, { duration: options?.duration });
+
+ return Promise.resolve(true);
},
getIntersectingNodes: (
nodeOrRect: Node | { id: Node['id'] } | Rect,
diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts
index e1eea73f..e52fc8a8 100644
--- a/packages/svelte/src/lib/store/index.ts
+++ b/packages/svelte/src/lib/store/index.ts
@@ -90,7 +90,7 @@ export function createStore({
store.nodes.update((nds) => nds);
};
- function updateNodeInternals(updates: Map) {
+ async function updateNodeInternals(updates: Map) {
const nodeLookup = get(store.nodeLookup);
const { changes, updatedInternals } = updateNodeInternalsSystem(
updates,
@@ -106,7 +106,7 @@ export function createStore({
if (!get(store.fitViewOnInitDone) && get(store.fitViewOnInit)) {
const fitViewOptions = get(store.fitViewOptions);
- const fitViewOnInitDone = fitView({
+ const fitViewOnInitDone = await fitView({
...fitViewOptions,
nodes: fitViewOptions?.nodes
});
@@ -150,7 +150,7 @@ export function createStore({
const panZoom = get(store.panZoom);
if (!panZoom) {
- return false;
+ return Promise.resolve(false);
}
return fitViewSystem(
@@ -168,18 +168,19 @@ export function createStore({
function zoomBy(factor: number, options?: ViewportHelperFunctionOptions) {
const panZoom = get(store.panZoom);
-
- if (panZoom) {
- panZoom.scaleBy(factor, options);
+ if (!panZoom) {
+ return Promise.resolve(false);
}
+
+ return panZoom.scaleBy(factor, options);
}
function zoomIn(options?: ViewportHelperFunctionOptions) {
- zoomBy(1.2, options);
+ return zoomBy(1.2, options);
}
function zoomOut(options?: ViewportHelperFunctionOptions) {
- zoomBy(1 / 1.2, options);
+ return zoomBy(1 / 1.2, options);
}
function setMinZoom(minZoom: number) {
diff --git a/packages/svelte/src/lib/store/types.ts b/packages/svelte/src/lib/store/types.ts
index d87ca907..0d8c01bf 100644
--- a/packages/svelte/src/lib/store/types.ts
+++ b/packages/svelte/src/lib/store/types.ts
@@ -20,19 +20,19 @@ export type SvelteFlowStoreActions = {
setNodeTypes: (nodeTypes: NodeTypes) => void;
setEdgeTypes: (edgeTypes: EdgeTypes) => void;
addEdge: (edge: Edge | Connection) => void;
- zoomIn: (options?: ViewportHelperFunctionOptions) => void;
- zoomOut: (options?: ViewportHelperFunctionOptions) => void;
+ zoomIn: (options?: ViewportHelperFunctionOptions) => Promise;
+ zoomOut: (options?: ViewportHelperFunctionOptions) => Promise;
setMinZoom: (minZoom: number) => void;
setMaxZoom: (maxZoom: number) => void;
setTranslateExtent: (extent: CoordinateExtent) => void;
- fitView: (options?: FitViewOptions) => boolean;
+ fitView: (options?: FitViewOptions) => Promise;
updateNodePositions: UpdateNodePositions;
updateNodeInternals: (updates: Map) => void;
unselectNodesAndEdges: (params?: { nodes?: Node[]; edges?: Edge[] }) => void;
addSelectedNodes: (ids: string[]) => void;
addSelectedEdges: (ids: string[]) => void;
handleNodeSelection: (id: string) => void;
- panBy: (delta: XYPosition) => boolean;
+ panBy: (delta: XYPosition) => Promise;
updateConnection: UpdateConnection;
cancelConnection: () => void;
reset(): void;
diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts
index 7e44be9b..f0a0a504 100644
--- a/packages/system/src/types/general.ts
+++ b/packages/system/src/types/general.ts
@@ -18,13 +18,13 @@ export type OnMove = (event: MouseEvent | TouchEvent | null, viewport: Viewport)
export type OnMoveStart = OnMove;
export type OnMoveEnd = OnMove;
-export type ZoomInOut = (options?: ViewportHelperFunctionOptions) => void;
-export type ZoomTo = (zoomLevel: number, options?: ViewportHelperFunctionOptions) => void;
+export type ZoomInOut = (options?: ViewportHelperFunctionOptions) => Promise;
+export type ZoomTo = (zoomLevel: number, options?: ViewportHelperFunctionOptions) => Promise;
export type GetZoom = () => number;
export type GetViewport = () => Viewport;
-export type SetViewport = (viewport: Viewport, options?: ViewportHelperFunctionOptions) => void;
-export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => void;
-export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => void;
+export type SetViewport = (viewport: Viewport, options?: ViewportHelperFunctionOptions) => Promise;
+export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => Promise;
+export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => Promise;
export type Connection = {
source: string;
@@ -130,7 +130,7 @@ export type SelectionRect = Rect & {
export type OnError = (id: string, message: string) => void;
export type UpdateNodePositions = (dragItems: Map, dragging?: boolean) => void;
-export type PanBy = (delta: XYPosition) => boolean;
+export type PanBy = (delta: XYPosition) => Promise;
export const initialConnection: NoConnection = {
inProgress: false,
diff --git a/packages/system/src/types/panzoom.ts b/packages/system/src/types/panzoom.ts
index 81654bdb..4a126a98 100644
--- a/packages/system/src/types/panzoom.ts
+++ b/packages/system/src/types/panzoom.ts
@@ -45,15 +45,15 @@ export type PanZoomInstance = {
update: (params: PanZoomUpdateOptions) => void;
destroy: () => void;
getViewport: () => Viewport;
- setViewport: (viewport: Viewport, options?: PanZoomTransformOptions) => ZoomTransform | undefined;
+ setViewport: (viewport: Viewport, options?: PanZoomTransformOptions) => Promise;
setViewportConstrained: (
viewport: Viewport,
extent: CoordinateExtent,
translateExtent: CoordinateExtent
- ) => ZoomTransform | undefined;
+ ) => Promise;
setScaleExtent: (scaleExtent: [number, number]) => void;
setTranslateExtent: (translateExtent: CoordinateExtent) => void;
- scaleTo: (scale: number, options?: PanZoomTransformOptions) => void;
- scaleBy: (factor: number, options?: PanZoomTransformOptions) => void;
+ scaleTo: (scale: number, options?: PanZoomTransformOptions) => Promise;
+ scaleBy: (factor: number, options?: PanZoomTransformOptions) => Promise;
syncViewport: (viewport: Viewport) => void;
};
diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts
index d09fe1ef..8d98fa40 100644
--- a/packages/system/src/utils/graph.ts
+++ b/packages/system/src/utils/graph.ts
@@ -233,10 +233,10 @@ export const getConnectedEdges = nodeIds.has(edge.source) || nodeIds.has(edge.target));
};
-export function fitView, Options extends FitViewOptionsBase>(
+export async function fitView, Options extends FitViewOptionsBase>(
{ nodeLookup, width, height, panZoom, minZoom, maxZoom }: Params,
options?: Options
-) {
+): Promise {
const filteredNodes: Map = new Map();
const optionNodeIds = options?.nodes ? new Set(options.nodes.map((node) => node.id)) : null;
@@ -260,12 +260,12 @@ export function fitView, Options exte
options?.padding ?? 0.1
);
- panZoom.setViewport(viewport, { duration: options?.duration });
+ await panZoom.setViewport(viewport, { duration: options?.duration });
- return true;
+ return Promise.resolve(true);
}
- return false;
+ return Promise.resolve(false);
}
/**
diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts
index 9c4904c7..5a977cc0 100644
--- a/packages/system/src/utils/store.ts
+++ b/packages/system/src/utils/store.ts
@@ -325,7 +325,7 @@ export function updateNodeInternals(
return { changes, updatedInternals };
}
-export function panBy({
+export async function panBy({
delta,
panZoom,
transform,
@@ -339,12 +339,12 @@ export function panBy({
translateExtent: CoordinateExtent;
width: number;
height: number;
-}) {
+}): Promise {
if (!panZoom || (!delta.x && !delta.y)) {
- return false;
+ return Promise.resolve(false);
}
- const nextViewport = panZoom.setViewportConstrained(
+ const nextViewport = await panZoom.setViewportConstrained(
{
x: transform[0] + delta.x,
y: transform[1] + delta.y,
@@ -361,7 +361,7 @@ export function panBy({
!!nextViewport &&
(nextViewport.x !== transform[0] || nextViewport.y !== transform[1] || nextViewport.k !== transform[2]);
- return transformChanged;
+ return Promise.resolve(transformChanged);
}
export function updateConnectionLookup(connectionLookup: ConnectionLookup, edgeLookup: EdgeLookup, edges: EdgeBase[]) {
diff --git a/packages/system/src/xydrag/XYDrag.ts b/packages/system/src/xydrag/XYDrag.ts
index 675aef3a..27022760 100644
--- a/packages/system/src/xydrag/XYDrag.ts
+++ b/packages/system/src/xydrag/XYDrag.ts
@@ -195,7 +195,7 @@ export function XYDrag voi
}
}
- function autoPan() {
+ async function autoPan() {
if (!containerBounds) {
return;
}
@@ -208,7 +208,7 @@ export function XYDrag voi
lastPos.x = (lastPos.x ?? 0) - xMovement / transform[2];
lastPos.y = (lastPos.y ?? 0) - yMovement / transform[2];
- if (panBy({ x: xMovement, y: yMovement })) {
+ if (await panBy({ x: xMovement, y: yMovement })) {
updateNodes(lastPos as XYPosition, null);
}
}
diff --git a/packages/system/src/xypanzoom/XYPanZoom.ts b/packages/system/src/xypanzoom/XYPanZoom.ts
index a1402dee..2db56b10 100644
--- a/packages/system/src/xypanzoom/XYPanZoom.ts
+++ b/packages/system/src/xypanzoom/XYPanZoom.ts
@@ -188,27 +188,27 @@ export function XYPanZoom({
d3ZoomInstance.on('zoom', null);
}
- function setViewportConstrained(
+ async function setViewportConstrained(
viewport: Viewport,
extent: CoordinateExtent,
translateExtent: CoordinateExtent
- ): ZoomTransform | undefined {
+ ): Promise {
const nextTransform = viewportToTransform(viewport);
const contrainedTransform = d3ZoomInstance?.constrain()(nextTransform, extent, translateExtent);
if (contrainedTransform) {
- setTransform(contrainedTransform);
+ await setTransform(contrainedTransform);
}
- return contrainedTransform;
+ return new Promise((resolve) => resolve(contrainedTransform));
}
- function setViewport(viewport: Viewport, options?: PanZoomTransformOptions) {
+ async function setViewport(viewport: Viewport, options?: PanZoomTransformOptions) {
const nextTransform = viewportToTransform(viewport);
- setTransform(nextTransform, options);
+ await setTransform(nextTransform, options);
- return nextTransform;
+ return new Promise((resolve) => resolve(nextTransform));
}
function syncViewport(viewport: Viewport) {
diff --git a/packages/system/src/xypanzoom/utils.ts b/packages/system/src/xypanzoom/utils.ts
index 55969f3e..5a3e687f 100644
--- a/packages/system/src/xypanzoom/utils.ts
+++ b/packages/system/src/xypanzoom/utils.ts
@@ -21,8 +21,6 @@ export const isWrappedWithClass = (event: any, className: string | undefined) =>
export const isRightClickPan = (panOnDrag: boolean | number[], usedButton: number) =>
usedButton === 2 && Array.isArray(panOnDrag) && panOnDrag.includes(2);
-export const getD3Transition = (selection: D3SelectionInstance, duration = 0) =>
- typeof duration === 'number' && duration > 0 ? selection.transition().duration(duration) : selection;
export const getD3Transition = (selection: D3SelectionInstance, duration = 0, onEnd = () => {}) =>
typeof duration === 'number' && duration > 0 ? selection.transition().duration(duration).on('end', onEnd) : selection;