refactor(fitView): use same fitView function for viewport helper and initial prop
This commit is contained in:
@@ -63,7 +63,7 @@ const BasicFlow = () => {
|
||||
defaultZoom={1.5}
|
||||
minZoom={0.2}
|
||||
maxZoom={4}
|
||||
fitViewOnInit
|
||||
fitView
|
||||
>
|
||||
<Background variant={BackgroundVariant.Lines} />
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ const ControlledUncontrolled = () => {
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
defaultEdgeOptions={defaultEdgeOptions}
|
||||
fitViewOnInit
|
||||
fitView
|
||||
>
|
||||
<Background variant={BackgroundVariant.Lines} />
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import ReactFlow, {
|
||||
|
||||
import ColorSelectorNode from './ColorSelectorNode';
|
||||
|
||||
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => {
|
||||
const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
||||
console.log('flow loaded:', reactFlowInstance);
|
||||
reactFlowInstance.fitView();
|
||||
};
|
||||
@@ -111,13 +111,13 @@ const CustomNodeFlow = () => {
|
||||
onConnect={onConnect}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
style={{ background: bgColor }}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
nodeTypes={nodeTypes}
|
||||
connectionLineStyle={connectionLineStyle}
|
||||
snapToGrid={true}
|
||||
snapGrid={snapGrid}
|
||||
defaultZoom={1.5}
|
||||
fitViewOnInit
|
||||
fitView
|
||||
>
|
||||
<MiniMap
|
||||
nodeStrokeColor={(n: Node): string => {
|
||||
|
||||
@@ -55,12 +55,7 @@ const DefaultNodes = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<ReactFlow
|
||||
defaultNodes={defaultNodes}
|
||||
defaultEdges={defaultEdges}
|
||||
defaultEdgeOptions={defaultEdgeOptions}
|
||||
fitViewOnInit
|
||||
>
|
||||
<ReactFlow defaultNodes={defaultNodes} defaultEdges={defaultEdges} defaultEdgeOptions={defaultEdgeOptions} fitView>
|
||||
<Background variant={BackgroundVariant.Lines} />
|
||||
|
||||
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
|
||||
|
||||
@@ -31,7 +31,7 @@ const DnDFlow = () => {
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
|
||||
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
||||
const onPaneReady = (rfi: ReactFlowInstance) => setReactFlowInstance(rfi);
|
||||
const onInit = (rfi: ReactFlowInstance) => setReactFlowInstance(rfi);
|
||||
|
||||
const onDrop = (event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
@@ -60,7 +60,7 @@ const DnDFlow = () => {
|
||||
onEdgesChange={onEdgesChange}
|
||||
onNodesChange={onNodesChange}
|
||||
onConnect={onConnect}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
onDrop={onDrop}
|
||||
onDragOver={onDragOver}
|
||||
>
|
||||
|
||||
@@ -15,7 +15,7 @@ import ReactFlow, {
|
||||
} from 'react-flow-renderer';
|
||||
import { getElements } from './utils';
|
||||
|
||||
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => {
|
||||
const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
||||
reactFlowInstance.fitView();
|
||||
console.log(reactFlowInstance.getNodes());
|
||||
};
|
||||
@@ -36,7 +36,7 @@ const EdgeTypesFlow = () => {
|
||||
edges={edges}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
onConnect={onConnect}
|
||||
minZoom={0.2}
|
||||
zoomOnScroll={false}
|
||||
|
||||
@@ -18,7 +18,7 @@ import ReactFlow, {
|
||||
import CustomEdge from './CustomEdge';
|
||||
import CustomEdge2 from './CustomEdge2';
|
||||
|
||||
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
|
||||
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
|
||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||
|
||||
@@ -121,7 +121,7 @@ const EdgesFlow = () => {
|
||||
onNodeClick={onNodeClick}
|
||||
onConnect={onConnect}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
snapToGrid={true}
|
||||
edgeTypes={edgeTypes}
|
||||
>
|
||||
|
||||
@@ -13,7 +13,7 @@ import ReactFlow, {
|
||||
ReactFlowInstance,
|
||||
} from 'react-flow-renderer';
|
||||
|
||||
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
|
||||
const onInit = (reactFlowInstance: ReactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
|
||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||
|
||||
@@ -38,7 +38,7 @@ const EmptyFlow = () => {
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onNodeClick={onNodeClick}
|
||||
|
||||
@@ -16,7 +16,7 @@ import FloatingEdge from './FloatingEdge';
|
||||
import FloatingConnectionLine from './FloatingConnectionLine';
|
||||
import { createElements } from './utils';
|
||||
|
||||
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
|
||||
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
|
||||
|
||||
const { nodes: initialNodes, edges: initialEdges } = createElements();
|
||||
|
||||
@@ -40,7 +40,7 @@ const FloatingEdges = () => {
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onConnect={onConnect}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
edgeTypes={edgeTypes}
|
||||
connectionLineComponent={FloatingConnectionLine}
|
||||
>
|
||||
|
||||
@@ -67,7 +67,7 @@ const LayoutFlow = () => {
|
||||
edges={edges}
|
||||
onConnect={onConnect}
|
||||
nodeExtent={nodeExtent}
|
||||
onPaneReady={() => onLayout('TB')}
|
||||
onInit={() => onLayout('TB')}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
>
|
||||
|
||||
@@ -91,7 +91,7 @@ const NestedFlow = () => {
|
||||
const onConnect = useCallback((connection: Connection) => {
|
||||
setEdges((eds) => addEdge(connection, eds));
|
||||
}, []);
|
||||
const onPaneReady = useCallback((reactFlowInstance: ReactFlowInstance) => setRfInstance(reactFlowInstance), []);
|
||||
const onInit = useCallback((reactFlowInstance: ReactFlowInstance) => setRfInstance(reactFlowInstance), []);
|
||||
|
||||
const updatePos = () => {
|
||||
setNodes((nds) => {
|
||||
@@ -131,7 +131,7 @@ const NestedFlow = () => {
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onNodeClick={onNodeClick}
|
||||
|
||||
@@ -58,7 +58,7 @@ const NodeTypeChangeFlow = () => {
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onConnect={onConnect}
|
||||
fitViewOnInit
|
||||
fitView
|
||||
>
|
||||
<button onClick={changeType} style={buttonStyle}>
|
||||
change type
|
||||
|
||||
@@ -32,7 +32,7 @@ const onSelectionContextMenu = (event: MouseEvent, nodes: Node[]) => {
|
||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('node click:', node);
|
||||
|
||||
const onSelectionChange = ({ nodes, edges }: OnSelectionChangeParams) => console.log('selection change', nodes, edges);
|
||||
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => {
|
||||
const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
||||
console.log('pane ready:', reactFlowInstance);
|
||||
};
|
||||
|
||||
@@ -183,7 +183,7 @@ const OverviewFlow = () => {
|
||||
onSelectionChange={onSelectionChange}
|
||||
onMoveStart={onMoveStart}
|
||||
onMoveEnd={onMoveEnd}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
connectionLineStyle={connectionLineStyle}
|
||||
snapToGrid={true}
|
||||
snapGrid={snapGrid}
|
||||
@@ -192,8 +192,10 @@ const OverviewFlow = () => {
|
||||
onEdgeMouseMove={onEdgeMouseMove}
|
||||
onEdgeMouseLeave={onEdgeMouseLeave}
|
||||
onEdgeDoubleClick={onEdgeDoubleClick}
|
||||
fitViewOnInit
|
||||
fitView
|
||||
fitViewOptions={{ padding: 0.2 }}
|
||||
attributionPosition="top-right"
|
||||
maxZoom={Infinity}
|
||||
>
|
||||
<MiniMap nodeStrokeColor={nodeStrokeColor} nodeColor={nodeColor} nodeBorderRadius={2} />
|
||||
<Controls />
|
||||
|
||||
@@ -17,7 +17,7 @@ import Sidebar from './Sidebar';
|
||||
import './provider.css';
|
||||
|
||||
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
|
||||
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => console.log('pane ready:', reactFlowInstance);
|
||||
const onInit = (reactFlowInstance: ReactFlowInstance) => console.log('pane ready:', reactFlowInstance);
|
||||
|
||||
const initialNodes: Node[] = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
@@ -48,7 +48,7 @@ const ProviderFlow = () => {
|
||||
onEdgesChange={onEdgesChange}
|
||||
onNodeClick={onNodeClick}
|
||||
onConnect={onConnect}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
connectionMode={ConnectionMode.Loose}
|
||||
>
|
||||
<Controls />
|
||||
|
||||
@@ -35,7 +35,7 @@ const SaveRestore = () => {
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onConnect={onConnect}
|
||||
onPaneReady={setRfInstance}
|
||||
onInit={setRfInstance}
|
||||
>
|
||||
<Controls rfInstance={rfInstance} setNodes={setNodes} setEdges={setEdges} />
|
||||
</ReactFlow>
|
||||
|
||||
@@ -16,7 +16,7 @@ import { getNodesAndEdges } from './utils';
|
||||
|
||||
const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: 10, top: 10, zIndex: 4 };
|
||||
|
||||
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => {
|
||||
const onInit = (reactFlowInstance: ReactFlowInstance) => {
|
||||
reactFlowInstance.fitView();
|
||||
console.log(reactFlowInstance.getNodes());
|
||||
};
|
||||
@@ -55,13 +55,7 @@ const StressFlow = () => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onPaneReady={onPaneReady}
|
||||
onConnect={onConnect}
|
||||
onNodesChange={onNodesChange}
|
||||
>
|
||||
<ReactFlow nodes={nodes} edges={edges} onInit={onInit} onConnect={onConnect} onNodesChange={onNodesChange}>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background />
|
||||
|
||||
@@ -113,7 +113,7 @@ const BasicFlow = () => {
|
||||
const onConnect = useCallback((connection: Connection) => {
|
||||
setEdges((eds) => addEdge(connection, eds));
|
||||
}, []);
|
||||
const onPaneReady = useCallback((reactFlowInstance: ReactFlowInstance) => setRfInstance(reactFlowInstance), []);
|
||||
const onInit = useCallback((reactFlowInstance: ReactFlowInstance) => setRfInstance(reactFlowInstance), []);
|
||||
|
||||
const updatePos = () => {
|
||||
setNodes((nds) => {
|
||||
@@ -155,7 +155,7 @@ const BasicFlow = () => {
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onNodeClick={onNodeClick}
|
||||
@@ -168,7 +168,7 @@ const BasicFlow = () => {
|
||||
maxZoom={4}
|
||||
onlyRenderVisibleElements={false}
|
||||
nodeTypes={nodeTypes}
|
||||
fitViewOnInit
|
||||
fitView
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
|
||||
@@ -53,7 +53,7 @@ const initialNodes: Node[] = [
|
||||
|
||||
const initialEdges = [{ id: 'e1-2', source: '1', target: '2', label: 'This is a draggable edge' }];
|
||||
|
||||
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
|
||||
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
|
||||
const onEdgeUpdateStart = (_: React.MouseEvent, edge: Edge) => console.log('start update', edge);
|
||||
const onEdgeUpdateEnd = (_: MouseEvent, edge: Edge) => console.log('end update', edge);
|
||||
|
||||
@@ -79,7 +79,7 @@ const UpdatableEdge = () => {
|
||||
edges={edges}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
snapToGrid={true}
|
||||
onEdgeUpdate={onEdgeUpdate}
|
||||
onConnect={onConnect}
|
||||
|
||||
@@ -33,7 +33,7 @@ const UseZoomPanHelperFlow = () => {
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
||||
const { project, setCenter, zoomIn, zoomOut } = useReactFlow();
|
||||
const { project, setCenter, zoomIn, zoomOut, fitView } = useReactFlow();
|
||||
|
||||
const onPaneClick = useCallback(
|
||||
(evt) => {
|
||||
@@ -55,7 +55,7 @@ const UseZoomPanHelperFlow = () => {
|
||||
const onNodeClick = useCallback(
|
||||
(_, element) => {
|
||||
const { x, y } = element.position;
|
||||
setCenter(x, y, { zoom: 1 });
|
||||
setCenter(x, y, { zoom: 1, duration: 1200 });
|
||||
},
|
||||
[setCenter]
|
||||
);
|
||||
@@ -69,10 +69,14 @@ const UseZoomPanHelperFlow = () => {
|
||||
onNodeClick={onNodeClick}
|
||||
onConnect={onConnect}
|
||||
onPaneClick={onPaneClick}
|
||||
fitView
|
||||
fitViewOptions={{ duration: 1200, padding: 0.2 }}
|
||||
maxZoom={Infinity}
|
||||
>
|
||||
<div style={{ position: 'absolute', left: 0, top: 0, zIndex: 100 }}>
|
||||
<button onClick={() => zoomIn({ duration: 1200 })}>zoomIn</button>
|
||||
<button onClick={() => zoomOut({ duration: 0 })}>zoomOut</button>
|
||||
<button onClick={() => fitView({ duration: 1200, padding: 0.3 })}>fitView</button>
|
||||
</div>
|
||||
<Background />
|
||||
<MiniMap />
|
||||
|
||||
@@ -70,7 +70,7 @@ const ValidationFlow = () => {
|
||||
onConnectStart={onConnectStart}
|
||||
onConnectStop={onConnectStop}
|
||||
onConnectEnd={onConnectEnd}
|
||||
fitViewOnInit
|
||||
fitView
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Generated
+1
-1
@@ -14,7 +14,7 @@
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-zoom": "^3.0.0",
|
||||
"react-draggable": "^4.4.4",
|
||||
"zustand": "^3.6.7"
|
||||
"zustand": "^3.6.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.5",
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-zoom": "^3.0.0",
|
||||
"react-draggable": "^4.4.4",
|
||||
"zustand": "^3.6.7"
|
||||
"zustand": "^3.6.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.5",
|
||||
|
||||
@@ -25,7 +25,7 @@ const Controls: FC<ControlProps> = ({
|
||||
showZoom = true,
|
||||
showFitView = true,
|
||||
showInteractive = true,
|
||||
fitViewParams,
|
||||
fitViewOptions,
|
||||
onZoomIn,
|
||||
onZoomOut,
|
||||
onFitView,
|
||||
@@ -51,9 +51,9 @@ const Controls: FC<ControlProps> = ({
|
||||
}, [zoomOut, onZoomOut]);
|
||||
|
||||
const onFitViewHandler = useCallback(() => {
|
||||
fitView?.(fitViewParams);
|
||||
fitView?.(fitViewOptions);
|
||||
onFitView?.();
|
||||
}, [fitView, fitViewParams, onFitView]);
|
||||
}, [fitView, fitViewOptions, onFitView]);
|
||||
|
||||
const onInteractiveChangeHandler = useCallback(() => {
|
||||
store.setState({
|
||||
|
||||
@@ -5,7 +5,7 @@ import shallow from 'zustand/shallow';
|
||||
import MiniMapNode from './MiniMapNode';
|
||||
|
||||
import { useStore } from '../../store';
|
||||
import { getRectOfNodeInternals } from '../../utils/graph';
|
||||
import { getRectOfNodes } from '../../utils/graph';
|
||||
import { getBoundsofRects } from '../../utils';
|
||||
|
||||
import { MiniMapProps, GetMiniMapNodeAttribute, ReactFlowState, Rect } from '../../types';
|
||||
@@ -48,7 +48,7 @@ const MiniMap = ({
|
||||
const hasNodes = nodeInternals && nodeInternals.size > 0;
|
||||
// @TODO: work with nodeInternals instead of converting it to an array
|
||||
const nodes = Array.from(nodeInternals).map(([_, node]) => node);
|
||||
const bb = getRectOfNodeInternals(nodes);
|
||||
const bb = getRectOfNodes(nodes);
|
||||
const viewBB: Rect = {
|
||||
x: -tX / tScale,
|
||||
y: -tY / tScale,
|
||||
|
||||
@@ -4,12 +4,12 @@ import cc from 'classcat';
|
||||
import { AttributionPosition, ProOptions } from '../../types';
|
||||
|
||||
type AttributionProps = {
|
||||
pro?: ProOptions;
|
||||
proOptions?: ProOptions;
|
||||
position?: AttributionPosition;
|
||||
};
|
||||
|
||||
function Attribution({ pro, position = 'bottom-right' }: AttributionProps) {
|
||||
if (pro?.account === 'paid-subscription' && pro?.hideAttribution) {
|
||||
function Attribution({ proOptions, position = 'bottom-right' }: AttributionProps) {
|
||||
if (proOptions?.account === 'paid-subscription' && proOptions?.hideAttribution) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ export default (NodeComponent: ComponentType<NodeProps>) => {
|
||||
sourcePosition,
|
||||
targetPosition,
|
||||
hidden,
|
||||
isInitialized,
|
||||
snapToGrid,
|
||||
snapGrid,
|
||||
dragging,
|
||||
@@ -60,11 +59,9 @@ export default (NodeComponent: ComponentType<NodeProps>) => {
|
||||
zIndex,
|
||||
transform: `translate(${xPos}px,${yPos}px)`,
|
||||
pointerEvents: hasPointerEvents ? 'all' : 'none',
|
||||
// prevents jumping of nodes on start
|
||||
opacity: isInitialized ? 1 : 0,
|
||||
...style,
|
||||
}),
|
||||
[zIndex, xPos, yPos, hasPointerEvents, isInitialized, style]
|
||||
[zIndex, xPos, yPos, hasPointerEvents, style]
|
||||
);
|
||||
|
||||
const node = useMemo(() => ({ id, type, position: { x: xPos, y: yPos }, data }), [id, type, xPos, yPos, data]);
|
||||
|
||||
@@ -10,7 +10,7 @@ import shallow from 'zustand/shallow';
|
||||
|
||||
import { useStore } from '../../store';
|
||||
import { Node, ReactFlowState } from '../../types';
|
||||
import { getRectOfNodeInternals } from '../../utils/graph';
|
||||
import { getRectOfNodes } from '../../utils/graph';
|
||||
|
||||
export interface NodesSelectionProps {
|
||||
onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void;
|
||||
@@ -55,7 +55,7 @@ function NodesSelection({
|
||||
[tX, tY, tScale]
|
||||
);
|
||||
|
||||
const selectedNodesBbox = useMemo(() => getRectOfNodeInternals(selectedNodes), [selectedNodes]);
|
||||
const selectedNodesBbox = useMemo(() => getRectOfNodes(selectedNodes), [selectedNodes]);
|
||||
|
||||
const innerStyle = useMemo(
|
||||
() => ({
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
ConnectionMode,
|
||||
SnapGrid,
|
||||
DefaultEdgeOptions,
|
||||
FitViewOptions,
|
||||
} from '../../types';
|
||||
|
||||
interface StoreUpdaterProps {
|
||||
@@ -40,9 +41,10 @@ interface StoreUpdaterProps {
|
||||
snapToGrid?: boolean;
|
||||
snapGrid?: SnapGrid;
|
||||
translateExtent?: CoordinateExtent;
|
||||
fitViewOnInit: boolean;
|
||||
connectOnClick: boolean;
|
||||
defaultEdgeOptions?: DefaultEdgeOptions;
|
||||
fitView?: boolean;
|
||||
fitViewOptions?: FitViewOptions;
|
||||
}
|
||||
|
||||
const selector = (s: ReactFlowState) => ({
|
||||
@@ -94,9 +96,10 @@ const StoreUpdater = ({
|
||||
snapGrid,
|
||||
snapToGrid,
|
||||
translateExtent,
|
||||
fitViewOnInit,
|
||||
connectOnClick,
|
||||
defaultEdgeOptions,
|
||||
fitView,
|
||||
fitViewOptions,
|
||||
}: StoreUpdaterProps) => {
|
||||
const {
|
||||
setNodes,
|
||||
@@ -127,12 +130,13 @@ const StoreUpdater = ({
|
||||
useDirectStoreUpdater('nodesDraggable', nodesDraggable, store.setState);
|
||||
useDirectStoreUpdater('nodesConnectable', nodesConnectable, store.setState);
|
||||
useDirectStoreUpdater('elementsSelectable', elementsSelectable, store.setState);
|
||||
useDirectStoreUpdater('fitViewOnInit', fitViewOnInit, store.setState);
|
||||
useDirectStoreUpdater('snapToGrid', snapToGrid, store.setState);
|
||||
useDirectStoreUpdater('snapGrid', snapGrid, store.setState);
|
||||
useDirectStoreUpdater('onNodesChange', onNodesChange, store.setState);
|
||||
useDirectStoreUpdater('onEdgesChange', onEdgesChange, store.setState);
|
||||
useDirectStoreUpdater('connectOnClick', connectOnClick, store.setState);
|
||||
useDirectStoreUpdater('fitViewOnInit', fitView, store.setState);
|
||||
useDirectStoreUpdater('fitViewOnInitOptions', fitViewOptions, store.setState);
|
||||
|
||||
useStoreUpdater<Node[]>(nodes, setNodes);
|
||||
useStoreUpdater<Edge[]>(edges, setEdges);
|
||||
|
||||
@@ -4,7 +4,7 @@ import FlowRenderer from '../FlowRenderer';
|
||||
import NodeRenderer from '../NodeRenderer';
|
||||
import EdgeRenderer from '../EdgeRenderer';
|
||||
import Viewport from '../Viewport';
|
||||
import useOnPaneReadyHandler from '../../hooks/useOnPaneReadyHandler';
|
||||
import useOnInitHandler from '../../hooks/useOnInitHandler';
|
||||
import { NodeTypesType, EdgeTypesType, ConnectionLineType, KeyCode, ReactFlowProps } from '../../types';
|
||||
|
||||
export interface GraphViewProps extends Omit<ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges'> {
|
||||
@@ -30,7 +30,7 @@ const GraphView = ({
|
||||
onMove,
|
||||
onMoveStart,
|
||||
onMoveEnd,
|
||||
onPaneReady,
|
||||
onInit,
|
||||
onNodeClick,
|
||||
onEdgeClick,
|
||||
onNodeDoubleClick,
|
||||
@@ -82,7 +82,7 @@ const GraphView = ({
|
||||
noWheelClassName,
|
||||
noPanClassName,
|
||||
}: GraphViewProps) => {
|
||||
useOnPaneReadyHandler(onPaneReady);
|
||||
useOnInitHandler(onInit);
|
||||
|
||||
return (
|
||||
<FlowRenderer
|
||||
|
||||
@@ -37,7 +37,7 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
||||
const { scale, nodesDraggable, nodesConnectable, elementsSelectable, updateNodeDimensions, snapGrid, snapToGrid } =
|
||||
useStore(selector, shallow);
|
||||
const nodes = useVisibleNodes(props.onlyRenderVisibleElements);
|
||||
const reseizeObserverRef = useRef<ResizeObserver>();
|
||||
const resizeObserverRef = useRef<ResizeObserver>();
|
||||
|
||||
const resizeObserver = useMemo(() => {
|
||||
if (typeof ResizeObserver === 'undefined') {
|
||||
@@ -54,14 +54,14 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
||||
updateNodeDimensions(updates);
|
||||
});
|
||||
|
||||
reseizeObserverRef.current = observer;
|
||||
resizeObserverRef.current = observer;
|
||||
|
||||
return observer;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
reseizeObserverRef?.current?.disconnect();
|
||||
resizeObserverRef?.current?.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -78,8 +78,6 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
||||
const isDraggable = !!(node.draggable || (nodesDraggable && typeof node.draggable === 'undefined'));
|
||||
const isSelectable = !!(node.selectable || (elementsSelectable && typeof node.selectable === 'undefined'));
|
||||
const isConnectable = !!(node.connectable || (nodesConnectable && typeof node.connectable === 'undefined'));
|
||||
const isInitialized =
|
||||
node.width && node.height && typeof node.width !== 'undefined' && typeof node.height !== 'undefined';
|
||||
|
||||
return (
|
||||
<NodeComponent
|
||||
@@ -95,7 +93,6 @@ const NodeRenderer = (props: NodeRendererProps) => {
|
||||
xPos={node.positionAbsolute?.x ?? 0}
|
||||
yPos={node.positionAbsolute?.y ?? 0}
|
||||
dragging={!!node.dragging}
|
||||
isInitialized={!!isInitialized}
|
||||
snapGrid={snapGrid}
|
||||
snapToGrid={snapToGrid}
|
||||
selectNodesOnDrag={props.selectNodesOnDrag}
|
||||
|
||||
@@ -46,7 +46,7 @@ const ReactFlow: FunctionComponent<ReactFlowProps> = forwardRef<ReactFlowRefType
|
||||
edgeTypes = defaultEdgeTypes,
|
||||
onNodeClick,
|
||||
onEdgeClick,
|
||||
onPaneReady,
|
||||
onInit,
|
||||
onMove,
|
||||
onMoveStart,
|
||||
onMoveEnd,
|
||||
@@ -115,10 +115,11 @@ const ReactFlow: FunctionComponent<ReactFlowProps> = forwardRef<ReactFlowRefType
|
||||
noDragClassName = 'nodrag',
|
||||
noWheelClassName = 'nowheel',
|
||||
noPanClassName = 'nopan',
|
||||
fitViewOnInit = false,
|
||||
fitView = false,
|
||||
fitViewOptions,
|
||||
connectOnClick = true,
|
||||
attributionPosition,
|
||||
pro,
|
||||
proOptions,
|
||||
defaultEdgeOptions,
|
||||
...rest
|
||||
},
|
||||
@@ -132,7 +133,7 @@ const ReactFlow: FunctionComponent<ReactFlowProps> = forwardRef<ReactFlowRefType
|
||||
<div {...rest} ref={ref} className={reactFlowClasses}>
|
||||
<Wrapper>
|
||||
<GraphView
|
||||
onPaneReady={onPaneReady}
|
||||
onInit={onInit}
|
||||
onMove={onMove}
|
||||
onMoveStart={onMoveStart}
|
||||
onMoveEnd={onMoveEnd}
|
||||
@@ -209,13 +210,14 @@ const ReactFlow: FunctionComponent<ReactFlowProps> = forwardRef<ReactFlowRefType
|
||||
snapGrid={snapGrid}
|
||||
connectionMode={connectionMode}
|
||||
translateExtent={translateExtent}
|
||||
fitViewOnInit={fitViewOnInit}
|
||||
connectOnClick={connectOnClick}
|
||||
defaultEdgeOptions={defaultEdgeOptions}
|
||||
fitView={fitView}
|
||||
fitViewOptions={fitViewOptions}
|
||||
/>
|
||||
{onSelectionChange && <SelectionListener onSelectionChange={onSelectionChange} />}
|
||||
{children}
|
||||
<Attribution pro={pro} position={attributionPosition} />
|
||||
<Attribution proOptions={proOptions} position={attributionPosition} />
|
||||
</Wrapper>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
import useReactFlow from './useReactFlow';
|
||||
import { OnPaneReady } from '../types';
|
||||
import { OnInit } from '../types';
|
||||
|
||||
function useOnPaneReadyHandler(onPaneReady: OnPaneReady<any> | undefined) {
|
||||
function useOnInitHandler(onInit: OnInit<any> | undefined) {
|
||||
const ReactFlowInstance = useReactFlow();
|
||||
const isInitialized = useRef<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isInitialized.current && ReactFlowInstance.viewportInitialized && onPaneReady) {
|
||||
onPaneReady(ReactFlowInstance);
|
||||
|
||||
if (!isInitialized.current && ReactFlowInstance.viewportInitialized && onInit) {
|
||||
setTimeout(() => onInit(ReactFlowInstance), 1);
|
||||
isInitialized.current = true;
|
||||
}
|
||||
}, [onPaneReady, ReactFlowInstance]);
|
||||
}, [onInit, ReactFlowInstance.viewportInitialized]);
|
||||
}
|
||||
|
||||
export default useOnPaneReadyHandler;
|
||||
export default useOnInitHandler;
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useMemo } from 'react';
|
||||
import { zoomIdentity } from 'd3-zoom';
|
||||
import shallow from 'zustand/shallow';
|
||||
import { Selection as D3Selection } from 'd3';
|
||||
|
||||
import { useStoreApi, useStore } from '../store';
|
||||
import { getRectOfNodeInternals, pointToRendererPoint, getTransformForBounds } from '../utils/graph';
|
||||
import { FitViewParams, Viewport, ViewportHelperFunctions, ReactFlowState, Rect, XYPosition } from '../types';
|
||||
import { pointToRendererPoint, getTransformForBounds, getD3Transition } from '../utils/graph';
|
||||
import { FitViewOptions, Viewport, ViewportHelperFunctions, ReactFlowState, Rect, XYPosition } from '../types';
|
||||
import { fitView as fitViewStore } from '../store/utils';
|
||||
|
||||
const DEFAULT_PADDING = 0.1;
|
||||
|
||||
@@ -16,7 +16,7 @@ const initialViewportHelper: ViewportHelperFunctions = {
|
||||
getZoom: () => 1,
|
||||
setViewport: (_: Viewport) => {},
|
||||
getViewport: () => ({ x: 0, y: 0, zoom: 1 }),
|
||||
fitView: (_: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => {},
|
||||
fitView: (_: FitViewOptions = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => {},
|
||||
setCenter: (_: number, __: number) => {},
|
||||
fitBounds: (_: Rect) => {},
|
||||
project: (position: XYPosition) => position,
|
||||
@@ -28,10 +28,6 @@ const selector = (s: ReactFlowState) => ({
|
||||
d3Selection: s.d3Selection,
|
||||
});
|
||||
|
||||
const getTransition = (selection: D3Selection<Element, unknown, null, undefined>, duration: number = 0) => {
|
||||
return selection.transition().duration(duration);
|
||||
};
|
||||
|
||||
const useViewportHelper = (): ViewportHelperFunctions => {
|
||||
const store = useStoreApi();
|
||||
const { d3Zoom, d3Selection } = useStore(selector, shallow);
|
||||
@@ -39,45 +35,22 @@ const useViewportHelper = (): ViewportHelperFunctions => {
|
||||
const viewportHelperFunctions = useMemo<ViewportHelperFunctions>(() => {
|
||||
if (d3Selection && d3Zoom) {
|
||||
return {
|
||||
zoomIn: (options) => d3Zoom.scaleBy(getTransition(d3Selection, options?.duration), 1.2),
|
||||
zoomOut: (options) => d3Zoom.scaleBy(getTransition(d3Selection, options?.duration), 1 / 1.2),
|
||||
zoomTo: (zoomLevel, options) => d3Zoom.scaleTo(getTransition(d3Selection, options?.duration), zoomLevel),
|
||||
zoomIn: (options) => d3Zoom.scaleBy(getD3Transition(d3Selection, options?.duration), 1.2),
|
||||
zoomOut: (options) => d3Zoom.scaleBy(getD3Transition(d3Selection, options?.duration), 1 / 1.2),
|
||||
zoomTo: (zoomLevel, options) => d3Zoom.scaleTo(getD3Transition(d3Selection, options?.duration), zoomLevel),
|
||||
getZoom: () => {
|
||||
const [, , zoom] = store.getState().transform;
|
||||
return zoom;
|
||||
},
|
||||
setViewport: (transform, options) => {
|
||||
const nextTransform = zoomIdentity.translate(transform.x, transform.y).scale(transform.zoom);
|
||||
d3Zoom.transform(getTransition(d3Selection, options?.duration), nextTransform);
|
||||
d3Zoom.transform(getD3Transition(d3Selection, options?.duration), nextTransform);
|
||||
},
|
||||
getViewport: () => {
|
||||
const [x, y, zoom] = store.getState().transform;
|
||||
return { x, y, zoom };
|
||||
},
|
||||
fitView: (options) => {
|
||||
const { nodeInternals, width, height, minZoom, maxZoom } = store.getState();
|
||||
// @TODO: work with nodeInternals instead of converting it to an array
|
||||
const nodes = Array.from(nodeInternals).map(([_, node]) => node);
|
||||
|
||||
if (!nodes.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bounds = getRectOfNodeInternals(
|
||||
options?.includeHiddenNodes ? nodes : nodes.filter((node) => !node.hidden)
|
||||
);
|
||||
const [x, y, zoom] = getTransformForBounds(
|
||||
bounds,
|
||||
width,
|
||||
height,
|
||||
options?.minZoom ?? minZoom,
|
||||
options?.maxZoom ?? maxZoom,
|
||||
options?.padding ?? DEFAULT_PADDING
|
||||
);
|
||||
const transform = zoomIdentity.translate(x, y).scale(zoom);
|
||||
|
||||
d3Zoom.transform(getTransition(d3Selection, options?.duration), transform);
|
||||
},
|
||||
fitView: (options) => fitViewStore(store.getState, options),
|
||||
setCenter: (x, y, options) => {
|
||||
const { width, height, maxZoom } = store.getState();
|
||||
const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom;
|
||||
@@ -85,21 +58,14 @@ const useViewportHelper = (): ViewportHelperFunctions => {
|
||||
const centerY = height / 2 - y * nextZoom;
|
||||
const transform = zoomIdentity.translate(centerX, centerY).scale(nextZoom);
|
||||
|
||||
d3Zoom.transform(getTransition(d3Selection, options?.duration), transform);
|
||||
d3Zoom.transform(getD3Transition(d3Selection, options?.duration), transform);
|
||||
},
|
||||
fitBounds: (bounds, options) => {
|
||||
const { width, height, minZoom, maxZoom } = store.getState();
|
||||
const [x, y, zoom] = getTransformForBounds(
|
||||
bounds,
|
||||
width,
|
||||
height,
|
||||
minZoom,
|
||||
maxZoom,
|
||||
options?.padding ?? DEFAULT_PADDING
|
||||
);
|
||||
const [x, y, zoom] = getTransformForBounds(bounds, width, height, minZoom, maxZoom, options?.padding ?? 0.1);
|
||||
const transform = zoomIdentity.translate(x, y).scale(zoom);
|
||||
|
||||
d3Zoom.transform(getTransition(d3Selection, options?.duration), transform);
|
||||
d3Zoom.transform(getD3Transition(d3Selection, options?.duration), transform);
|
||||
},
|
||||
project: (position: XYPosition) => {
|
||||
const { transform, snapToGrid, snapGrid } = store.getState();
|
||||
|
||||
+7
-4
@@ -3,6 +3,7 @@ import createContext from 'zustand/context';
|
||||
|
||||
import { clampPosition, getDimensions } from '../utils';
|
||||
import { applyNodeChanges } from '../utils/changes';
|
||||
|
||||
import {
|
||||
ReactFlowState,
|
||||
Node,
|
||||
@@ -20,10 +21,10 @@ import { createSelectionChange, getSelectionChanges } from '../utils/changes';
|
||||
import {
|
||||
createNodeInternals,
|
||||
createPositionChange,
|
||||
fitView,
|
||||
handleControlledEdgeSelectionChange,
|
||||
handleControlledNodeSelectionChange,
|
||||
isParentSelected,
|
||||
fitView,
|
||||
} from './utils';
|
||||
import initialState from './initialState';
|
||||
|
||||
@@ -54,7 +55,7 @@ const createStore = () =>
|
||||
set({ nodeInternals, edges: nextEdges, hasDefaultNodes, hasDefaultEdges });
|
||||
},
|
||||
updateNodeDimensions: (updates: NodeDimensionUpdate[]) => {
|
||||
const { onNodesChange, transform, nodeInternals, fitViewOnInit } = get();
|
||||
const { onNodesChange, transform, nodeInternals, fitViewOnInit, fitViewOnInitDone, fitViewOnInitOptions } = get();
|
||||
|
||||
const changes: NodeDimensionChange[] = updates.reduce<NodeDimensionChange[]>((res, update) => {
|
||||
const node = nodeInternals.get(update.id);
|
||||
@@ -86,8 +87,9 @@ const createStore = () =>
|
||||
return res;
|
||||
}, []);
|
||||
|
||||
const fitViewOnInitDone = fitViewOnInit && fitView(get);
|
||||
set({ nodeInternals: new Map(nodeInternals), fitViewOnInitDone });
|
||||
const nextFitViewOnInitDone =
|
||||
fitViewOnInit && !fitViewOnInitDone && fitView(get, { initial: true, ...fitViewOnInitOptions });
|
||||
set({ nodeInternals: new Map(nodeInternals), fitViewOnInitDone: nextFitViewOnInitDone });
|
||||
|
||||
if (changes?.length > 0) {
|
||||
onNodesChange?.(changes);
|
||||
@@ -186,6 +188,7 @@ const createStore = () =>
|
||||
onEdgesChange?.(edgesToUnselect);
|
||||
}
|
||||
},
|
||||
|
||||
setMinZoom: (minZoom: number) => {
|
||||
const { d3Zoom, maxZoom } = get();
|
||||
d3Zoom?.scaleExtent([minZoom, maxZoom]);
|
||||
|
||||
@@ -37,14 +37,14 @@ const initialState: ReactFlowStore = {
|
||||
nodesDraggable: true,
|
||||
nodesConnectable: true,
|
||||
elementsSelectable: true,
|
||||
fitViewOnInit: false,
|
||||
fitViewOnInitDone: false,
|
||||
fitViewOnInitOptions: undefined,
|
||||
|
||||
multiSelectionActive: false,
|
||||
|
||||
reactFlowVersion: typeof __REACT_FLOW_VERSION__ !== 'undefined' ? __REACT_FLOW_VERSION__ : '-',
|
||||
|
||||
fitViewOnInit: false,
|
||||
fitViewOnInitDone: false,
|
||||
|
||||
connectionStartHandle: null,
|
||||
connectOnClick: true,
|
||||
};
|
||||
|
||||
+35
-14
@@ -2,7 +2,7 @@ import { zoomIdentity } from 'd3-zoom';
|
||||
import { GetState } from 'zustand';
|
||||
|
||||
import { clampPosition, isNumeric } from '../utils';
|
||||
import { getRectOfNodes, getTransformForBounds } from '../utils/graph';
|
||||
import { getD3Transition, getRectOfNodes, getTransformForBounds } from '../utils/graph';
|
||||
import {
|
||||
CoordinateExtent,
|
||||
Edge,
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
ReactFlowState,
|
||||
XYPosition,
|
||||
XYZPosition,
|
||||
FitViewOptions,
|
||||
} from '../types';
|
||||
|
||||
type ParentNodes = Record<string, boolean>;
|
||||
@@ -145,26 +146,46 @@ export function createPositionChange({
|
||||
return change;
|
||||
}
|
||||
|
||||
export function fitView(get: GetState<ReactFlowState>) {
|
||||
type InternalFitViewOptions = {
|
||||
initial?: boolean;
|
||||
} & FitViewOptions;
|
||||
|
||||
export function fitView(get: GetState<ReactFlowState>, options: InternalFitViewOptions = {}) {
|
||||
let { nodeInternals, width, height, minZoom, maxZoom, d3Zoom, d3Selection, fitViewOnInitDone, fitViewOnInit } = get();
|
||||
|
||||
if (fitViewOnInit && !fitViewOnInitDone && d3Zoom && d3Selection) {
|
||||
const rootNodes = Array.from(nodeInternals)
|
||||
.filter(([_, n]) => !n.parentNode)
|
||||
.map(([_, n]) => n);
|
||||
const nodesInitialized = rootNodes.every((n) => n.width && n.height);
|
||||
if ((options.initial && !fitViewOnInitDone && fitViewOnInit) || !options.initial) {
|
||||
if (d3Zoom && d3Selection) {
|
||||
const nodes = Array.from(nodeInternals.values()).filter((n) =>
|
||||
options.includeHiddenNodes ? !n.parentNode && n.width && n.height : !n.parentNode && !n.hidden
|
||||
);
|
||||
|
||||
if (rootNodes.length > 0 && nodesInitialized) {
|
||||
const bounds = getRectOfNodes(rootNodes);
|
||||
const [x, y, zoom] = getTransformForBounds(bounds, width, height, minZoom ?? 0.5, maxZoom ?? 2);
|
||||
const nodesInitialized = nodes.every((n) => n.width && n.height);
|
||||
|
||||
const nextTransform = zoomIdentity.translate(x, y).scale(zoom);
|
||||
d3Zoom.transform(d3Selection, nextTransform);
|
||||
fitViewOnInitDone = true;
|
||||
if (nodes.length > 0 && nodesInitialized) {
|
||||
const bounds = getRectOfNodes(nodes);
|
||||
const [x, y, zoom] = getTransformForBounds(
|
||||
bounds,
|
||||
width,
|
||||
height,
|
||||
options.minZoom ?? minZoom,
|
||||
options.maxZoom ?? maxZoom,
|
||||
options.padding ?? 0.1
|
||||
);
|
||||
|
||||
const nextTransform = zoomIdentity.translate(x, y).scale(zoom);
|
||||
|
||||
if (typeof options.duration === 'number' && options.duration > 0) {
|
||||
d3Zoom.transform(getD3Transition(d3Selection, options.duration), nextTransform);
|
||||
} else {
|
||||
d3Zoom.transform(d3Selection, nextTransform);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fitViewOnInitDone;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function handleControlledNodeSelectionChange(nodeChanges: NodeSelectionChange[], nodeInternals: NodeInternals) {
|
||||
|
||||
@@ -20,15 +20,15 @@ import {
|
||||
OnEdgeUpdateFunc,
|
||||
NodeChange,
|
||||
EdgeChange,
|
||||
OnPaneReady,
|
||||
OnInit,
|
||||
ProOptions,
|
||||
AttributionPosition,
|
||||
DefaultEdgeOptions,
|
||||
FitViewParams,
|
||||
FitViewOptions,
|
||||
BackgroundVariant,
|
||||
} from '.';
|
||||
|
||||
export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onPaneReady'> {
|
||||
export interface ReactFlowProps extends HTMLAttributes<HTMLDivElement> {
|
||||
nodes?: Node[];
|
||||
edges?: Edge[];
|
||||
defaultNodes?: Node[];
|
||||
@@ -50,7 +50,7 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
||||
onConnectStart?: OnConnectStart;
|
||||
onConnectStop?: OnConnectStop;
|
||||
onConnectEnd?: OnConnectEnd;
|
||||
onPaneReady?: OnPaneReady;
|
||||
onInit?: OnInit;
|
||||
onMove?: (viewport?: Viewport) => void;
|
||||
onMoveStart?: (viewport?: Viewport) => void;
|
||||
onMoveEnd?: (viewport?: Viewport) => void;
|
||||
@@ -106,10 +106,11 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
||||
noDragClassName?: string;
|
||||
noWheelClassName?: string;
|
||||
noPanClassName?: string;
|
||||
fitViewOnInit?: boolean;
|
||||
fitView?: boolean;
|
||||
fitViewOptions?: FitViewOptions;
|
||||
connectOnClick?: boolean;
|
||||
attributionPosition?: AttributionPosition;
|
||||
pro?: ProOptions;
|
||||
proOptions?: ProOptions;
|
||||
}
|
||||
|
||||
export type ReactFlowRefType = HTMLDivElement;
|
||||
@@ -129,7 +130,7 @@ export interface ControlProps extends HTMLAttributes<HTMLDivElement> {
|
||||
showZoom?: boolean;
|
||||
showFitView?: boolean;
|
||||
showInteractive?: boolean;
|
||||
fitViewParams?: FitViewParams;
|
||||
fitViewOptions?: FitViewOptions;
|
||||
onZoomIn?: () => void;
|
||||
onZoomOut?: () => void;
|
||||
onFitView?: () => void;
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ReactFlowInstance } from './instance';
|
||||
export type NodeTypesType = { [key: string]: ReactNode };
|
||||
export type EdgeTypesType = NodeTypesType;
|
||||
|
||||
export type FitView = (fitViewOptions?: FitViewParams) => void;
|
||||
export type FitView = (fitViewOptions?: FitViewOptions) => void;
|
||||
|
||||
export type Project = (position: XYPosition) => XYPosition;
|
||||
|
||||
@@ -28,9 +28,7 @@ export type SetViewport = (viewport: Viewport, options?: ViewportHelperFunctionO
|
||||
export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => void;
|
||||
export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => void;
|
||||
|
||||
export type OnPaneReady<NodeData = any, EdgeData = any> = (
|
||||
reactFlowInstance: ReactFlowInstance<NodeData, EdgeData>
|
||||
) => void;
|
||||
export type OnInit<NodeData = any, EdgeData = any> = (reactFlowInstance: ReactFlowInstance<NodeData, EdgeData>) => void;
|
||||
|
||||
export interface Connection {
|
||||
source: string | null;
|
||||
@@ -46,7 +44,7 @@ export enum ConnectionMode {
|
||||
|
||||
export type OnConnect = (connection: Connection) => void;
|
||||
|
||||
export type FitViewParams = {
|
||||
export type FitViewOptions = {
|
||||
padding?: number;
|
||||
includeHiddenNodes?: boolean;
|
||||
minZoom?: number;
|
||||
@@ -153,9 +151,6 @@ export type ReactFlowStore = {
|
||||
|
||||
reactFlowVersion: string;
|
||||
|
||||
fitViewOnInit: boolean;
|
||||
fitViewOnInitDone: boolean;
|
||||
|
||||
connectionStartHandle: StartHandle | null;
|
||||
|
||||
onConnect?: OnConnect;
|
||||
@@ -165,6 +160,10 @@ export type ReactFlowStore = {
|
||||
|
||||
connectOnClick: boolean;
|
||||
defaultEdgeOptions?: DefaultEdgeOptions;
|
||||
|
||||
fitViewOnInit: boolean;
|
||||
fitViewOnInitDone: boolean;
|
||||
fitViewOnInitOptions: FitViewOptions | undefined;
|
||||
};
|
||||
|
||||
export type ReactFlowActions = {
|
||||
|
||||
@@ -81,7 +81,6 @@ export interface WrapNodeProps<T = any> {
|
||||
sourcePosition?: Position;
|
||||
targetPosition?: Position;
|
||||
hidden?: boolean;
|
||||
isInitialized?: boolean;
|
||||
snapToGrid?: boolean;
|
||||
snapGrid?: SnapGrid;
|
||||
dragging: boolean;
|
||||
|
||||
+15
-13
@@ -1,3 +1,4 @@
|
||||
import { Selection as D3Selection } from 'd3';
|
||||
import { boxToRect, clamp, getBoundsOfBoxes, rectToBox } from '../utils';
|
||||
|
||||
import { Node, Edge, Connection, EdgeMarkerType, Transform, XYPosition, Rect, NodeInternals } from '../types';
|
||||
@@ -124,21 +125,18 @@ export const pointToRendererPoint = (
|
||||
return position;
|
||||
};
|
||||
|
||||
// @TODO: use one function for getRectOfNodes and getRectOfNodeInternals
|
||||
export const getRectOfNodes = (nodes: Node[]): Rect => {
|
||||
const box = nodes.reduce(
|
||||
(currBox, { position, width, height }) =>
|
||||
getBoundsOfBoxes(currBox, rectToBox({ ...position, width: width || 0, height: height || 0 })),
|
||||
{ x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity }
|
||||
);
|
||||
|
||||
return boxToRect(box);
|
||||
};
|
||||
|
||||
export const getRectOfNodeInternals = (nodes: Node[]): Rect => {
|
||||
const box = nodes.reduce(
|
||||
(currBox, { positionAbsolute, width, height }) =>
|
||||
getBoundsOfBoxes(currBox, rectToBox({ ...positionAbsolute!, width: width || 0, height: height || 0 })),
|
||||
(currBox, { positionAbsolute, position, width, height }) =>
|
||||
getBoundsOfBoxes(
|
||||
currBox,
|
||||
rectToBox({
|
||||
x: positionAbsolute ? positionAbsolute.x : position.x,
|
||||
y: positionAbsolute ? positionAbsolute.y : position.y,
|
||||
width: width || 0,
|
||||
height: height || 0,
|
||||
})
|
||||
),
|
||||
{ x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity }
|
||||
);
|
||||
|
||||
@@ -213,3 +211,7 @@ export const getTransformForBounds = (
|
||||
|
||||
return [x, y, clampedZoom];
|
||||
};
|
||||
|
||||
export const getD3Transition = (selection: D3Selection<Element, unknown, null, undefined>, duration: number = 0) => {
|
||||
return selection.transition().duration(duration);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user