diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 9e8d1321..3b2cd39d 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -16,7 +16,8 @@ ".": "./index.js" }, "dependencies": { - "@reactflow/system": "workspace:*", + "@reactflow/system": "workspace:11.5.5", + "@reactflow/utils": "workspace:^11.5.5", "cc": "^3.0.1", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", diff --git a/packages/svelte/src/lib/container/Viewport.svelte b/packages/svelte/src/lib/container/Viewport.svelte index 66cb8a27..61a8c944 100644 --- a/packages/svelte/src/lib/container/Viewport.svelte +++ b/packages/svelte/src/lib/container/Viewport.svelte @@ -2,10 +2,10 @@ import zoom from '$lib/hooks/zoom' import { useStore } from '$lib/store'; - const { transformStore } = useStore(); + const { transformStore, d3Store } = useStore(); -
+
event.target.closest(`.${className}`); export default function zoom( domNode: Element, - { transformStore }: { transformStore: Writable } + { + transformStore, + d3Store + }: { + transformStore: Writable; + d3Store: Writable<{ zoom: D3ZoomInstance | null; selection: D3SelectionInstance | null }>; + } ) { const d3ZoomInstance = d3Zoom(); const selection = select(domNode).call(d3ZoomInstance); @@ -26,6 +32,11 @@ export default function zoom( d3ZoomHandler!.call(this, event, d); }); + d3Store.set({ + zoom: d3ZoomInstance, + selection + }); + d3ZoomInstance.on('zoom', (event: D3ZoomEvent) => { transformStore.set([event.transform.x, event.transform.y, event.transform.k]); }); diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts index 865a6f14..ac038588 100644 --- a/packages/svelte/src/lib/store/index.ts +++ b/packages/svelte/src/lib/store/index.ts @@ -7,8 +7,12 @@ import { type NodeDimensionUpdate, type Edge, Position, - internalsSymbol + internalsSymbol, + type NodeOrigin, + type D3ZoomInstance, + type D3SelectionInstance } from '@reactflow/system'; +import { fitView } from '@reactflow/utils'; import { getDimensions, getHandleBounds } from '../../utils'; import { @@ -24,6 +28,7 @@ type CreateStoreProps = { nodes: Node[]; edges: Edge[]; fitView: boolean; + nodeOrigin?: NodeOrigin; transform?: Transform; }; @@ -37,6 +42,10 @@ type SvelteFlowStore = { edgesStore: Writable; heightStore: Writable; widthStore: Writable; + d3Store: Writable<{ + zoom: D3ZoomInstance | null; + selection: D3SelectionInstance | null; + }>; transformStore: Writable; edgesWithDataStore: Readable; updateNodePositions: ( @@ -51,12 +60,15 @@ export function createStore({ nodes = [], edges = [], transform = [0, 0, 1], + nodeOrigin = [0, 0], fitView: fitViewOnInit = false }: CreateStoreProps): SvelteFlowStore { const nodesStore = writable(nodes.map((n) => ({ ...n, positionAbsolute: n.position }))); const edgesStore = writable(edges); const heightStore = writable(500); const widthStore = writable(500); + const nodeOriginStore = writable(nodeOrigin); + const d3Store = writable({ zoom: null, selection: null }); let fitViewOnInitDone = false; @@ -166,10 +178,29 @@ export function createStore({ return node; }); - // const nextFitViewOnInitDone = - // fitViewOnInitDone || (fitViewOnInit && !fitViewOnInitDone && fitView(get, { initial: true })); + const { zoom: d3Zoom, selection: d3Selection } = get(d3Store); - // fitViewOnInitDone = nextFitViewOnInitDone; + const nextFitViewOnInitDone = + fitViewOnInitDone || + (fitViewOnInit && + !fitViewOnInitDone && + !!d3Zoom && + !!d3Selection && + fitView( + { + nodes: get(nodesStore), + width: get(widthStore), + height: get(heightStore), + minZoom: 0.2, + maxZoom: 2, + d3Selection, + d3Zoom, + nodeOrigin: get(nodeOriginStore) + }, + {} + )); + + fitViewOnInitDone = nextFitViewOnInitDone; nodesStore.set(nextNodes); } @@ -178,6 +209,7 @@ export function createStore({ nodesStore, edgesStore, transformStore, + d3Store, heightStore, widthStore, edgesWithDataStore, diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index f628727e..3a488d88 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -70,6 +70,15 @@ export enum ConnectionMode { export type OnConnect = (connection: Connection) => void; +export type FitViewParams = { + nodes: Node[]; + width: number; + height: number; + nodeOrigin: NodeOrigin; + d3Zoom: D3ZoomInstance; + d3Selection: D3SelectionInstance; +}; + export type FitViewOptions = { padding?: number; includeHiddenNodes?: boolean; @@ -137,6 +146,9 @@ export type ViewportHelperFunctions = { viewportInitialized: boolean; }; +export type D3ZoomInstance = ZoomBehavior; +export type D3SelectionInstance = D3Selection; + export type ReactFlowStore = { rfId: string; width: number; @@ -152,8 +164,8 @@ export type ReactFlowStore = { paneDragging: boolean; noPanClassName: string; - d3Zoom: ZoomBehavior | null; - d3Selection: D3Selection | null; + d3Zoom: D3ZoomInstance | null; + d3Selection: D3SelectionInstance | null; d3ZoomHandler: ((this: Element, event: any, d: unknown) => void) | undefined; minZoom: number; maxZoom: number; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5897d059..05e0cad5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -310,7 +310,8 @@ importers: packages/svelte: specifiers: - '@reactflow/system': workspace:* + '@reactflow/system': workspace:11.5.5 + '@reactflow/utils': workspace:^11.5.5 '@sveltejs/adapter-auto': ^2.0.0 '@sveltejs/kit': ^1.5.6 '@sveltejs/package': ^1.0.2 @@ -334,6 +335,7 @@ importers: vite: ^4.1.1 dependencies: '@reactflow/system': link:../system + '@reactflow/utils': link:../utils cc: registry.npmjs.org/cc/3.0.1 d3-drag: registry.npmjs.org/d3-drag/3.0.0 d3-selection: registry.npmjs.org/d3-selection/3.0.0 @@ -399,6 +401,7 @@ importers: '@types/node': ^18.7.16 '@types/react': '>=17' '@types/react-dom': '>=17' + d3-zoom: ^3.0.0 react: ^18.2.0 typescript: ^4.9.4 dependencies: @@ -407,6 +410,7 @@ importers: '@types/d3-drag': registry.npmjs.org/@types/d3-drag/3.0.1 '@types/d3-selection': registry.npmjs.org/@types/d3-selection/3.0.3 '@types/d3-zoom': registry.npmjs.org/@types/d3-zoom/3.0.1 + d3-zoom: registry.npmjs.org/d3-zoom/3.0.0 devDependencies: '@reactflow/eslint-config': link:../../tooling/eslint-config '@reactflow/rollup-config': link:../../tooling/rollup-config