feat(rf): add fitViewOnInit option
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import React, { MutableRefObject, useEffect, useRef } from 'react';
|
||||
|
||||
import { Node } from '../../types';
|
||||
import { getRectOfNodes, getTransformForBounds } from '../../utils/graph';
|
||||
import { useStoreApi } from '../../store';
|
||||
import useZoomPanHelper from '../../hooks/useZoomPanHelper';
|
||||
|
||||
type ViewFitterInnerProps = {
|
||||
nodes: Node[];
|
||||
viewFitted: MutableRefObject<boolean>;
|
||||
};
|
||||
|
||||
function ViewFitterInner({ nodes, viewFitted }: ViewFitterInnerProps) {
|
||||
const store = useStoreApi();
|
||||
const { setTransform } = useZoomPanHelper();
|
||||
|
||||
useEffect(() => {
|
||||
if (nodes.length > 0 && !viewFitted.current) {
|
||||
const nodesInitialized = nodes.every((n) => n.width && n.height);
|
||||
|
||||
if (nodesInitialized) {
|
||||
const { width, height, minZoom, maxZoom } = store.getState();
|
||||
const bounds = getRectOfNodes(nodes);
|
||||
const [x, y, zoom] = getTransformForBounds(bounds, width, height, minZoom ?? 0.5, maxZoom ?? 2);
|
||||
|
||||
viewFitted.current = true;
|
||||
setTransform({ x, y, zoom });
|
||||
}
|
||||
}
|
||||
}, [nodes]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export type ViewFitterProps = {
|
||||
nodes: Node[];
|
||||
};
|
||||
|
||||
function ViewFitter({ nodes }: ViewFitterProps) {
|
||||
// we are storing the viewFitted in this wrapper to get rid of the useEffect of the inner component
|
||||
// that needs to check if the nodes changed after we fitted the view.
|
||||
const viewFitted = useRef<boolean>(false);
|
||||
|
||||
if (viewFitted.current) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <ViewFitterInner nodes={nodes} viewFitted={viewFitted} />;
|
||||
}
|
||||
|
||||
export default ViewFitter;
|
||||
@@ -19,6 +19,7 @@ import SelectionListener from '../../components/SelectionListener';
|
||||
import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '../../components/Edges';
|
||||
import { createEdgeTypes } from '../EdgeRenderer/utils';
|
||||
import Wrapper from './Wrapper';
|
||||
import ViewFitter from '../../components/ViewFitter';
|
||||
import {
|
||||
OnSelectionChangeFunc,
|
||||
NodeTypesType,
|
||||
@@ -133,6 +134,7 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
||||
noDragClassName?: string;
|
||||
noWheelClassName?: string;
|
||||
noPanClassName?: string;
|
||||
fitViewOnInit?: boolean;
|
||||
}
|
||||
|
||||
export type ReactFlowRefType = HTMLDivElement;
|
||||
@@ -219,6 +221,7 @@ const ReactFlow: FunctionComponent<ReactFlowProps> = forwardRef<ReactFlowRefType
|
||||
noDragClassName = 'nodrag',
|
||||
noWheelClassName = 'nowheel',
|
||||
noPanClassName = 'nopan',
|
||||
fitViewOnInit = false,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
@@ -307,7 +310,7 @@ const ReactFlow: FunctionComponent<ReactFlowProps> = forwardRef<ReactFlowRefType
|
||||
connectionMode={connectionMode}
|
||||
translateExtent={translateExtent}
|
||||
/>
|
||||
|
||||
{fitViewOnInit && <ViewFitter nodes={nodes} />}
|
||||
{onSelectionChange && <SelectionListener onSelectionChange={onSelectionChange} />}
|
||||
{children}
|
||||
</Wrapper>
|
||||
|
||||
Reference in New Issue
Block a user