diff --git a/packages/svelte/src/lib/container/Panel/Panel.svelte b/packages/svelte/src/lib/container/Panel/Panel.svelte
index 23d3f79e..86b8aa35 100644
--- a/packages/svelte/src/lib/container/Panel/Panel.svelte
+++ b/packages/svelte/src/lib/container/Panel/Panel.svelte
@@ -2,17 +2,18 @@
import cc from 'classcat';
import type { PanelProps } from './types';
- interface $$Props extends PanelProps {}
+ type $$Props = PanelProps;
export let position: $$Props['position'] = 'top-right';
- export let style: $$Props['style'] = '';
+ export let style: $$Props['style'] = undefined;
+
let className: $$Props['class'] = undefined;
export { className as class };
$: positionClasses = `${position}`.split('-');
-
+
diff --git a/packages/svelte/src/lib/container/Panel/types.ts b/packages/svelte/src/lib/container/Panel/types.ts
index 01f071da..32bbea01 100644
--- a/packages/svelte/src/lib/container/Panel/types.ts
+++ b/packages/svelte/src/lib/container/Panel/types.ts
@@ -1,6 +1,8 @@
import type { PanelPosition } from '@reactflow/system';
+import type { HTMLAttributes } from 'svelte/elements';
-export type PanelProps = {
+export type PanelProps = HTMLAttributes
& {
+ 'data-testid'?: string;
position?: PanelPosition;
style?: string;
class?: string;
diff --git a/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte b/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte
index a12fd924..7b7153b3 100644
--- a/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte
+++ b/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte
@@ -96,7 +96,7 @@
bind:this={domNode}
style={style}
class={cc(['svelte-flow', className])}
- data-testid="rf__wrapper"
+ data-testid="svelte-flow__wrapper"
on:dragover
on:drop
{...$$restProps}
diff --git a/packages/svelte/src/lib/hooks/useSvelteFlow.ts b/packages/svelte/src/lib/hooks/useSvelteFlow.ts
index cd246eea..d24c299f 100644
--- a/packages/svelte/src/lib/hooks/useSvelteFlow.ts
+++ b/packages/svelte/src/lib/hooks/useSvelteFlow.ts
@@ -1,22 +1,47 @@
-import type { Project, Viewport, XYPosition, ZoomInOut } from '@reactflow/system';
+import { get, writable, type Writable } from 'svelte/store';
+import type {
+ Project,
+ SetCenterOptions,
+ Viewport,
+ ViewportHelperFunctionOptions,
+ XYPosition,
+ ZoomInOut
+} from '@reactflow/system';
+import { zoomIdentity } from 'd3-zoom';
import { useStore } from '$lib/store';
import type { FitViewOptions } from '$lib/types';
-import { get, writable, type Writable } from 'svelte/store';
import type { SvelteFlowStore } from '$lib/store/types';
-import { pointToRendererPoint } from '@reactflow/utils';
+import { getD3Transition, pointToRendererPoint } from '@reactflow/utils';
export function useSvelteFlow(): {
zoomIn: ZoomInOut;
zoomOut: ZoomInOut;
+ setZoom: (zoomLevel: number, options?: ViewportHelperFunctionOptions) => void;
+ getZoom: () => number;
+ setCenter: (x: number, y: number, options?: SetCenterOptions) => void;
+ setViewport: (viewport: Viewport, options?: ViewportHelperFunctionOptions) => void;
+ getViewport: () => Viewport;
fitView: (options?: FitViewOptions) => void;
+ project: Project;
viewport: Writable;
nodes: SvelteFlowStore['nodes'];
edges: SvelteFlowStore['edges'];
- project: Project;
} {
// how to get the new context here? fit view doesn't work, because the store is not updated (uses old nodes store)
- const { zoomIn, zoomOut, fitView, snapGrid: snapGridStore, transform, nodes, edges } = useStore();
+ const {
+ zoomIn,
+ zoomOut,
+ fitView,
+ snapGrid,
+ transform,
+ width,
+ height,
+ maxZoom,
+ d3,
+ nodes,
+ edges
+ } = useStore();
const transformValues = get(transform);
const viewportWritable = writable({
@@ -36,10 +61,53 @@ export function useSvelteFlow(): {
return {
zoomIn,
zoomOut,
+ setZoom: (zoomLevel, options) => {
+ const { zoom, selection } = get(d3);
+
+ if (zoom && selection) {
+ zoom.scaleTo(getD3Transition(selection, options?.duration), zoomLevel);
+ }
+ },
+ getZoom: () => get(transform)[2],
+ setViewport: (viewport, options) => {
+ const [x, y, zoom] = get(transform);
+ const { zoom: d3Zoom, selection } = get(d3);
+
+ if (d3Zoom && selection) {
+ const nextTransform = zoomIdentity
+ .translate(viewport.x ?? x, viewport.y ?? y)
+ .scale(viewport.zoom ?? zoom);
+ d3Zoom.transform(getD3Transition(selection, options?.duration), nextTransform);
+ }
+ },
+ getViewport: () => {
+ const [x, y, zoom] = get(transform);
+ return { x, y, zoom };
+ },
+ setCenter: (x, y, options) => {
+ const _width = get(width);
+ const _height = get(height);
+ const _maxZoom = get(maxZoom);
+ const { zoom, selection } = get(d3);
+
+ if (zoom && selection) {
+ const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : _maxZoom;
+ const centerX = _width / 2 - x * nextZoom;
+ const centerY = _height / 2 - y * nextZoom;
+ const transform = zoomIdentity.translate(centerX, centerY).scale(nextZoom);
+
+ zoom.transform(getD3Transition(selection, options?.duration), transform);
+ }
+ },
fitView,
project: (position: XYPosition) => {
- const snapGrid = get(snapGridStore);
- return pointToRendererPoint(position, get(transform), snapGrid !== null, snapGrid || [1, 1]);
+ const _snapGrid = get(snapGrid);
+ return pointToRendererPoint(
+ position,
+ get(transform),
+ _snapGrid !== null,
+ _snapGrid || [1, 1]
+ );
},
nodes,
edges,
diff --git a/packages/svelte/src/lib/plugins/Background/Background.svelte b/packages/svelte/src/lib/plugins/Background/Background.svelte
index c8e74f72..908d3f6d 100644
--- a/packages/svelte/src/lib/plugins/Background/Background.svelte
+++ b/packages/svelte/src/lib/plugins/Background/Background.svelte
@@ -47,7 +47,7 @@
: [patternDimensions[0] / 2, patternDimensions[1] / 2];
-