package(core): use system fitView
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
import { useMemo } from 'react';
|
||||
import { zoomIdentity } from 'd3-zoom';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { pointToRendererPoint, getTransformForBounds, getD3Transition } from '@reactflow/utils';
|
||||
import { pointToRendererPoint, getTransformForBounds, getD3Transition, fitView } from '@reactflow/utils';
|
||||
import type { ViewportHelperFunctions, ReactFlowState, XYPosition } from '@reactflow/system';
|
||||
|
||||
import { useStoreApi, useStore } from '../hooks/useStore';
|
||||
import { fitView } from '../store/utils';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const noop = () => {};
|
||||
@@ -51,7 +50,28 @@ const useViewportHelper = (): ViewportHelperFunctions => {
|
||||
const [x, y, zoom] = store.getState().transform;
|
||||
return { x, y, zoom };
|
||||
},
|
||||
fitView: (options) => fitView(store.getState, options),
|
||||
fitView: (options) => {
|
||||
const { getNodes, width, height, nodeOrigin, minZoom, maxZoom, d3Selection, d3Zoom } = store.getState();
|
||||
const d3Initialized = d3Selection && d3Zoom;
|
||||
|
||||
if (!d3Initialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fitView(
|
||||
{
|
||||
nodes: getNodes(),
|
||||
width,
|
||||
height,
|
||||
nodeOrigin,
|
||||
minZoom,
|
||||
maxZoom,
|
||||
d3Selection,
|
||||
d3Zoom,
|
||||
},
|
||||
options
|
||||
);
|
||||
},
|
||||
setCenter: (x, y, options) => {
|
||||
const { width, height, maxZoom } = store.getState();
|
||||
const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createStore } from 'zustand';
|
||||
import { zoomIdentity } from 'd3-zoom';
|
||||
import { clampPosition, getDimensions } from '@reactflow/utils';
|
||||
import { clampPosition, getDimensions, fitView } from '@reactflow/utils';
|
||||
import {
|
||||
internalsSymbol,
|
||||
type ReactFlowState,
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
|
||||
import { applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
|
||||
import { getHandleBounds } from '../components/Nodes/utils';
|
||||
import { createNodeInternals, fitView, updateAbsoluteNodePositions, updateNodesAndEdgesSelections } from './utils';
|
||||
import { createNodeInternals, updateAbsoluteNodePositions, updateNodesAndEdgesSelections } from './utils';
|
||||
import initialState from './initialState';
|
||||
|
||||
const createRFStore = () =>
|
||||
@@ -57,6 +57,12 @@ const createRFStore = () =>
|
||||
fitViewOnInitOptions,
|
||||
domNode,
|
||||
nodeOrigin,
|
||||
width,
|
||||
height,
|
||||
minZoom,
|
||||
maxZoom,
|
||||
d3Selection,
|
||||
d3Zoom,
|
||||
} = get();
|
||||
const viewportNode = domNode?.querySelector('.react-flow__viewport');
|
||||
|
||||
@@ -106,7 +112,23 @@ const createRFStore = () =>
|
||||
|
||||
const nextFitViewOnInitDone =
|
||||
fitViewOnInitDone ||
|
||||
(fitViewOnInit && !fitViewOnInitDone && fitView(get, { initial: true, ...fitViewOnInitOptions }));
|
||||
(fitViewOnInit &&
|
||||
!fitViewOnInitDone &&
|
||||
!!d3Zoom &&
|
||||
!!d3Selection &&
|
||||
fitView(
|
||||
{
|
||||
nodes: Array.from(nodeInternals.values()),
|
||||
width,
|
||||
height,
|
||||
d3Zoom,
|
||||
d3Selection,
|
||||
minZoom,
|
||||
maxZoom,
|
||||
nodeOrigin,
|
||||
},
|
||||
fitViewOnInitOptions
|
||||
));
|
||||
set({ nodeInternals: new Map(nodeInternals), fitViewOnInitDone: nextFitViewOnInitDone });
|
||||
|
||||
if (changes?.length > 0) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { zoomIdentity } from 'd3-zoom';
|
||||
import type { StoreApi } from 'zustand';
|
||||
import {
|
||||
internalsSymbol,
|
||||
@@ -9,16 +8,9 @@ import {
|
||||
type NodeSelectionChange,
|
||||
type ReactFlowState,
|
||||
type XYZPosition,
|
||||
type FitViewOptions,
|
||||
type NodeOrigin,
|
||||
} from '@reactflow/system';
|
||||
import {
|
||||
isNumeric,
|
||||
getD3Transition,
|
||||
getRectOfNodes,
|
||||
getTransformForBounds,
|
||||
getNodePositionWithOrigin,
|
||||
} from '@reactflow/utils';
|
||||
import { isNumeric, getNodePositionWithOrigin } from '@reactflow/utils';
|
||||
|
||||
type ParentNodes = Record<string, boolean>;
|
||||
|
||||
@@ -126,66 +118,6 @@ export function createNodeInternals(
|
||||
return nextNodeInternals;
|
||||
}
|
||||
|
||||
type InternalFitViewOptions = {
|
||||
initial?: boolean;
|
||||
} & FitViewOptions;
|
||||
|
||||
export function fitView(get: StoreApi<ReactFlowState>['getState'], options: InternalFitViewOptions = {}) {
|
||||
const {
|
||||
getNodes,
|
||||
width,
|
||||
height,
|
||||
minZoom,
|
||||
maxZoom,
|
||||
d3Zoom,
|
||||
d3Selection,
|
||||
fitViewOnInitDone,
|
||||
fitViewOnInit,
|
||||
nodeOrigin,
|
||||
} = get();
|
||||
const isInitialFitView = options.initial && !fitViewOnInitDone && fitViewOnInit;
|
||||
const d3initialized = d3Zoom && d3Selection;
|
||||
|
||||
if (d3initialized && (isInitialFitView || !options.initial)) {
|
||||
const nodes = getNodes().filter((n) => {
|
||||
const isVisible = options.includeHiddenNodes ? n.width && n.height : !n.hidden;
|
||||
|
||||
if (options.nodes?.length) {
|
||||
return isVisible && options.nodes.some((optionNode) => optionNode.id === n.id);
|
||||
}
|
||||
|
||||
return isVisible;
|
||||
});
|
||||
|
||||
const nodesInitialized = nodes.every((n) => n.width && n.height);
|
||||
|
||||
if (nodes.length > 0 && nodesInitialized) {
|
||||
const bounds = getRectOfNodes(nodes, nodeOrigin);
|
||||
|
||||
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 false;
|
||||
}
|
||||
|
||||
export function handleControlledNodeSelectionChange(nodeChanges: NodeSelectionChange[], nodeInternals: NodeInternals) {
|
||||
nodeChanges.forEach((change) => {
|
||||
const node = nodeInternals.get(change.id);
|
||||
|
||||
Reference in New Issue
Block a user