From 53c04e2546cad8081ef8d19ed73286cc025d4198 Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 2 Oct 2023 16:16:17 +0200 Subject: [PATCH 1/8] chore(react): cleanup viewport component --- packages/react/src/container/Viewport/index.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/react/src/container/Viewport/index.tsx b/packages/react/src/container/Viewport/index.tsx index ab10bada..b0de6954 100644 --- a/packages/react/src/container/Viewport/index.tsx +++ b/packages/react/src/container/Viewport/index.tsx @@ -2,7 +2,6 @@ import type { ReactNode } from 'react'; import { useStore } from '../../hooks/useStore'; import type { ReactFlowState } from '../../types'; -import { Viewport } from '@xyflow/system'; const selector = (s: ReactFlowState) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`; @@ -10,7 +9,7 @@ type ViewportProps = { children: ReactNode; }; -function Viewport({ children }: ViewportProps) { +export default function Viewport({ children }: ViewportProps) { const transform = useStore(selector); return ( @@ -19,5 +18,3 @@ function Viewport({ children }: ViewportProps) { ); } - -export default Viewport; From 969fa8280a913d470fab8a87c2aa917e9f2a3d29 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 4 Oct 2023 10:37:39 +0200 Subject: [PATCH 2/8] fix(svelte-flow) style is now applied properly to the connectionLine --- .../src/lib/components/ConnectionLine/ConnectionLine.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/svelte/src/lib/components/ConnectionLine/ConnectionLine.svelte b/packages/svelte/src/lib/components/ConnectionLine/ConnectionLine.svelte index eb30d3f7..904a45d3 100644 --- a/packages/svelte/src/lib/components/ConnectionLine/ConnectionLine.svelte +++ b/packages/svelte/src/lib/components/ConnectionLine/ConnectionLine.svelte @@ -12,11 +12,11 @@ {#if $connection.path} - + {#if !isCustomComponent} - + {/if} From e46c3cddaa6b8458fe6fc8c472288b2c4a6b5739 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 4 Oct 2023 11:32:32 +0200 Subject: [PATCH 3/8] fix(svelte) prevent unecessary rerenders & execution of reactive statements, closes #3336 --- .../svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte | 2 ++ .../svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte | 2 ++ 2 files changed, 4 insertions(+) diff --git a/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte b/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte index 81d35e49..7d609447 100644 --- a/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte +++ b/packages/svelte/src/lib/components/EdgeWrapper/EdgeWrapper.svelte @@ -1,3 +1,5 @@ + + + + + + + diff --git a/examples/svelte/src/routes/add-node-on-drop/Flow.svelte b/examples/svelte/src/routes/add-node-on-drop/Flow.svelte new file mode 100644 index 00000000..cd12c1a4 --- /dev/null +++ b/examples/svelte/src/routes/add-node-on-drop/Flow.svelte @@ -0,0 +1,115 @@ + + + + +
+ { + // Memorize the nodeId you start draggin a connection line from a node + connectingNodeId = nodeId; + }} + on:connectend={handleConnectEnd} + /> +
+ + diff --git a/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte b/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte index ef5d547b..d9eb867d 100644 --- a/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte +++ b/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte @@ -71,13 +71,14 @@ export { className as class }; let domNode: HTMLDivElement; + let clientWidth: number; + let clientHeight: number; const store = hasContext(key) ? useStore() : createStoreContext(); onMount(() => { - const { width, height } = domNode.getBoundingClientRect(); - store.width.set(width); - store.height.set(height); + store.width.set(clientWidth); + store.height.set(clientHeight); store.domNode.set(domNode); store.syncNodeStores(nodes); @@ -141,6 +142,8 @@
void; getViewport: () => Viewport; fitView: (options?: FitViewOptions) => void; - project: Project; + fitBounds: (bounds: Rect, options?: FitBoundsOptions) => void; + deleteElements: ( + nodesToRemove?: Partial & { id: string }[], + edgesToRemove?: Partial & { id: string }[] + ) => { deletedNodes: Node[]; deletedEdges: Edge[] }; + screenToFlowCoordinate: (position: XYPosition) => XYPosition; + flowToScreenCoordinate: (position: XYPosition) => XYPosition; viewport: Writable; - nodes: SvelteFlowStore['nodes']; - edges: SvelteFlowStore['edges']; } { const { zoomIn, @@ -35,10 +42,12 @@ export function useSvelteFlow(): { viewport, width, height, + minZoom, maxZoom, panZoom, nodes, - edges + edges, + domNode } = useStore(); return { @@ -78,14 +87,94 @@ export function useSvelteFlow(): { ); }, fitView, - project: (position: XYPosition) => { - const _snapGrid = get(snapGrid); - const { x, y, zoom } = get(viewport); + fitBounds: (bounds: Rect, options?: FitBoundsOptions) => { + const _width = get(width); + const _height = get(height); + const _maxZoom = get(maxZoom); + const _minZoom = get(minZoom); - return pointToRendererPoint(position, [x, y, zoom], _snapGrid !== null, _snapGrid || [1, 1]); + const [x, y, zoom] = getTransformForBounds( + bounds, + _width, + _height, + _minZoom, + _maxZoom, + options?.padding ?? 0.1 + ); + + get(panZoom)?.setViewport( + { + x, + y, + zoom + }, + { duration: options?.duration } + ); + }, + deleteElements: ( + nodesToRemove: Partial & { id: string }[] = [], + edgesToRemove: Partial & { id: string }[] = [] + ) => { + const _nodes = get(nodes); + const _edges = get(edges); + const { matchingNodes, matchingEdges } = getElementsToRemove({ + nodesToRemove, + edgesToRemove, + nodes: _nodes, + edges: _edges + }); + + if (matchingNodes) { + nodes.set(_nodes.filter((node) => !matchingNodes.some(({ id }) => id === node.id))); + } + + if (matchingEdges) { + edges.set(_edges.filter((edge) => !matchingEdges.some(({ id }) => id === edge.id))); + } + + return { + deletedNodes: matchingNodes, + deletedEdges: matchingEdges + }; + }, + screenToFlowCoordinate: (position: XYPosition) => { + const _domNode = get(domNode); + if (_domNode) { + const _snapGrid = get(snapGrid); + const { x, y, zoom } = get(viewport); + const { x: domX, y: domY } = _domNode.getBoundingClientRect(); + + const correctedPosition = { + x: position.x - domX, + y: position.y - domY + }; + + return pointToRendererPoint( + correctedPosition, + [x, y, zoom], + _snapGrid !== null, + _snapGrid || [1, 1] + ); + } + + return { x: 0, y: 0 }; + }, + flowToScreenCoordinate: (position: XYPosition) => { + const _domNode = get(domNode); + if (_domNode) { + const { x, y, zoom } = get(viewport); + const { x: domX, y: domY } = _domNode.getBoundingClientRect(); + + const rendererPosition = rendererPointToPoint(position, [x, y, zoom]); + + return { + x: rendererPosition.x + domX, + y: rendererPosition.y + domY + }; + } + + return { x: 0, y: 0 }; }, - nodes, - edges, viewport: viewport }; }