From 609f7ed79235662f071f53c5bb36ec99c232afab Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 27 Jun 2024 15:03:35 +0200 Subject: [PATCH] refactor(positions): remove unused node origins --- .../additional-components/MiniMap/MiniMap.tsx | 6 +- .../NodeToolbar/NodeToolbar.tsx | 55 +++++++++++-------- .../src/components/NodesSelection/index.tsx | 1 - .../src/container/FlowRenderer/index.tsx | 1 - packages/react/src/container/Pane/index.tsx | 5 +- packages/react/src/hooks/useViewportHelper.ts | 31 ++++++----- packages/react/src/store/index.ts | 3 +- packages/react/src/store/initialState.ts | 1 - packages/svelte/src/lib/store/index.ts | 3 +- packages/system/src/types/general.ts | 3 +- packages/system/src/utils/graph.ts | 22 +++----- packages/system/src/xydrag/XYDrag.ts | 2 +- 12 files changed, 64 insertions(+), 69 deletions(-) diff --git a/packages/react/src/additional-components/MiniMap/MiniMap.tsx b/packages/react/src/additional-components/MiniMap/MiniMap.tsx index 0a05890d..bd7d6634 100644 --- a/packages/react/src/additional-components/MiniMap/MiniMap.tsx +++ b/packages/react/src/additional-components/MiniMap/MiniMap.tsx @@ -25,12 +25,8 @@ const selector = (s: ReactFlowState) => { return { viewBB, - boundingRect: - s.nodeLookup.size > 0 - ? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup, { nodeOrigin: s.nodeOrigin }), viewBB) - : viewBB, + boundingRect: s.nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup), viewBB) : viewBB, rfId: s.rfId, - nodeOrigin: s.nodeOrigin, panZoom: s.panZoom, translateExtent: s.translateExtent, flowWidth: s.width, diff --git a/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx b/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx index f14f822e..b4431157 100644 --- a/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx +++ b/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx @@ -1,7 +1,7 @@ import { useCallback, CSSProperties } from 'react'; import cc from 'classcat'; import { shallow } from 'zustand/shallow'; -import { Rect, Position, getNodeToolbarTransform, getNodesBounds } from '@xyflow/system'; +import { Position, getNodeToolbarTransform, getInternalNodesBounds, NodeLookup } from '@xyflow/system'; import { InternalNode, ReactFlowState } from '../../types'; import { useStore } from '../../hooks/useStore'; @@ -17,21 +17,24 @@ const nodeEqualityFn = (a?: InternalNode, b?: InternalNode) => a?.selected !== b?.selected || a?.internals.z !== b?.internals.z; -const nodesEqualityFn = (a: InternalNode[], b: InternalNode[]) => { - if (a.length !== b.length) { +const nodesEqualityFn = (a: NodeLookup, b: NodeLookup) => { + if (a.size !== b.size) { return false; } - return !a.some((node, i) => nodeEqualityFn(node, b[i])); + for (const [key, node] of a) { + if (nodeEqualityFn(node, b.get(key))) { + return false; + } + } + + return true; }; const storeSelector = (state: ReactFlowState) => ({ - viewport: { - x: state.transform[0], - y: state.transform[1], - zoom: state.transform[2], - }, - nodeOrigin: state.nodeOrigin, + x: state.transform[0], + y: state.transform[1], + zoom: state.transform[2], selectedNodesCount: state.nodes.filter((node) => node.selected).length, }); @@ -49,36 +52,41 @@ export function NodeToolbar({ const contextNodeId = useNodeId(); const nodesSelector = useCallback( - (state: ReactFlowState): InternalNode[] => { + (state: ReactFlowState): NodeLookup => { const nodeIds = Array.isArray(nodeId) ? nodeId : [nodeId || contextNodeId || '']; - - return nodeIds.reduce((acc, id) => { + const internalNodes = nodeIds.reduce((res, id) => { const node = state.nodeLookup.get(id); if (node) { - acc.push(node); + res.set(node.id, node); } - return acc; - }, []); + + return res; + }, new Map()); + + return internalNodes; }, [nodeId, contextNodeId] ); const nodes = useStore(nodesSelector, nodesEqualityFn); - const { viewport, nodeOrigin, selectedNodesCount } = useStore(storeSelector, shallow); + const { x, y, zoom, selectedNodesCount } = useStore(storeSelector, shallow); // if isVisible is not set, we show the toolbar only if its node is selected and no other node is selected const isActive = - typeof isVisible === 'boolean' ? isVisible : nodes.length === 1 && nodes[0].selected && selectedNodesCount === 1; + typeof isVisible === 'boolean' + ? isVisible + : nodes.size === 1 && nodes.values().next().value.selected && selectedNodesCount === 1; - if (!isActive || !nodes.length) { + if (!isActive || !nodes.size) { return null; } - const nodeRect: Rect = getNodesBounds(nodes, { nodeOrigin }); - const zIndex: number = Math.max(...nodes.map((node) => node.internals.z + 1)); + const nodeRect = getInternalNodesBounds(nodes); + const nodesArray = Array.from(nodes.values()); + const zIndex = Math.max(...nodesArray.map((node) => node.internals.z + 1)); const wrapperStyle: CSSProperties = { position: 'absolute', - transform: getNodeToolbarTransform(nodeRect, viewport, position, offset, align), + transform: getNodeToolbarTransform(nodeRect, { x, y, zoom }, position, offset, align), zIndex, ...style, }; @@ -89,7 +97,8 @@ export function NodeToolbar({ style={wrapperStyle} className={cc(['react-flow__node-toolbar', className])} {...rest} - data-id={nodes.reduce((acc, node) => `${acc}${node.id} `, '').trim()} + // @todo: check if we could only do this for non-prod envs + data-id={nodesArray.reduce((acc, node) => `${acc}${node.id} `, '').trim()} > {children} diff --git a/packages/react/src/components/NodesSelection/index.tsx b/packages/react/src/components/NodesSelection/index.tsx index fda3a8c9..e2bcd238 100644 --- a/packages/react/src/components/NodesSelection/index.tsx +++ b/packages/react/src/components/NodesSelection/index.tsx @@ -21,7 +21,6 @@ export type NodesSelectionProps = { const selector = (s: ReactFlowState) => { const { width, height, x, y } = getInternalNodesBounds(s.nodeLookup, { - nodeOrigin: s.nodeOrigin, filter: (node) => !!node.selected, }); diff --git a/packages/react/src/container/FlowRenderer/index.tsx b/packages/react/src/container/FlowRenderer/index.tsx index 30d17979..f3e0a23d 100644 --- a/packages/react/src/container/FlowRenderer/index.tsx +++ b/packages/react/src/container/FlowRenderer/index.tsx @@ -22,7 +22,6 @@ export type FlowRendererProps = Omit< | 'selectNodesOnDrag' | 'defaultMarkerColor' | 'rfId' - | 'nodeOrigin' > & { isControlledViewport: boolean; children: ReactNode; diff --git a/packages/react/src/container/Pane/index.tsx b/packages/react/src/container/Pane/index.tsx index d0661307..3a623372 100644 --- a/packages/react/src/container/Pane/index.tsx +++ b/packages/react/src/container/Pane/index.tsx @@ -155,7 +155,7 @@ export function Pane({ }; const onPointerMove = (event: ReactPointerEvent): void => { - const { userSelectionRect, edgeLookup, transform, nodeOrigin, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = + const { userSelectionRect, edgeLookup, transform, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = store.getState(); if (!containerBounds.current || !userSelectionRect) { @@ -181,8 +181,7 @@ export function Pane({ nextUserSelectRect, transform, selectionMode === SelectionMode.Partial, - true, - nodeOrigin + true ); const selectedEdgeIds = new Set(); diff --git a/packages/react/src/hooks/useViewportHelper.ts b/packages/react/src/hooks/useViewportHelper.ts index ef4f6f38..245fafd7 100644 --- a/packages/react/src/hooks/useViewportHelper.ts +++ b/packages/react/src/hooks/useViewportHelper.ts @@ -45,22 +45,23 @@ const useViewportHelper = (): ViewportHelperFunctions => { return { x, y, zoom }; }, fitView: (options) => { - const { nodeLookup, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store.getState(); + const { nodeLookup, width, height, minZoom, maxZoom, panZoom } = store.getState(); - return panZoom - ? fitView( - { - nodeLookup, - width, - height, - nodeOrigin, - minZoom, - maxZoom, - panZoom, - }, - options - ) - : false; + if (!panZoom) { + return false; + } + + return fitView( + { + nodeLookup, + width, + height, + minZoom, + maxZoom, + panZoom, + }, + options + ); }, setCenter: (x, y, options) => { const { width, height, maxZoom, panZoom } = store.getState(); diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 02930758..31e2ed21 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -288,7 +288,7 @@ const createStore = ({ return panBySystem({ delta, panZoom, transform, translateExtent, width, height }); }, fitView: (options?: FitViewOptions): boolean => { - const { panZoom, width, height, minZoom, maxZoom, nodeOrigin, nodeLookup } = get(); + const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get(); if (!panZoom) { return false; @@ -302,7 +302,6 @@ const createStore = ({ panZoom, minZoom, maxZoom, - nodeOrigin, }, options ); diff --git a/packages/react/src/store/initialState.ts b/packages/react/src/store/initialState.ts index d519665f..d80706a4 100644 --- a/packages/react/src/store/initialState.ts +++ b/packages/react/src/store/initialState.ts @@ -46,7 +46,6 @@ const getInitialState = ({ if (fitView && width && height) { // @todo users nodeOrigin should be used here const bounds = getInternalNodesBounds(nodeLookup, { - nodeOrigin: [0, 0], filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)), }); const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1); diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts index 8dc92b5c..fc8ba6b2 100644 --- a/packages/svelte/src/lib/store/index.ts +++ b/packages/svelte/src/lib/store/index.ts @@ -148,8 +148,7 @@ export function createStore({ height: get(store.height), minZoom: get(store.minZoom), maxZoom: get(store.maxZoom), - panZoom, - nodeOrigin: get(store.nodeOrigin) + panZoom }, options ); diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index ccaa8719..5d2bb390 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -7,7 +7,7 @@ import type { ZoomBehavior } from 'd3-zoom'; import type { Transition } from 'd3-transition'; import type { XYPosition, Rect } from './utils'; -import type { InternalNodeBase, NodeBase, NodeDragItem, NodeOrigin } from './nodes'; +import type { InternalNodeBase, NodeBase, NodeDragItem } from './nodes'; import type { ConnectingHandle, HandleType } from './handles'; import { PanZoomInstance } from './panzoom'; import { EdgeBase } from '..'; @@ -63,7 +63,6 @@ export type FitViewParamsBase = { panZoom: PanZoomInstance; minZoom: number; maxZoom: number; - nodeOrigin?: NodeOrigin; }; export type FitViewOptionsBase = { diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index b42580b1..3bf34784 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -147,7 +147,6 @@ export const getNodesBounds = (nodes: NodeBase[], params: GetNodesBoundsParams = }; export type GetInternalNodesBoundsParams = { - nodeOrigin?: NodeOrigin; useRelativePosition?: boolean; filter?: (node: NodeType) => boolean; }; @@ -158,9 +157,7 @@ export type GetInternalNodesBoundsParams = { */ export const getInternalNodesBounds = ( nodeLookup: Map, - params: GetInternalNodesBoundsParams = { - nodeOrigin: [0, 0], - } + params: GetInternalNodesBoundsParams = {} ): Rect => { if (nodeLookup.size === 0) { return { x: 0, y: 0, width: 0, height: 0 }; @@ -170,7 +167,7 @@ export const getInternalNodesBounds = { if (params.filter == undefined || params.filter(node)) { - const nodeBox = nodeToBox(node as InternalNodeBase, params.nodeOrigin); + const nodeBox = nodeToBox(node as InternalNodeBase); box = getBoundsOfBoxes(box, nodeBox); } }); @@ -184,8 +181,7 @@ export const getNodesInside = ( [tx, ty, tScale]: Transform = [0, 0, 1], partially = false, // set excludeNonSelectableNodes if you want to pay attention to the nodes "selectable" attribute - excludeNonSelectableNodes = false, - nodeOrigin: NodeOrigin = [0, 0] + excludeNonSelectableNodes = false ): InternalNodeBase[] => { const paneRect = { ...pointToRendererPoint(rect, [tx, ty, tScale]), @@ -204,7 +200,7 @@ export const getNodesInside = ( continue; } - const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node, nodeOrigin)); + const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node)); const notInitialized = width === null || height === null; const partiallyVisible = partially && overlappingArea > 0; @@ -238,22 +234,22 @@ export const getConnectedEdges = , Options extends FitViewOptionsBase>( - { nodeLookup, width, height, panZoom, minZoom, maxZoom, nodeOrigin = [0, 0] }: Params, + { nodeLookup, width, height, panZoom, minZoom, maxZoom }: Params, options?: Options ) { - const filteredNodes: InternalNodeBase[] = []; + const filteredNodes: Map = new Map(); const optionNodeIds = options?.nodes ? new Set(options.nodes.map((node) => node.id)) : null; nodeLookup.forEach((n) => { const isVisible = n.measured.width && n.measured.height && (options?.includeHiddenNodes || !n.hidden); if (isVisible && (!optionNodeIds || optionNodeIds.has(n.id))) { - filteredNodes.push(n); + filteredNodes.set(n.id, n); } }); - if (filteredNodes.length > 0) { - const bounds = getNodesBounds(filteredNodes, { nodeOrigin }); + if (filteredNodes.size > 0) { + const bounds = getInternalNodesBounds(filteredNodes); const viewport = getViewportForBounds( bounds, diff --git a/packages/system/src/xydrag/XYDrag.ts b/packages/system/src/xydrag/XYDrag.ts index 948865ca..0e89c1c6 100644 --- a/packages/system/src/xydrag/XYDrag.ts +++ b/packages/system/src/xydrag/XYDrag.ts @@ -124,7 +124,7 @@ export function XYDrag voi let nodesBox: Box = { x: 0, y: 0, x2: 0, y2: 0 }; if (dragItems.size > 1 && nodeExtent) { - const rect = getInternalNodesBounds(dragItems, { nodeOrigin }); + const rect = getInternalNodesBounds(dragItems); nodesBox = rectToBox(rect); }