fix(viewport): make onViewportChange prop dynamic #4579

This commit is contained in:
moklick
2024-09-02 14:42:42 +02:00
parent 5032f56a99
commit 5bbc9fb09c
6 changed files with 38 additions and 19 deletions

View File

@@ -1,4 +1,4 @@
import { MouseEvent, useCallback, useState } from 'react';
import { MouseEvent, useCallback, useRef, useState } from 'react';
import {
ReactFlow,
addEdge,
@@ -55,10 +55,18 @@ const Flow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initEdges);
const [viewport, setViewport] = useState<Viewport>({ x: 0, y: 0, zoom: 1 });
const [viewport2, setViewport2] = useState<Viewport>({ x: 100, y: 100, zoom: 1.5 });
const [currentViewport, setCurrentViewport] = useState(0);
const { fitView } = useReactFlow();
const onConnect = useCallback((params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
const setter = currentViewport === 0 ? setViewport : setViewport2;
const toggleViewport = () => {
setCurrentViewport(currentViewport === 0 ? 1 : 0);
};
return (
<ReactFlow
nodes={nodes}
@@ -66,12 +74,13 @@ const Flow = () => {
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
viewport={viewport}
onViewportChange={setViewport}
viewport={currentViewport === 0 ? viewport : viewport2}
onViewportChange={setter}
>
<Panel position="top-left">
<button onClick={() => setViewport((vp) => ({ ...vp, y: vp.y + 10 }))}>update viewport</button>
<button onClick={() => setter((vp) => ({ ...vp, y: vp.y + 10 }))}>update viewport</button>
<button onClick={() => fitView()}>fitView</button>
<button onClick={() => toggleViewport()}>toggle viewport</button>
</Panel>
<MiniMap />

View File

@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useEffect, useRef } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import { shallow } from 'zustand/shallow';
import { XYPanZoom, PanOnScrollMode, type Transform, type PanZoomInstance } from '@xyflow/system';
@@ -57,6 +57,17 @@ export function ZoomPane({
useResizeHandler(zoomPane);
const onTransformChange = useCallback(
(transform: Transform) => {
onViewportChange?.({ x: transform[0], y: transform[1], zoom: transform[2] });
if (!isControlledViewport) {
store.setState({ transform });
}
},
[onViewportChange, isControlledViewport]
);
useEffect(() => {
if (zoomPane.current) {
panZoom.current = XYPanZoom({
@@ -66,13 +77,6 @@ export function ZoomPane({
translateExtent,
viewport: defaultViewport,
paneClickDistance,
onTransformChange: (transform: Transform) => {
onViewportChange?.({ x: transform[0], y: transform[1], zoom: transform[2] });
if (!isControlledViewport) {
store.setState({ transform });
}
},
onDraggingChange: (paneDragging: boolean) => store.setState({ paneDragging }),
onPanZoomStart: (event, vp) => {
const { onViewportChangeStart, onMoveStart } = store.getState();
@@ -121,6 +125,7 @@ export function ZoomPane({
userSelectionActive,
noWheelClassName,
lib,
onTransformChange,
});
}, [
onPaneContextMenu,
@@ -137,6 +142,7 @@ export function ZoomPane({
userSelectionActive,
noWheelClassName,
lib,
onTransformChange,
]);
return (

View File

@@ -5,6 +5,7 @@ import {
type CoordinateExtent,
type OnPanZoom,
type PanZoomInstance,
type Transform,
type Viewport
} from '@xyflow/system';
@@ -36,6 +37,7 @@ type ZoomParams = {
userSelectionActive: boolean;
lib: string;
paneClickDistance: number;
onTransformChange: (transform: Transform) => void;
};
export default function zoom(domNode: Element, params: ZoomParams) {
@@ -57,8 +59,6 @@ export default function zoom(domNode: Element, params: ZoomParams) {
translateExtent,
viewport: initialViewport,
paneClickDistance,
onTransformChange: (transform) =>
viewport.set({ x: transform[0], y: transform[1], zoom: transform[2] }),
onDraggingChange: dragging.set
});
const currentViewport = panZoomInstance.getViewport();

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import { PanOnScrollMode } from '@xyflow/system';
import { onMount } from 'svelte';
import { PanOnScrollMode, type Transform } from '@xyflow/system';
import { useStore } from '$lib/store';
import zoom from '$lib/actions/zoom';
import type { ZoomProps } from './types';
import { onMount } from 'svelte';
type $$Props = ZoomProps;
@@ -39,6 +39,9 @@
$: _panOnDrag = $panActivationKeyPressed || panOnDrag;
$: _panOnScroll = $panActivationKeyPressed || panOnScroll;
const onTransformChange = (transform: Transform) =>
viewport.set({ x: transform[0], y: transform[1], zoom: transform[2] });
onMount(() => {
$viewportInitialized = true;
});
@@ -70,7 +73,8 @@
userSelectionActive: !!$selectionRect,
translateExtent: $translateExtent,
lib: $lib,
paneClickDistance
paneClickDistance,
onTransformChange
}}
>
<slot />

View File

@@ -12,7 +12,6 @@ export type PanZoomParams = {
paneClickDistance: number;
viewport: Viewport;
translateExtent: CoordinateExtent;
onTransformChange: OnTransformChange;
onDraggingChange: OnDraggingChange;
onPanZoomStart?: OnPanZoom;
onPanZoom?: OnPanZoom;
@@ -40,6 +39,7 @@ export type PanZoomUpdateOptions = {
zoomOnDoubleClick: boolean;
zoomActivationKeyPressed: boolean;
lib: string;
onTransformChange: OnTransformChange;
};
export type PanZoomInstance = {

View File

@@ -40,7 +40,6 @@ export function XYPanZoom({
onPanZoom,
onPanZoomStart,
onPanZoomEnd,
onTransformChange,
onDraggingChange,
}: PanZoomParams): PanZoomInstance {
const zoomPanValues: ZoomPanValues = {
@@ -105,6 +104,7 @@ export function XYPanZoom({
zoomOnDoubleClick,
zoomActivationKeyPressed,
lib,
onTransformChange,
}: PanZoomUpdateOptions) {
if (userSelectionActive && !zoomPanValues.isZoomingOrPanning) {
destroy();