feat(nodes): add extent option
This commit is contained in:
@@ -36,6 +36,7 @@ const initialNodes: Node[] = [
|
|||||||
position: { x: 15, y: 15 },
|
position: { x: 15, y: 15 },
|
||||||
className: 'light',
|
className: 'light',
|
||||||
parentNode: '4',
|
parentNode: '4',
|
||||||
|
extent: 'parent',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '4b',
|
id: '4b',
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import ReactFlow, {
|
|||||||
Node,
|
Node,
|
||||||
Connection,
|
Connection,
|
||||||
Edge,
|
Edge,
|
||||||
NodeExtent,
|
CoordinateExtent,
|
||||||
Position,
|
Position,
|
||||||
} from 'react-flow-renderer';
|
} from 'react-flow-renderer';
|
||||||
import dagre from 'dagre';
|
import dagre from 'dagre';
|
||||||
@@ -22,7 +22,7 @@ import './layouting.css';
|
|||||||
const dagreGraph = new dagre.graphlib.Graph();
|
const dagreGraph = new dagre.graphlib.Graph();
|
||||||
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
||||||
|
|
||||||
const nodeExtent: NodeExtent = [
|
const nodeExtent: CoordinateExtent = [
|
||||||
[0, 0],
|
[0, 0],
|
||||||
[1000, 1000],
|
[1000, 1000],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -10,12 +10,11 @@ import {
|
|||||||
OnConnectStartFunc,
|
OnConnectStartFunc,
|
||||||
OnConnectStopFunc,
|
OnConnectStopFunc,
|
||||||
OnConnectEndFunc,
|
OnConnectEndFunc,
|
||||||
NodeExtent,
|
CoordinateExtent,
|
||||||
OnNodesChange,
|
OnNodesChange,
|
||||||
OnEdgesChange,
|
OnEdgesChange,
|
||||||
ConnectionMode,
|
ConnectionMode,
|
||||||
SnapGrid,
|
SnapGrid,
|
||||||
TranslateExtent,
|
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
interface StoreUpdaterProps {
|
interface StoreUpdaterProps {
|
||||||
@@ -29,14 +28,14 @@ interface StoreUpdaterProps {
|
|||||||
nodesConnectable?: boolean;
|
nodesConnectable?: boolean;
|
||||||
minZoom?: number;
|
minZoom?: number;
|
||||||
maxZoom?: number;
|
maxZoom?: number;
|
||||||
nodeExtent?: NodeExtent;
|
nodeExtent?: CoordinateExtent;
|
||||||
onNodesChange?: OnNodesChange;
|
onNodesChange?: OnNodesChange;
|
||||||
onEdgesChange?: OnEdgesChange;
|
onEdgesChange?: OnEdgesChange;
|
||||||
elementsSelectable?: boolean;
|
elementsSelectable?: boolean;
|
||||||
connectionMode?: ConnectionMode;
|
connectionMode?: ConnectionMode;
|
||||||
snapToGrid?: boolean;
|
snapToGrid?: boolean;
|
||||||
snapGrid?: SnapGrid;
|
snapGrid?: SnapGrid;
|
||||||
translateExtent?: TranslateExtent;
|
translateExtent?: CoordinateExtent;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selector = (s: ReactFlowState) => ({
|
const selector = (s: ReactFlowState) => ({
|
||||||
|
|||||||
@@ -33,11 +33,10 @@ import {
|
|||||||
OnConnectStopFunc,
|
OnConnectStopFunc,
|
||||||
OnConnectEndFunc,
|
OnConnectEndFunc,
|
||||||
OnConnectFunc,
|
OnConnectFunc,
|
||||||
TranslateExtent,
|
CoordinateExtent,
|
||||||
KeyCode,
|
KeyCode,
|
||||||
PanOnScrollMode,
|
PanOnScrollMode,
|
||||||
OnEdgeUpdateFunc,
|
OnEdgeUpdateFunc,
|
||||||
NodeExtent,
|
|
||||||
NodeChange,
|
NodeChange,
|
||||||
EdgeChange,
|
EdgeChange,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
@@ -111,9 +110,9 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
|||||||
maxZoom?: number;
|
maxZoom?: number;
|
||||||
defaultZoom?: number;
|
defaultZoom?: number;
|
||||||
defaultPosition?: [number, number];
|
defaultPosition?: [number, number];
|
||||||
translateExtent?: TranslateExtent;
|
translateExtent?: CoordinateExtent;
|
||||||
preventScrolling?: boolean;
|
preventScrolling?: boolean;
|
||||||
nodeExtent?: NodeExtent;
|
nodeExtent?: CoordinateExtent;
|
||||||
defaultMarkerColor?: string;
|
defaultMarkerColor?: string;
|
||||||
zoomOnScroll?: boolean;
|
zoomOnScroll?: boolean;
|
||||||
zoomOnPinch?: boolean;
|
zoomOnPinch?: boolean;
|
||||||
|
|||||||
+19
-7
@@ -11,8 +11,7 @@ import {
|
|||||||
NodeDiffUpdate,
|
NodeDiffUpdate,
|
||||||
XYPosition,
|
XYPosition,
|
||||||
InitD3ZoomPayload,
|
InitD3ZoomPayload,
|
||||||
TranslateExtent,
|
CoordinateExtent,
|
||||||
NodeExtent,
|
|
||||||
Transform,
|
Transform,
|
||||||
Dimensions,
|
Dimensions,
|
||||||
OnConnectFunc,
|
OnConnectFunc,
|
||||||
@@ -143,7 +142,7 @@ const createStore = () =>
|
|||||||
onNodesChange?.(nodesToChange);
|
onNodesChange?.(nodesToChange);
|
||||||
},
|
},
|
||||||
updateNodePosition: ({ id, diff, isDragging }: NodeDiffUpdate) => {
|
updateNodePosition: ({ id, diff, isDragging }: NodeDiffUpdate) => {
|
||||||
const { onNodesChange, nodes, nodeExtent } = get();
|
const { onNodesChange, nodes, nodeExtent, nodeInternals } = get();
|
||||||
|
|
||||||
if (onNodesChange) {
|
if (onNodesChange) {
|
||||||
const matchingNodes = nodes.filter((n) => !!(n.isSelected || n.id === id));
|
const matchingNodes = nodes.filter((n) => !!(n.isSelected || n.id === id));
|
||||||
@@ -158,13 +157,26 @@ const createStore = () =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (diff) {
|
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(
|
? clampPosition(
|
||||||
{
|
{
|
||||||
x: node.position.x + diff.x,
|
x: node.position.x + diff.x,
|
||||||
y: node.position.y + diff.y,
|
y: node.position.y + diff.y,
|
||||||
},
|
},
|
||||||
nodeExtent
|
currentExtent
|
||||||
)
|
)
|
||||||
: { x: node.position.x + diff.x, y: node.position.y + diff.y };
|
: { x: node.position.x + diff.x, y: node.position.y + diff.y };
|
||||||
}
|
}
|
||||||
@@ -300,7 +312,7 @@ const createStore = () =>
|
|||||||
|
|
||||||
set({ maxZoom });
|
set({ maxZoom });
|
||||||
},
|
},
|
||||||
setTranslateExtent: (translateExtent: TranslateExtent) => {
|
setTranslateExtent: (translateExtent: CoordinateExtent) => {
|
||||||
const { d3Zoom } = get();
|
const { d3Zoom } = get();
|
||||||
d3Zoom?.translateExtent(translateExtent);
|
d3Zoom?.translateExtent(translateExtent);
|
||||||
|
|
||||||
@@ -320,7 +332,7 @@ const createStore = () =>
|
|||||||
onEdgesChange?.(edgesToUnselect as EdgeChange[]);
|
onEdgesChange?.(edgesToUnselect as EdgeChange[]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setNodeExtent: (nodeExtent: NodeExtent) =>
|
setNodeExtent: (nodeExtent: CoordinateExtent) =>
|
||||||
set({
|
set({
|
||||||
nodeExtent,
|
nodeExtent,
|
||||||
nodes: get().nodes.map((node) => {
|
nodes: get().nodes.map((node) => {
|
||||||
|
|||||||
+6
-6
@@ -84,6 +84,7 @@ export interface Node<T = any> {
|
|||||||
height?: number | null;
|
height?: number | null;
|
||||||
parentNode?: ElementId;
|
parentNode?: ElementId;
|
||||||
zIndex?: number;
|
zIndex?: number;
|
||||||
|
extent?: 'parent' | CoordinateExtent;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ArrowHeadType {
|
export enum ArrowHeadType {
|
||||||
@@ -416,8 +417,7 @@ export type FlowTransform = {
|
|||||||
zoom: number;
|
zoom: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TranslateExtent = [[number, number], [number, number]];
|
export type CoordinateExtent = [[number, number], [number, number]];
|
||||||
export type NodeExtent = TranslateExtent;
|
|
||||||
|
|
||||||
export type KeyCode = string | Array<string>;
|
export type KeyCode = string | Array<string>;
|
||||||
|
|
||||||
@@ -486,8 +486,8 @@ export interface ReactFlowState {
|
|||||||
d3ZoomHandler: ((this: Element, event: any, d: unknown) => void) | undefined;
|
d3ZoomHandler: ((this: Element, event: any, d: unknown) => void) | undefined;
|
||||||
minZoom: number;
|
minZoom: number;
|
||||||
maxZoom: number;
|
maxZoom: number;
|
||||||
translateExtent: TranslateExtent;
|
translateExtent: CoordinateExtent;
|
||||||
nodeExtent: NodeExtent;
|
nodeExtent: CoordinateExtent;
|
||||||
|
|
||||||
nodesSelectionActive: boolean;
|
nodesSelectionActive: boolean;
|
||||||
selectionActive: boolean;
|
selectionActive: boolean;
|
||||||
@@ -527,8 +527,8 @@ export interface ReactFlowState {
|
|||||||
initD3Zoom: (payload: InitD3ZoomPayload) => void;
|
initD3Zoom: (payload: InitD3ZoomPayload) => void;
|
||||||
setMinZoom: (minZoom: number) => void;
|
setMinZoom: (minZoom: number) => void;
|
||||||
setMaxZoom: (maxZoom: number) => void;
|
setMaxZoom: (maxZoom: number) => void;
|
||||||
setTranslateExtent: (translateExtent: TranslateExtent) => void;
|
setTranslateExtent: (translateExtent: CoordinateExtent) => void;
|
||||||
setNodeExtent: (nodeExtent: NodeExtent) => void;
|
setNodeExtent: (nodeExtent: CoordinateExtent) => void;
|
||||||
setOnConnect: (onConnectFunction: OnConnectFunc) => void;
|
setOnConnect: (onConnectFunction: OnConnectFunc) => void;
|
||||||
setOnConnectStart: (onConnectFunction: OnConnectStartFunc) => void;
|
setOnConnectStart: (onConnectFunction: OnConnectStartFunc) => void;
|
||||||
setOnConnectStop: (onConnectFunction: OnConnectStopFunc) => 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 => ({
|
export const getDimensions = (node: HTMLDivElement): Dimensions => ({
|
||||||
width: node.offsetWidth,
|
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 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]),
|
x: clamp(position.x, extent[0][0], extent[1][0]),
|
||||||
y: clamp(position.y, extent[0][1], extent[1][1]),
|
y: clamp(position.y, extent[0][1], extent[1][1]),
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user