From 66caa4c8caf7119623b13cf1d0ae17ca0ef08d86 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 27 Sep 2023 13:40:03 +0200 Subject: [PATCH] chore(svelte) refactored connectionPath & connection --- .../ConnectionLine.svelte | 8 +-- .../ConnectionLine/ConnectionLine.svelte | 8 +-- ...on-path.ts => derived-connection-props.ts} | 49 +++++++++++++++++-- packages/svelte/src/lib/store/index.ts | 42 +++++++--------- .../svelte/src/lib/store/initial-store.ts | 13 ++--- packages/system/src/types/general.ts | 8 +-- packages/system/src/xyhandle/XYHandle.ts | 17 +++++-- 7 files changed, 88 insertions(+), 57 deletions(-) rename packages/svelte/src/lib/store/{connection-path.ts => derived-connection-props.ts} (68%) diff --git a/examples/svelte/src/routes/custom-connection-line/ConnectionLine.svelte b/examples/svelte/src/routes/custom-connection-line/ConnectionLine.svelte index a3676bb0..20ac6192 100644 --- a/examples/svelte/src/routes/custom-connection-line/ConnectionLine.svelte +++ b/examples/svelte/src/routes/custom-connection-line/ConnectionLine.svelte @@ -1,11 +1,11 @@ -{#if $connectionPath} - - +{#if $connection.path} + + {/if} diff --git a/packages/svelte/src/lib/components/ConnectionLine/ConnectionLine.svelte b/packages/svelte/src/lib/components/ConnectionLine/ConnectionLine.svelte index 9f53f486..d88cb728 100644 --- a/packages/svelte/src/lib/components/ConnectionLine/ConnectionLine.svelte +++ b/packages/svelte/src/lib/components/ConnectionLine/ConnectionLine.svelte @@ -6,14 +6,14 @@ export let containerStyle: string = ''; export let style: string = ''; - const { connectionPath, width, height, connection } = useStore(); + const { width, height, connection } = useStore(); -{#if $connectionPath} +{#if $connection.path} - - + + diff --git a/packages/svelte/src/lib/store/connection-path.ts b/packages/svelte/src/lib/store/derived-connection-props.ts similarity index 68% rename from packages/svelte/src/lib/store/connection-path.ts rename to packages/svelte/src/lib/store/derived-connection-props.ts index aea51c3f..f9586885 100644 --- a/packages/svelte/src/lib/store/connection-path.ts +++ b/packages/svelte/src/lib/store/derived-connection-props.ts @@ -1,4 +1,4 @@ -import { derived } from 'svelte/store'; +import { derived, type Writable } from 'svelte/store'; import { getBezierPath, getSmoothStepPath, @@ -10,6 +10,35 @@ import { } from '@xyflow/system'; import type { SvelteFlowStoreState } from './types'; +import type { ConnectionData } from '$lib/types'; + +export type ConnectionProps = { + path: string | null; + sourceX: number | null; + sourceY: number | null; + sourcePosition: Position | undefined | null; + targetX: number | null; + targetY: number | null; + targetPosition: Position | undefined | null; + pointerPosition: ConnectionData['connectionPosition'] | null; + startHandle: ConnectionData['connectionStartHandle'] | null; + endHandle: ConnectionData['connectionEndHandle'] | null; + status: ConnectionData['connectionStatus'] | null; +}; + +export const initConnectionProps = { + path: null, + sourceX: null, + sourceY: null, + sourcePosition: null, + targetX: null, + targetY: null, + targetPosition: null, + pointerPosition: null, + startHandle: null, + endHandle: null, + status: null +}; const oppositePosition = { [Position.Left]: Position.Right, @@ -18,10 +47,13 @@ const oppositePosition = { [Position.Bottom]: Position.Top }; -export function getConnectionPath(store: SvelteFlowStoreState) { +export function getDerivedConnectionProps( + store: SvelteFlowStoreState, + currentConnection: Writable +) { return derived( [ - store.connection, + currentConnection, store.connectionLineType, store.connectionMode, store.nodes, @@ -29,7 +61,7 @@ export function getConnectionPath(store: SvelteFlowStoreState) { ], ([connection, connectionLineType, connectionMode, nodes, transform]) => { if (!connection.connectionStartHandle?.nodeId) { - return null; + return initConnectionProps; } const fromNode = nodes.find((n) => n.id === connection.connectionStartHandle?.nodeId); @@ -80,7 +112,14 @@ export function getConnectionPath(store: SvelteFlowStoreState) { [path] = getStraightPath(pathParams); } - return path; + return { + path, + ...pathParams, + pointerPosition: connection.connectionPosition, + startHandle: connection.connectionStartHandle, + endHandle: connection.connectionEndHandle, + status: connection.connectionStatus + }; } ); } diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts index 08fc8b90..18896dae 100644 --- a/packages/svelte/src/lib/store/index.ts +++ b/packages/svelte/src/lib/store/index.ts @@ -1,5 +1,5 @@ import { getContext, setContext } from 'svelte'; -import { derived, get } from 'svelte/store'; +import { derived, get, writable } from 'svelte/store'; import { internalsSymbol, createMarkerIds, @@ -19,18 +19,13 @@ import { } from '@xyflow/system'; import { addEdge as addEdgeUtil } from '$lib/utils'; -import type { EdgeTypes, NodeTypes, Node, Edge, FitViewOptions } from '$lib/types'; -import { getConnectionPath } from './connection-path'; -import { - initConnectionData, - initialEdgeTypes, - initialNodeTypes, - getInitialStore -} from './initial-store'; +import type { EdgeTypes, NodeTypes, Node, Edge, FitViewOptions, ConnectionData } from '$lib/types'; +import { initialEdgeTypes, initialNodeTypes, getInitialStore } from './initial-store'; import type { SvelteFlowStore } from './types'; import { syncNodeStores, syncEdgeStores } from './utils'; import { getEdgeTree } from './edge-tree'; import { getVisibleNodes } from './visible-nodes'; +import { getDerivedConnectionProps } from './derived-connection-props'; export const key = Symbol(); @@ -252,25 +247,22 @@ export function createStore(): SvelteFlowStore { }); } - const updateConnection: UpdateConnection = (update) => { - const currentConnectionData = get(store.connection); + const initConnectionUpdateData = { + connectionStartHandle: null, + connectionEndHandle: null, + connectionPosition: null, + connectionStatus: null + }; - const nextConnectionData = currentConnectionData - ? { - ...initConnectionData, - ...currentConnectionData, - ...update - } - : { - ...initConnectionData, - ...update - }; - - store.connection.set(nextConnectionData); + // by creating an internal, unexposed store and using a derived store + // we prevent using slow get() calls + const currentConnection = writable(initConnectionUpdateData); + const updateConnection: UpdateConnection = (newConnection: ConnectionData) => { + currentConnection.set(newConnection); }; function cancelConnection() { - updateConnection(initConnectionData); + updateConnection(initConnectionUpdateData); } function reset() { @@ -292,7 +284,7 @@ export function createStore(): SvelteFlowStore { // derived state edgeTree: getEdgeTree(store), - connectionPath: getConnectionPath(store), + connection: getDerivedConnectionProps(store, currentConnection), visibleNodes: getVisibleNodes(store), markers: derived( [store.edges, store.defaultMarkerColor, store.flowId], diff --git a/packages/svelte/src/lib/store/initial-store.ts b/packages/svelte/src/lib/store/initial-store.ts index f3e69b9e..2740be0a 100644 --- a/packages/svelte/src/lib/store/initial-store.ts +++ b/packages/svelte/src/lib/store/initial-store.ts @@ -24,15 +24,9 @@ import BezierEdge from '$lib/components/edges/BezierEdge.svelte'; import StraightEdge from '$lib/components/edges/StraightEdge.svelte'; import SmoothStepEdge from '$lib/components/edges/SmoothStepEdge.svelte'; import StepEdge from '$lib/components/edges/StepEdge.svelte'; -import type { ConnectionData, NodeTypes, EdgeTypes, EdgeLayouted, Node } from '$lib/types'; +import type { NodeTypes, EdgeTypes, EdgeLayouted, Node } from '$lib/types'; import { createNodesStore, createEdgesStore } from './utils'; - -export const initConnectionData = { - connectionStartHandle: null, - connectionEndHandle: null, - connectionPosition: null, - connectionStatus: null -}; +import { initConnectionProps, type ConnectionProps } from './derived-connection-props'; export const initialNodeTypes = { input: InputNode, @@ -79,8 +73,7 @@ export const getInitialStore = () => ({ transform: writable([0, 0, 1]), connectionMode: writable(ConnectionMode.Strict), domNode: writable(null), - connectionPath: readable(null), - connection: writable(initConnectionData), + connection: readable(initConnectionProps), connectionLineType: writable(ConnectionLineType.Bezier), connectionRadius: writable(20), isValidConnection: writable(() => true), diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index ba1c6e3c..d23dee9b 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -131,8 +131,8 @@ export type UpdateNodePositions = ( export type PanBy = (delta: XYPosition) => boolean; export type UpdateConnection = (params: { - connectionPosition?: XYPosition | null; - connectionStatus?: ConnectionStatus | null; - connectionStartHandle?: ConnectingHandle | null; - connectionEndHandle?: ConnectingHandle | null; + connectionPosition: XYPosition | null; + connectionStatus: ConnectionStatus | null; + connectionStartHandle: ConnectingHandle | null; + connectionEndHandle: ConnectingHandle | null; }) => void; diff --git a/packages/system/src/xyhandle/XYHandle.ts b/packages/system/src/xyhandle/XYHandle.ts index 732b3e60..6ec86528 100644 --- a/packages/system/src/xyhandle/XYHandle.ts +++ b/packages/system/src/xyhandle/XYHandle.ts @@ -66,6 +66,8 @@ const nullConnection: Connection = { source: null, target: null, sourceHandle: n const alwaysValid = () => true; +let connectionStartHandle: ConnectingHandle | null = null; + function onPointerDown( event: MouseEvent | TouchEvent, { @@ -129,15 +131,18 @@ function onPointerDown( autoPanId = requestAnimationFrame(autoPan); } + // Stays the same for all consecutive pointermove events + connectionStartHandle = { + nodeId, + handleId, + type: handleType, + }; + updateConnection({ connectionPosition, connectionStatus: null, // connectionNodeId etc will be removed in the next major in favor of connectionStartHandle - connectionStartHandle: { - nodeId, - handleId, - type: handleType, - }, + connectionStartHandle, connectionEndHandle: null, }); @@ -173,6 +178,7 @@ function onPointerDown( isValid = result.isValid; updateConnection({ + connectionStartHandle, connectionPosition: closestHandle && isValid ? rendererPointToPoint( @@ -220,6 +226,7 @@ function onPointerDown( isValid = false; connection = null; handleDomNode = null; + connectionStartHandle = null; doc.removeEventListener('mousemove', onPointerMove as EventListener); doc.removeEventListener('mouseup', onPointerUp as EventListener);