chore(react): node origin cleanup

This commit is contained in:
moklick
2024-06-26 15:26:22 +02:00
parent c444eb380b
commit f968ff42ca
13 changed files with 33 additions and 71 deletions
@@ -128,7 +128,7 @@ const initialNodes: Node[] = [
data: { label: 'Parent', keepAspectRatio: true }, data: { label: 'Parent', keepAspectRatio: true },
position: { x: 700, y: 0 }, position: { x: 700, y: 0 },
width: 300, width: 300,
height: 400, height: 300,
style: { ...nodeStyle }, style: { ...nodeStyle },
}, },
{ {
@@ -148,7 +148,9 @@ const initialNodes: Node[] = [
id: '5b', id: '5b',
type: 'defaultResizer', type: 'defaultResizer',
data: { label: 'Child with expandParent' }, data: { label: 'Child with expandParent' },
position: { x: 150, y: 100 }, position: { x: 100, y: 100 },
width: 100,
height: 100,
parentId: '5', parentId: '5',
expandParent: true, expandParent: true,
style: { ...nodeStyle }, style: { ...nodeStyle },
@@ -187,7 +189,6 @@ const CustomNodeFlow = () => {
minZoom={0.2} minZoom={0.2}
maxZoom={5} maxZoom={5}
snapToGrid={snapToGrid} snapToGrid={snapToGrid}
nodeOrigin={[1, 1]}
fitView fitView
onlyRenderVisibleElements onlyRenderVisibleElements
> >
@@ -84,8 +84,8 @@ function ResizeControl({
height, height,
...evaluateAbsolutePosition( ...evaluateAbsolutePosition(
{ {
x: change.x ?? node.internals.positionAbsolute.x, x: change.x ?? node.position.x,
y: change.y ?? node.internals.positionAbsolute.y, y: change.y ?? node.position.y,
}, },
{ width, height }, { width, height },
node.parentId, node.parentId,
@@ -94,6 +94,7 @@ function ResizeControl({
), ),
}, },
}; };
console.log(child);
const parentExpandChanges = handleExpandParent([child], nodeLookup, parentLookup, nodeOrigin); const parentExpandChanges = handleExpandParent([child], nodeLookup, parentLookup, nodeOrigin);
changes.push(...parentExpandChanges); changes.push(...parentExpandChanges);
@@ -39,7 +39,6 @@ export function NodeWrapper<NodeType extends Node>({
rfId, rfId,
nodeTypes, nodeTypes,
nodeExtent, nodeExtent,
nodeOrigin,
onError, onError,
}: NodeWrapperProps<NodeType>) { }: NodeWrapperProps<NodeType>) {
const { node, internals, isParent } = useStore((s) => { const { node, internals, isParent } = useStore((s) => {
@@ -87,7 +86,9 @@ export function NodeWrapper<NodeType extends Node>({
const nodeDimensions = getNodeDimensions(node); const nodeDimensions = getNodeDimensions(node);
const inlineDimensions = getNodeInlineStyleDimensions(node); const inlineDimensions = getNodeInlineStyleDimensions(node);
// TODO: clamping should happen earlier // TODO: clamping should happen earlier
let clampedPosition = nodeExtent ? clampPosition(internals.positionAbsolute, nodeExtent) : internals.positionAbsolute; const clampedPosition = nodeExtent
? clampPosition(internals.positionAbsolute, nodeExtent)
: internals.positionAbsolute;
const hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave; const hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave;
@@ -32,7 +32,6 @@ export type GraphViewProps<NodeType extends Node = Node, EdgeType extends Edge =
| 'noPanClassName' | 'noPanClassName'
| 'defaultViewport' | 'defaultViewport'
| 'disableKeyboardA11y' | 'disableKeyboardA11y'
| 'nodeOrigin'
> >
> & { > & {
rfId: string; rfId: string;
@@ -97,7 +96,6 @@ function GraphViewComponent<NodeType extends Node = Node, EdgeType extends Edge
noWheelClassName, noWheelClassName,
noPanClassName, noPanClassName,
disableKeyboardA11y, disableKeyboardA11y,
nodeOrigin,
nodeExtent, nodeExtent,
rfId, rfId,
viewport, viewport,
@@ -186,7 +184,6 @@ function GraphViewComponent<NodeType extends Node = Node, EdgeType extends Edge
noPanClassName={noPanClassName} noPanClassName={noPanClassName}
noDragClassName={noDragClassName} noDragClassName={noDragClassName}
disableKeyboardA11y={disableKeyboardA11y} disableKeyboardA11y={disableKeyboardA11y}
nodeOrigin={nodeOrigin}
nodeExtent={nodeExtent} nodeExtent={nodeExtent}
rfId={rfId} rfId={rfId}
/> />
@@ -22,7 +22,6 @@ export type NodeRendererProps<NodeType extends Node> = Pick<
| 'noDragClassName' | 'noDragClassName'
| 'rfId' | 'rfId'
| 'disableKeyboardA11y' | 'disableKeyboardA11y'
| 'nodeOrigin'
| 'nodeExtent' | 'nodeExtent'
| 'nodeTypes' | 'nodeTypes'
>; >;
@@ -72,7 +71,6 @@ function NodeRendererComponent<NodeType extends Node>(props: NodeRendererProps<N
id={nodeId} id={nodeId}
nodeTypes={props.nodeTypes} nodeTypes={props.nodeTypes}
nodeExtent={props.nodeExtent} nodeExtent={props.nodeExtent}
nodeOrigin={props.nodeOrigin}
onClick={props.onNodeClick} onClick={props.onNodeClick}
onMouseEnter={props.onNodeMouseEnter} onMouseEnter={props.onNodeMouseEnter}
onMouseMove={props.onNodeMouseMove} onMouseMove={props.onNodeMouseMove}
@@ -217,7 +217,6 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
noPanClassName={noPanClassName} noPanClassName={noPanClassName}
rfId={rfId} rfId={rfId}
disableKeyboardA11y={disableKeyboardA11y} disableKeyboardA11y={disableKeyboardA11y}
nodeOrigin={nodeOrigin}
nodeExtent={nodeExtent} nodeExtent={nodeExtent}
viewport={viewport} viewport={viewport}
onViewportChange={onViewportChange} onViewportChange={onViewportChange}
+1 -9
View File
@@ -1,12 +1,5 @@
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react'; import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react';
import type { import type { CoordinateExtent, NodeBase, OnError, NodeProps as NodePropsBase, InternalNodeBase } from '@xyflow/system';
CoordinateExtent,
NodeBase,
NodeOrigin,
OnError,
NodeProps as NodePropsBase,
InternalNodeBase,
} from '@xyflow/system';
import { NodeTypes } from './general'; import { NodeTypes } from './general';
@@ -59,7 +52,6 @@ export type NodeWrapperProps<NodeType extends Node> = {
disableKeyboardA11y: boolean; disableKeyboardA11y: boolean;
nodeTypes?: NodeTypes; nodeTypes?: NodeTypes;
nodeExtent?: CoordinateExtent; nodeExtent?: CoordinateExtent;
nodeOrigin: NodeOrigin;
onError?: OnError; onError?: OnError;
}; };
+1 -1
View File
@@ -54,7 +54,7 @@ export type ReactFlowStore<NodeType extends Node = Node, EdgeType extends Edge =
transform: Transform; transform: Transform;
nodes: NodeType[]; nodes: NodeType[];
nodeLookup: NodeLookup<InternalNode<NodeType>>; nodeLookup: NodeLookup<InternalNode<NodeType>>;
parentLookup: Map<string, InternalNode<NodeType>[]>; parentLookup: Map<string, Map<string, InternalNode<NodeType>>>;
edges: Edge[]; edges: Edge[];
edgeLookup: EdgeLookup<EdgeType>; edgeLookup: EdgeLookup<EdgeType>;
connectionLookup: ConnectionLookup; connectionLookup: ConnectionLookup;
@@ -107,7 +107,7 @@ export const getInitialStore = ({
flowId: writable<string | null>(null), flowId: writable<string | null>(null),
nodes: createNodesStore(nodes, nodeLookup, parentLookup), nodes: createNodesStore(nodes, nodeLookup, parentLookup),
nodeLookup: readable<NodeLookup<InternalNode>>(nodeLookup), nodeLookup: readable<NodeLookup<InternalNode>>(nodeLookup),
parentLookup: readable<Map<string, InternalNode[]>>(parentLookup), parentLookup: readable<Map<string, Map<string, InternalNode>>>(parentLookup),
edgeLookup: readable<EdgeLookup<Edge>>(edgeLookup), edgeLookup: readable<EdgeLookup<Edge>>(edgeLookup),
visibleNodes: readable<InternalNode[]>([]), visibleNodes: readable<InternalNode[]>([]),
edges: createEdgesStore(edges, connectionLookup, edgeLookup), edges: createEdgesStore(edges, connectionLookup, edgeLookup),
+3 -2
View File
@@ -13,7 +13,8 @@ import {
type PanZoomInstance, type PanZoomInstance,
type ConnectionLookup, type ConnectionLookup,
type EdgeLookup, type EdgeLookup,
type NodeLookup type NodeLookup,
type ParentLookup
} from '@xyflow/system'; } from '@xyflow/system';
import type { DefaultEdgeOptions, DefaultNodeOptions, Edge, InternalNode, Node } from '$lib/types'; import type { DefaultEdgeOptions, DefaultNodeOptions, Edge, InternalNode, Node } from '$lib/types';
@@ -128,7 +129,7 @@ export type NodeStoreOptions = {
export const createNodesStore = ( export const createNodesStore = (
nodes: Node[], nodes: Node[],
nodeLookup: NodeLookup<InternalNode>, nodeLookup: NodeLookup<InternalNode>,
parentLookup: Map<string, InternalNode[]> parentLookup: ParentLookup<InternalNode>
): { ): {
subscribe: (this: void, run: Subscriber<Node[]>) => Unsubscriber; subscribe: (this: void, run: Subscriber<Node[]>) => Unsubscriber;
update: (this: void, updater: Updater<Node[]>) => void; update: (this: void, updater: Updater<Node[]>) => void;
+1 -1
View File
@@ -154,4 +154,4 @@ export type NodeHandle = Optional<HandleElement, 'width' | 'height'>;
export type Align = 'center' | 'start' | 'end'; export type Align = 'center' | 'start' | 'end';
export type NodeLookup<NodeType extends InternalNodeBase = InternalNodeBase> = Map<string, NodeType>; export type NodeLookup<NodeType extends InternalNodeBase = InternalNodeBase> = Map<string, NodeType>;
export type ParentLookup<NodeType extends InternalNodeBase = InternalNodeBase> = Map<string, NodeType[]>; export type ParentLookup<NodeType extends InternalNodeBase = InternalNodeBase> = Map<string, Map<string, NodeType>>;
+3 -28
View File
@@ -118,29 +118,6 @@ export const devWarn = (id: string, message: string) => {
} }
}; };
export const getPositionWithOrigin = ({
x,
y,
width,
height,
origin = [0, 0],
}: {
x: number;
y: number;
width: number;
height: number;
origin?: NodeOrigin;
}): XYPosition => {
if (!width || !height || origin[0] < 0 || origin[1] < 0 || origin[0] > 1 || origin[1] > 1) {
return { x, y };
}
return {
x: x - width * origin[0],
y: y - height * origin[1],
};
};
export const snapPosition = (position: XYPosition, snapGrid: SnapGrid = [1, 1]): XYPosition => { export const snapPosition = (position: XYPosition, snapGrid: SnapGrid = [1, 1]): XYPosition => {
return { return {
x: snapGrid[0] * Math.round(position.x / snapGrid[0]), x: snapGrid[0] * Math.round(position.x / snapGrid[0]),
@@ -243,7 +220,7 @@ export function nodeHasDimensions<NodeType extends NodeBase = NodeBase>(node: No
*/ */
export function evaluateAbsolutePosition( export function evaluateAbsolutePosition(
position: XYPosition, position: XYPosition,
dimensions: { width: number; height: number }, dimensions: { width?: number; height?: number } = { width: 0, height: 0 },
parentId: string, parentId: string,
nodeLookup: NodeLookup, nodeLookup: NodeLookup,
nodeOrigin: NodeOrigin nodeOrigin: NodeOrigin
@@ -257,10 +234,8 @@ export function evaluateAbsolutePosition(
if (parent) { if (parent) {
const origin = parent.origin || nodeOrigin; const origin = parent.origin || nodeOrigin;
const xOffset = (parent.measured.width ?? 0) * origin[0]; positionAbsolute.x += parent.internals.positionAbsolute.x - (dimensions.width ?? 0) * origin[0];
const yOffset = (parent.measured.height ?? 0) * origin[1]; positionAbsolute.y += parent.internals.positionAbsolute.y - (dimensions.height ?? 0) * origin[1];
positionAbsolute.x += parent.internals.positionAbsolute.x - dimensions.width * nodeOrigin[0];
positionAbsolute.y += parent.internals.positionAbsolute.y - dimensions.height * nodeOrigin[1];
} }
} }
+13 -16
View File
@@ -15,7 +15,6 @@ import {
NodeDimensionChange, NodeDimensionChange,
NodePositionChange, NodePositionChange,
ParentLookup, ParentLookup,
Dimensions,
} from '../types'; } from '../types';
import { getDimensions, getHandleBounds } from './dom'; import { getDimensions, getHandleBounds } from './dom';
import { getBoundsOfRects, getNodeDimensions, isNumeric, nodeToRect } from './general'; import { getBoundsOfRects, getNodeDimensions, isNumeric, nodeToRect } from './general';
@@ -23,8 +22,8 @@ import { getNodePositionWithOrigin } from './graph';
import { ParentExpandChild } from './types'; import { ParentExpandChild } from './types';
export function updateAbsolutePositions<NodeType extends NodeBase>( export function updateAbsolutePositions<NodeType extends NodeBase>(
nodeLookup: Map<string, InternalNodeBase<NodeType>>, nodeLookup: NodeLookup<InternalNodeBase<NodeType>>,
parentLookup: Map<string, InternalNodeBase<NodeType>[]>, parentLookup: ParentLookup<InternalNodeBase<NodeType>>,
options: UpdateNodesOptions<NodeType> = { options: UpdateNodesOptions<NodeType> = {
nodeOrigin: [0, 0] as NodeOrigin, nodeOrigin: [0, 0] as NodeOrigin,
elevateNodesOnSelect: true, elevateNodesOnSelect: true,
@@ -49,8 +48,8 @@ type UpdateNodesOptions<NodeType extends NodeBase> = {
export function adoptUserNodes<NodeType extends NodeBase>( export function adoptUserNodes<NodeType extends NodeBase>(
nodes: NodeType[], nodes: NodeType[],
nodeLookup: Map<string, InternalNodeBase<NodeType>>, nodeLookup: NodeLookup<InternalNodeBase<NodeType>>,
parentLookup: Map<string, InternalNodeBase<NodeType>[]>, parentLookup: ParentLookup<InternalNodeBase<NodeType>>,
options: UpdateNodesOptions<NodeType> = { options: UpdateNodesOptions<NodeType> = {
nodeOrigin: [0, 0] as NodeOrigin, nodeOrigin: [0, 0] as NodeOrigin,
elevateNodesOnSelect: true, elevateNodesOnSelect: true,
@@ -94,8 +93,8 @@ export function adoptUserNodes<NodeType extends NodeBase>(
function updateChildPosition<NodeType extends NodeBase>( function updateChildPosition<NodeType extends NodeBase>(
node: InternalNodeBase<NodeType>, node: InternalNodeBase<NodeType>,
nodeLookup: NodeLookup, nodeLookup: NodeLookup<InternalNodeBase<NodeType>>,
parentLookup: ParentLookup, parentLookup: ParentLookup<InternalNodeBase<NodeType>>,
options: UpdateNodesOptions<NodeType> = { options: UpdateNodesOptions<NodeType> = {
nodeOrigin: [0, 0] as NodeOrigin, nodeOrigin: [0, 0] as NodeOrigin,
elevateNodesOnSelect: true, elevateNodesOnSelect: true,
@@ -111,9 +110,9 @@ function updateChildPosition<NodeType extends NodeBase>(
// update the parentLookup // update the parentLookup
const childNodes = parentLookup.get(parentId); const childNodes = parentLookup.get(parentId);
if (childNodes) { if (childNodes) {
childNodes.push(node); childNodes.set(node.id, node);
} else { } else {
parentLookup.set(parentId, [node]); parentLookup.set(parentId, new Map([[node.id, node]]);
} }
const selectedNodeZ: number = options?.elevateNodesOnSelect ? 1000 : 0; const selectedNodeZ: number = options?.elevateNodesOnSelect ? 1000 : 0;
@@ -160,7 +159,7 @@ export function handleExpandParent(
): (NodeDimensionChange | NodePositionChange)[] { ): (NodeDimensionChange | NodePositionChange)[] {
const changes: (NodeDimensionChange | NodePositionChange)[] = []; const changes: (NodeDimensionChange | NodePositionChange)[] = [];
const parentExpansions = new Map<string, { expandedRect: Rect; parent: InternalNodeBase }>(); const parentExpansions = new Map<string, { expandedRect: Rect; parent: InternalNodeBase }>();
console.log(children)
// determine the expanded rectangle the child nodes would take for each parent // determine the expanded rectangle the child nodes would take for each parent
for (const child of children) { for (const child of children) {
const parent = nodeLookup.get(child.parentId); const parent = nodeLookup.get(child.parentId);
@@ -168,14 +167,13 @@ export function handleExpandParent(
continue; continue;
} }
const parentRect = const parentRect = parentExpansions.get(child.parentId)?.expandedRect ?? nodeToRect(parent);
parentExpansions.get(child.parentId)?.expandedRect ?? nodeToRect(parent, parent.origin ?? nodeOrigin);
const expandedRect = getBoundsOfRects(parentRect, child.rect); const expandedRect = getBoundsOfRects(parentRect, child.rect);
parentExpansions.set(child.parentId, { expandedRect, parent }); parentExpansions.set(child.parentId, { expandedRect, parent });
} }
if (parentExpansions.size > 0) { if (parentExpansions.size > 0) {
parentExpansions.forEach(({ expandedRect, parent }, parentId) => { parentExpansions.forEach(({ expandedRect, parent }, parentId) => {
// determine the position & dimensions of the parent // determine the position & dimensions of the parent
@@ -208,8 +206,7 @@ export function handleExpandParent(
// We move all child nodes in the oppsite direction // We move all child nodes in the oppsite direction
// so the x,y changes of the parent do not move the children // so the x,y changes of the parent do not move the children
const childNodes = parentLookup.get(parentId); parentLookup.get(parentId)?.forEach((childNode) => {
childNodes?.forEach((childNode) => {
if (!children.some((child) => child.id === childNode.id)) { if (!children.some((child) => child.id === childNode.id)) {
changes.push({ changes.push({
id: childNode.id, id: childNode.id,
@@ -295,7 +292,7 @@ export function updateNodeInternals<NodeType extends InternalNodeBase>(
}, },
}; };
if (node.parentId) { if (node.parentId) {
updateChildPosition(node, nodeLookup, parentLookup, { nodeOrigin }); updateChildPosition(node, nodeLookup, parentLookup, { nodeOrigin });
} }
updatedInternals = true; updatedInternals = true;