feat(nodes): add extent option
This commit is contained in:
@@ -36,6 +36,7 @@ const initialNodes: Node[] = [
|
||||
position: { x: 15, y: 15 },
|
||||
className: 'light',
|
||||
parentNode: '4',
|
||||
extent: 'parent',
|
||||
},
|
||||
{
|
||||
id: '4b',
|
||||
|
||||
@@ -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],
|
||||
];
|
||||
|
||||
@@ -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) => ({
|
||||
|
||||
@@ -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<HTMLAttributes<HTMLDivElement>, 'on
|
||||
maxZoom?: number;
|
||||
defaultZoom?: number;
|
||||
defaultPosition?: [number, number];
|
||||
translateExtent?: TranslateExtent;
|
||||
translateExtent?: CoordinateExtent;
|
||||
preventScrolling?: boolean;
|
||||
nodeExtent?: NodeExtent;
|
||||
nodeExtent?: CoordinateExtent;
|
||||
defaultMarkerColor?: string;
|
||||
zoomOnScroll?: boolean;
|
||||
zoomOnPinch?: boolean;
|
||||
|
||||
+19
-7
@@ -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) => {
|
||||
|
||||
+6
-6
@@ -84,6 +84,7 @@ export interface Node<T = any> {
|
||||
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<string>;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+2
-2
@@ -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]),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user