From 0f62a3d07a48862339fb7e20ccdef64724164a7a Mon Sep 17 00:00:00 2001 From: moklick Date: Sun, 19 Feb 2023 16:15:26 +0100 Subject: [PATCH] package(core): use system fitView --- packages/core/src/hooks/useViewportHelper.ts | 26 +++++++- packages/core/src/store/index.ts | 28 +++++++- packages/core/src/store/utils.ts | 70 +------------------- 3 files changed, 49 insertions(+), 75 deletions(-) diff --git a/packages/core/src/hooks/useViewportHelper.ts b/packages/core/src/hooks/useViewportHelper.ts index 10e2b677..324cb945 100644 --- a/packages/core/src/hooks/useViewportHelper.ts +++ b/packages/core/src/hooks/useViewportHelper.ts @@ -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; diff --git a/packages/core/src/store/index.ts b/packages/core/src/store/index.ts index c6f3dff9..972ba9e8 100644 --- a/packages/core/src/store/index.ts +++ b/packages/core/src/store/index.ts @@ -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) { diff --git a/packages/core/src/store/utils.ts b/packages/core/src/store/utils.ts index d55f8a39..de21c644 100644 --- a/packages/core/src/store/utils.ts +++ b/packages/core/src/store/utils.ts @@ -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; @@ -126,66 +118,6 @@ export function createNodeInternals( return nextNodeInternals; } -type InternalFitViewOptions = { - initial?: boolean; -} & FitViewOptions; - -export function fitView(get: StoreApi['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);