From 18a22e6f4c04eb47e2912d0648460575fd167cc9 Mon Sep 17 00:00:00 2001
From: Peter
Date: Thu, 5 Oct 2023 12:10:35 +0200
Subject: [PATCH 1/5] refactor(xyflow) improved performance of
getConnectedEdgesBase
---
packages/system/src/utils/graph.ts | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts
index fb7d74c2..dca0dacc 100644
--- a/packages/system/src/utils/graph.ts
+++ b/packages/system/src/utils/graph.ts
@@ -161,9 +161,12 @@ export const getConnectedEdgesBase = {
- const nodeIds = nodes.map((node) => node.id);
+ const nodeIds = new Set();
+ nodes.forEach((node) => {
+ nodeIds.add(node.id);
+ });
- return edges.filter((edge) => nodeIds.includes(edge.source) || nodeIds.includes(edge.target));
+ return edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
};
export function fitView, Options extends FitViewOptionsBase>(
From 8e7ee88ca3241a0a71682389cb8886eef3995501 Mon Sep 17 00:00:00 2001
From: Peter
Date: Thu, 5 Oct 2023 12:24:35 +0200
Subject: [PATCH 2/5] feat(react) added getConnectedEdges to useReactFlow
---
packages/react/src/hooks/useReactFlow.ts | 17 +++++++++++++++++
packages/react/src/types/instance.ts | 1 +
2 files changed, 18 insertions(+)
diff --git a/packages/react/src/hooks/useReactFlow.ts b/packages/react/src/hooks/useReactFlow.ts
index 45a8dbe1..cec31cc8 100644
--- a/packages/react/src/hooks/useReactFlow.ts
+++ b/packages/react/src/hooks/useReactFlow.ts
@@ -223,6 +223,21 @@ export default function useReactFlow(): ReactFlo
[]
);
+ const getConnectedEdges = useCallback((node) => {
+ const edges = store.getState().edges;
+
+ const nodeIds = new Set();
+ if (typeof node === 'string') {
+ nodeIds.add(node);
+ } else if (node.length >= 1) {
+ node.forEach((n) => {
+ nodeIds.add(n.id);
+ });
+ }
+
+ return edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
+ }, []);
+
return useMemo(() => {
return {
...viewportHelper,
@@ -238,6 +253,7 @@ export default function useReactFlow(): ReactFlo
deleteElements,
getIntersectingNodes,
isNodeIntersecting,
+ getConnectedEdges,
};
}, [
viewportHelper,
@@ -253,5 +269,6 @@ export default function useReactFlow(): ReactFlo
deleteElements,
getIntersectingNodes,
isNodeIntersecting,
+ getConnectedEdges,
]);
}
diff --git a/packages/react/src/types/instance.ts b/packages/react/src/types/instance.ts
index 239d339f..0bc61617 100644
--- a/packages/react/src/types/instance.ts
+++ b/packages/react/src/types/instance.ts
@@ -39,6 +39,7 @@ export namespace Instance {
area: Rect,
partially?: boolean
) => boolean;
+ export type getConnectedEdges = (id: string | (Partial & { id: Node['id'] })[]) => Edge[];
}
export type ReactFlowInstance = {
From d4179ac5925e8144dd29ff383b85deb5ee165b26 Mon Sep 17 00:00:00 2001
From: Peter
Date: Thu, 5 Oct 2023 12:28:06 +0200
Subject: [PATCH 3/5] feat(svelte) added getConnectedEdges to useSvelteFlow
---
packages/svelte/src/lib/hooks/useSvelteFlow.ts | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/packages/svelte/src/lib/hooks/useSvelteFlow.ts b/packages/svelte/src/lib/hooks/useSvelteFlow.ts
index 366f104d..191b2ea0 100644
--- a/packages/svelte/src/lib/hooks/useSvelteFlow.ts
+++ b/packages/svelte/src/lib/hooks/useSvelteFlow.ts
@@ -10,7 +10,7 @@ import {
} from '@xyflow/system';
import { useStore } from '$lib/store';
-import type { FitViewOptions } from '$lib/types';
+import type { Edge, FitViewOptions, Node } from '$lib/types';
import type { SvelteFlowStore } from '$lib/store/types';
export function useSvelteFlow(): {
@@ -26,6 +26,7 @@ export function useSvelteFlow(): {
viewport: Writable;
nodes: SvelteFlowStore['nodes'];
edges: SvelteFlowStore['edges'];
+ getConnectedEdges: (id: string | (Partial & { id: Node['id'] })[]) => Edge[];
} {
const {
zoomIn,
@@ -86,6 +87,20 @@ export function useSvelteFlow(): {
},
nodes,
edges,
+ getConnectedEdges: (node) => {
+ const _edges = get(edges);
+
+ const nodeIds = new Set();
+ if (typeof node === 'string') {
+ nodeIds.add(node);
+ } else if (node.length >= 1) {
+ node.forEach((n) => {
+ nodeIds.add(n.id);
+ });
+ }
+
+ return _edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
+ },
viewport: viewport
};
}
From 1b0790e79f2d7ef310a88158cf9c062457ef5df4 Mon Sep 17 00:00:00 2001
From: Peter
Date: Thu, 5 Oct 2023 13:00:20 +0200
Subject: [PATCH 4/5] refactor(xyflow) improved performance of getOutgoersBase
& getIncomersBase
---
packages/system/src/utils/graph.ts | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts
index dca0dacc..e72642be 100644
--- a/packages/system/src/utils/graph.ts
+++ b/packages/system/src/utils/graph.ts
@@ -43,8 +43,14 @@ export const getOutgoersBase = e.source === node.id).map((e) => e.target);
- return nodes.filter((n) => outgoerIds.includes(n.id));
+ const outgoerIds = new Set();
+ edges.forEach((edge) => {
+ if (edge.source === node.id) {
+ outgoerIds.add(edge.target);
+ }
+ });
+
+ return nodes.filter((n) => outgoerIds.has(n.id));
};
export const getIncomersBase = (
@@ -55,9 +61,14 @@ export const getIncomersBase = {
+ if (edge.target === node.id) {
+ incomersIds.add(edge.source);
+ }
+ });
- const incomersIds = edges.filter((e) => e.target === node.id).map((e) => e.source);
- return nodes.filter((n) => incomersIds.includes(n.id));
+ return nodes.filter((n) => incomersIds.has(n.id));
};
export const getNodePositionWithOrigin = (
From 6fd9d19797ca72997d0c0afdbb71418e2238c825 Mon Sep 17 00:00:00 2001
From: Peter
Date: Thu, 5 Oct 2023 13:28:04 +0200
Subject: [PATCH 5/5] feat(react, svelte) added getIncomers & getOutgoers to
use...Flow()
---
packages/react/src/hooks/useReactFlow.ts | 36 +++++++++++++++++--
packages/react/src/types/instance.ts | 2 ++
.../svelte/src/lib/hooks/useSvelteFlow.ts | 24 +++++++++++++
packages/system/src/utils/graph.ts | 8 ++---
4 files changed, 64 insertions(+), 6 deletions(-)
diff --git a/packages/react/src/hooks/useReactFlow.ts b/packages/react/src/hooks/useReactFlow.ts
index cec31cc8..8e94954a 100644
--- a/packages/react/src/hooks/useReactFlow.ts
+++ b/packages/react/src/hooks/useReactFlow.ts
@@ -1,5 +1,13 @@
import { useCallback, useMemo } from 'react';
-import { getElementsToRemove, getOverlappingArea, isRectObject, nodeToRect, type Rect } from '@xyflow/system';
+import {
+ getElementsToRemove,
+ getIncomersBase,
+ getOutgoersBase,
+ getOverlappingArea,
+ isRectObject,
+ nodeToRect,
+ type Rect,
+} from '@xyflow/system';
import useViewportHelper from './useViewportHelper';
import { useStoreApi } from '../hooks/useStore';
@@ -224,7 +232,7 @@ export default function useReactFlow(): ReactFlo
);
const getConnectedEdges = useCallback((node) => {
- const edges = store.getState().edges;
+ const { edges } = store.getState();
const nodeIds = new Set();
if (typeof node === 'string') {
@@ -238,6 +246,26 @@ export default function useReactFlow(): ReactFlo
return edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
}, []);
+ const getIncomers = useCallback((node) => {
+ const { nodes, edges } = store.getState();
+
+ if (typeof node === 'string') {
+ return getIncomersBase({ id: node }, nodes, edges);
+ }
+
+ return getIncomersBase(node, nodes, edges);
+ }, []);
+
+ const getOutgoers = useCallback((node) => {
+ const { nodes, edges } = store.getState();
+
+ if (typeof node == 'string') {
+ return getOutgoersBase({ id: node }, nodes, edges);
+ }
+
+ return getOutgoersBase(node, nodes, edges);
+ }, []);
+
return useMemo(() => {
return {
...viewportHelper,
@@ -254,6 +282,8 @@ export default function useReactFlow(): ReactFlo
getIntersectingNodes,
isNodeIntersecting,
getConnectedEdges,
+ getIncomers,
+ getOutgoers,
};
}, [
viewportHelper,
@@ -270,5 +300,7 @@ export default function useReactFlow(): ReactFlo
getIntersectingNodes,
isNodeIntersecting,
getConnectedEdges,
+ getIncomers,
+ getOutgoers,
]);
}
diff --git a/packages/react/src/types/instance.ts b/packages/react/src/types/instance.ts
index 0bc61617..694329fb 100644
--- a/packages/react/src/types/instance.ts
+++ b/packages/react/src/types/instance.ts
@@ -40,6 +40,8 @@ export namespace Instance {
partially?: boolean
) => boolean;
export type getConnectedEdges = (id: string | (Partial & { id: Node['id'] })[]) => Edge[];
+ export type getIncomers = (node: string | (Partial & { id: Node['id'] })) => Node[];
+ export type getOutgoers = (node: string | (Partial & { id: Node['id'] })) => Node[];
}
export type ReactFlowInstance = {
diff --git a/packages/svelte/src/lib/hooks/useSvelteFlow.ts b/packages/svelte/src/lib/hooks/useSvelteFlow.ts
index 191b2ea0..c3b6caec 100644
--- a/packages/svelte/src/lib/hooks/useSvelteFlow.ts
+++ b/packages/svelte/src/lib/hooks/useSvelteFlow.ts
@@ -1,5 +1,7 @@
import { get, type Writable } from 'svelte/store';
import {
+ getIncomersBase,
+ getOutgoersBase,
pointToRendererPoint,
type Project,
type SetCenterOptions,
@@ -27,6 +29,8 @@ export function useSvelteFlow(): {
nodes: SvelteFlowStore['nodes'];
edges: SvelteFlowStore['edges'];
getConnectedEdges: (id: string | (Partial & { id: Node['id'] })[]) => Edge[];
+ getIncomers: (node: string | (Partial & { id: Node['id'] })) => Node[];
+ getOutgoers: (node: string | (Partial & { id: Node['id'] })) => Node[];
} {
const {
zoomIn,
@@ -101,6 +105,26 @@ export function useSvelteFlow(): {
return _edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
},
+ getIncomers: (node) => {
+ const _edges = get(edges);
+ const _nodes = get(nodes);
+
+ if (typeof node === 'string') {
+ return getIncomersBase({ id: node }, _nodes, _edges);
+ }
+
+ return getIncomersBase(node, _nodes, _edges);
+ },
+ getOutgoers: (node) => {
+ const _edges = get(edges);
+ const _nodes = get(nodes);
+
+ if (typeof node == 'string') {
+ return getOutgoersBase({ id: node }, _nodes, _edges);
+ }
+
+ return getOutgoersBase(node, _nodes, _edges);
+ },
viewport: viewport
};
}
diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts
index e72642be..17467503 100644
--- a/packages/system/src/utils/graph.ts
+++ b/packages/system/src/utils/graph.ts
@@ -35,11 +35,11 @@ export const isNodeBase = 'id' in element && !('source' in element) && !('target' in element);
export const getOutgoersBase = (
- node: NodeType,
+ node: Partial & { id: string },
nodes: NodeType[],
edges: EdgeType[]
): NodeType[] => {
- if (!isNodeBase(node)) {
+ if (!node.id) {
return [];
}
@@ -54,11 +54,11 @@ export const getOutgoersBase = (
- node: NodeType,
+ node: Partial & { id: string },
nodes: NodeType[],
edges: EdgeType[]
): NodeType[] => {
- if (!isNodeBase(node)) {
+ if (!node.id) {
return [];
}
const incomersIds = new Set();