From fdf2571402179acd73d060c4e44b659f8c6d7f89 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 4 Nov 2021 21:43:47 +0100 Subject: [PATCH] feat(nodes): add extent option --- example/src/Basic/index.tsx | 1 + example/src/Layouting/index.tsx | 4 ++-- src/components/StoreUpdater/index.tsx | 7 +++---- src/container/ReactFlow/index.tsx | 7 +++---- src/store/index.ts | 26 +++++++++++++++++++------- src/types/index.ts | 12 ++++++------ src/utils/index.ts | 4 ++-- 7 files changed, 36 insertions(+), 25 deletions(-) diff --git a/example/src/Basic/index.tsx b/example/src/Basic/index.tsx index 0e53b216..75069deb 100644 --- a/example/src/Basic/index.tsx +++ b/example/src/Basic/index.tsx @@ -36,6 +36,7 @@ const initialNodes: Node[] = [ position: { x: 15, y: 15 }, className: 'light', parentNode: '4', + extent: 'parent', }, { id: '4b', diff --git a/example/src/Layouting/index.tsx b/example/src/Layouting/index.tsx index cbae1310..56484640 100644 --- a/example/src/Layouting/index.tsx +++ b/example/src/Layouting/index.tsx @@ -10,7 +10,7 @@ import ReactFlow, { Node, Connection, Edge, - NodeExtent, + CoordinateExtent, Position, } from 'react-flow-renderer'; import dagre from 'dagre'; @@ -22,7 +22,7 @@ import './layouting.css'; const dagreGraph = new dagre.graphlib.Graph(); dagreGraph.setDefaultEdgeLabel(() => ({})); -const nodeExtent: NodeExtent = [ +const nodeExtent: CoordinateExtent = [ [0, 0], [1000, 1000], ]; diff --git a/src/components/StoreUpdater/index.tsx b/src/components/StoreUpdater/index.tsx index 235b7b08..33593e4d 100644 --- a/src/components/StoreUpdater/index.tsx +++ b/src/components/StoreUpdater/index.tsx @@ -10,12 +10,11 @@ import { OnConnectStartFunc, OnConnectStopFunc, OnConnectEndFunc, - NodeExtent, + CoordinateExtent, OnNodesChange, OnEdgesChange, ConnectionMode, SnapGrid, - TranslateExtent, } from '../../types'; interface StoreUpdaterProps { @@ -29,14 +28,14 @@ interface StoreUpdaterProps { nodesConnectable?: boolean; minZoom?: number; maxZoom?: number; - nodeExtent?: NodeExtent; + nodeExtent?: CoordinateExtent; onNodesChange?: OnNodesChange; onEdgesChange?: OnEdgesChange; elementsSelectable?: boolean; connectionMode?: ConnectionMode; snapToGrid?: boolean; snapGrid?: SnapGrid; - translateExtent?: TranslateExtent; + translateExtent?: CoordinateExtent; } const selector = (s: ReactFlowState) => ({ diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx index c9c184cb..9f266fb7 100644 --- a/src/container/ReactFlow/index.tsx +++ b/src/container/ReactFlow/index.tsx @@ -33,11 +33,10 @@ import { OnConnectStopFunc, OnConnectEndFunc, OnConnectFunc, - TranslateExtent, + CoordinateExtent, KeyCode, PanOnScrollMode, OnEdgeUpdateFunc, - NodeExtent, NodeChange, EdgeChange, } from '../../types'; @@ -111,9 +110,9 @@ export interface ReactFlowProps extends Omit, 'on maxZoom?: number; defaultZoom?: number; defaultPosition?: [number, number]; - translateExtent?: TranslateExtent; + translateExtent?: CoordinateExtent; preventScrolling?: boolean; - nodeExtent?: NodeExtent; + nodeExtent?: CoordinateExtent; defaultMarkerColor?: string; zoomOnScroll?: boolean; zoomOnPinch?: boolean; diff --git a/src/store/index.ts b/src/store/index.ts index b6c3cba0..570d3c3e 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -11,8 +11,7 @@ import { NodeDiffUpdate, XYPosition, InitD3ZoomPayload, - TranslateExtent, - NodeExtent, + CoordinateExtent, Transform, Dimensions, OnConnectFunc, @@ -143,7 +142,7 @@ const createStore = () => onNodesChange?.(nodesToChange); }, updateNodePosition: ({ id, diff, isDragging }: NodeDiffUpdate) => { - const { onNodesChange, nodes, nodeExtent } = get(); + const { onNodesChange, nodes, nodeExtent, nodeInternals } = get(); if (onNodesChange) { const matchingNodes = nodes.filter((n) => !!(n.isSelected || n.id === id)); @@ -158,13 +157,26 @@ const createStore = () => }; if (diff) { - change.position = nodeExtent + let currentExtent = nodeExtent || node.extent; + + if (node.extent === 'parent' && node.parentNode && node.width && node.height) { + const parent = nodeInternals.get(node.parentNode); + currentExtent = + parent?.width && parent?.height + ? [ + [0, 0], + [parent.width - node.width, parent.height - node.height], + ] + : currentExtent; + } + + change.position = currentExtent ? clampPosition( { x: node.position.x + diff.x, y: node.position.y + diff.y, }, - nodeExtent + currentExtent ) : { x: node.position.x + diff.x, y: node.position.y + diff.y }; } @@ -300,7 +312,7 @@ const createStore = () => set({ maxZoom }); }, - setTranslateExtent: (translateExtent: TranslateExtent) => { + setTranslateExtent: (translateExtent: CoordinateExtent) => { const { d3Zoom } = get(); d3Zoom?.translateExtent(translateExtent); @@ -320,7 +332,7 @@ const createStore = () => onEdgesChange?.(edgesToUnselect as EdgeChange[]); } }, - setNodeExtent: (nodeExtent: NodeExtent) => + setNodeExtent: (nodeExtent: CoordinateExtent) => set({ nodeExtent, nodes: get().nodes.map((node) => { diff --git a/src/types/index.ts b/src/types/index.ts index 02cf3d43..f8403993 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -84,6 +84,7 @@ export interface Node { height?: number | null; parentNode?: ElementId; zIndex?: number; + extent?: 'parent' | CoordinateExtent; } export enum ArrowHeadType { @@ -416,8 +417,7 @@ export type FlowTransform = { zoom: number; }; -export type TranslateExtent = [[number, number], [number, number]]; -export type NodeExtent = TranslateExtent; +export type CoordinateExtent = [[number, number], [number, number]]; export type KeyCode = string | Array; @@ -486,8 +486,8 @@ export interface ReactFlowState { d3ZoomHandler: ((this: Element, event: any, d: unknown) => void) | undefined; minZoom: number; maxZoom: number; - translateExtent: TranslateExtent; - nodeExtent: NodeExtent; + translateExtent: CoordinateExtent; + nodeExtent: CoordinateExtent; nodesSelectionActive: boolean; selectionActive: boolean; @@ -527,8 +527,8 @@ export interface ReactFlowState { initD3Zoom: (payload: InitD3ZoomPayload) => void; setMinZoom: (minZoom: number) => void; setMaxZoom: (maxZoom: number) => void; - setTranslateExtent: (translateExtent: TranslateExtent) => void; - setNodeExtent: (nodeExtent: NodeExtent) => void; + setTranslateExtent: (translateExtent: CoordinateExtent) => void; + setNodeExtent: (nodeExtent: CoordinateExtent) => void; setOnConnect: (onConnectFunction: OnConnectFunc) => void; setOnConnectStart: (onConnectFunction: OnConnectStartFunc) => void; setOnConnectStop: (onConnectFunction: OnConnectStopFunc) => void; diff --git a/src/utils/index.ts b/src/utils/index.ts index ec44298a..084f5beb 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,4 @@ -import { Dimensions, XYPosition, NodeExtent, Box, Rect } from '../types'; +import { Dimensions, XYPosition, CoordinateExtent, Box, Rect } from '../types'; export const getDimensions = (node: HTMLDivElement): Dimensions => ({ width: node.offsetWidth, @@ -7,7 +7,7 @@ export const getDimensions = (node: HTMLDivElement): Dimensions => ({ export const clamp = (val: number, min: number = 0, max: number = 1): number => Math.min(Math.max(val, min), max); -export const clampPosition = (position: XYPosition, extent: NodeExtent) => ({ +export const clampPosition = (position: XYPosition, extent: CoordinateExtent) => ({ x: clamp(position.x, extent[0][0], extent[1][0]), y: clamp(position.y, extent[0][1], extent[1][1]), });