Merge branch 'enhance/fitView' into enhance/fitViewOptions

This commit is contained in:
peterkogo
2025-03-25 10:25:24 +01:00
3 changed files with 54 additions and 31 deletions
+13 -3
View File
@@ -12,6 +12,8 @@ import {
Controls, Controls,
Background, Background,
Panel, Panel,
ReactFlowProvider,
useReactFlow,
} from '@xyflow/react'; } from '@xyflow/react';
import { getNodesAndEdges } from './utils'; import { getNodesAndEdges } from './utils';
@@ -22,6 +24,7 @@ const { nodes: initialNodes, edges: initialEdges } = getNodesAndEdges(25, 25);
const StressFlow = () => { const StressFlow = () => {
const [nodes, setNodes] = useState<Node[]>(initialNodes); const [nodes, setNodes] = useState<Node[]>(initialNodes);
const [edges, setEdges] = useState<Edge[]>(initialEdges); const [edges, setEdges] = useState<Edge[]>(initialEdges);
const { fitView } = useReactFlow();
const onConnect = useCallback((connection: Connection) => { const onConnect = useCallback((connection: Connection) => {
setEdges((eds) => addEdge(connection, eds)); setEdges((eds) => addEdge(connection, eds));
}, []); }, []);
@@ -191,12 +194,13 @@ const StressFlow = () => {
return { return {
...n, ...n,
position: { position: {
x: Math.random() * window.innerWidth, x: Math.random() * window.innerWidth * 4,
y: Math.random() * window.innerHeight, y: Math.random() * window.innerHeight * 4,
}, },
}; };
}); });
}); });
fitView();
}; };
const updateElements = () => { const updateElements = () => {
@@ -240,4 +244,10 @@ const StressFlow = () => {
); );
}; };
export default StressFlow; export default function StressFlowProvider() {
return (
<ReactFlowProvider>
<StressFlow />
</ReactFlowProvider>
);
}
+40 -27
View File
@@ -41,11 +41,36 @@ const createStore = ({
nodeOrigin?: NodeOrigin; nodeOrigin?: NodeOrigin;
nodeExtent?: CoordinateExtent; nodeExtent?: CoordinateExtent;
}) => }) =>
createWithEqualityFn<ReactFlowState>( createWithEqualityFn<ReactFlowState>((set, get) => {
(set, get) => ({ function resolveFitView() {
const { nodeLookup, panZoom, fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get();
if (!panZoom) {
return;
}
const fitViewPromise = fitViewport(
{
nodes: nodeLookup,
width,
height,
panZoom,
minZoom,
maxZoom,
},
fitViewOptions
);
fitViewPromise.then((value) => {
fitViewResolver?.resolve(value);
set({ fitViewResolver: null });
});
set({ nodes, fitViewQueued: false, fitViewOptions: undefined });
}
return {
...getInitialState({ nodes, edges, width, height, fitView, nodeOrigin, nodeExtent, defaultNodes, defaultEdges }), ...getInitialState({ nodes, edges, width, height, fitView, nodeOrigin, nodeExtent, defaultNodes, defaultEdges }),
setNodes: (nodes: Node[]) => { setNodes: (nodes: Node[]) => {
const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued, panZoom } = get(); const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued } = get();
/* /*
* setNodes() is called exclusively in response to user actions: * setNodes() is called exclusively in response to user actions:
* - either when the `<ReactFlow nodes>` prop is updated in the controlled ReactFlow setup, * - either when the `<ReactFlow nodes>` prop is updated in the controlled ReactFlow setup,
@@ -62,24 +87,8 @@ const createStore = ({
checkEquality: true, checkEquality: true,
}); });
if (fitViewQueued && nodesInitialized && panZoom) { if (fitViewQueued && nodesInitialized) {
const { fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); resolveFitView();
const fitViewPromise = fitViewport(
{
nodes: nodeLookup,
width,
height,
panZoom,
minZoom,
maxZoom,
},
fitViewOptions
);
fitViewPromise.then((value) => {
fitViewResolver?.resolve(value);
set({ fitViewResolver: null });
});
set({ nodes, fitViewQueued: false, fitViewOptions: undefined });
} else { } else {
set({ nodes }); set({ nodes });
} }
@@ -109,7 +118,8 @@ const createStore = ({
* new dimensions and update the nodes. * new dimensions and update the nodes.
*/ */
updateNodeInternals: (updates) => { updateNodeInternals: (updates) => {
const { triggerNodeChanges, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent, debug } = get(); const { triggerNodeChanges, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent, debug, fitViewQueued } =
get();
const { changes, updatedInternals } = updateNodeInternalsSystem( const { changes, updatedInternals } = updateNodeInternalsSystem(
updates, updates,
@@ -126,8 +136,12 @@ const createStore = ({
updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin, nodeExtent }); updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin, nodeExtent });
// we always want to trigger useStore calls whenever updateNodeInternals is called if (fitViewQueued) {
set({}); resolveFitView();
} else {
// we always want to trigger useStore calls whenever updateNodeInternals is called
set({});
}
if (changes?.length > 0) { if (changes?.length > 0) {
if (debug) { if (debug) {
@@ -329,8 +343,7 @@ const createStore = ({
}, },
reset: () => set({ ...getInitialState() }), reset: () => set({ ...getInitialState() }),
}), };
Object.is }, Object.is);
);
export { createStore }; export { createStore };
+1 -1
View File
@@ -108,7 +108,7 @@ const getInitialState = ({
multiSelectionActive: false, multiSelectionActive: false,
fitViewQueued: false, fitViewQueued: fitView ?? false,
fitViewOptions: undefined, fitViewOptions: undefined,
fitViewResolver: null, fitViewResolver: null,