diff --git a/examples/vite-app/src/examples/Subflow/index.tsx b/examples/vite-app/src/examples/Subflow/index.tsx index 057e6b7b..397e4376 100644 --- a/examples/vite-app/src/examples/Subflow/index.tsx +++ b/examples/vite-app/src/examples/Subflow/index.tsx @@ -29,12 +29,14 @@ const initialNodes: Node[] = [ data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light', + origin: [0.5, 0.5], }, { id: '4', data: { label: 'Node 4' }, position: { x: 100, y: 200 }, className: 'light', + origin: [0.5, 0.5], style: { backgroundColor: 'rgba(255,50, 50, 0.5)', width: 500, @@ -47,6 +49,8 @@ const initialNodes: Node[] = [ position: { x: 15, y: 15 }, className: 'light', parentNode: '4', + origin: [0.5, 0.5], + extent: [ [0, 0], [100, 100], diff --git a/packages/core/src/container/NodeRenderer/index.tsx b/packages/core/src/container/NodeRenderer/index.tsx index 3c695737..aa8252de 100644 --- a/packages/core/src/container/NodeRenderer/index.tsx +++ b/packages/core/src/container/NodeRenderer/index.tsx @@ -97,7 +97,7 @@ const NodeRenderer = (props: NodeRendererProps) => { y: posY, width: node.width ?? 0, height: node.height ?? 0, - origin: props.nodeOrigin, + origin: node.origin || props.nodeOrigin, }); return ( diff --git a/packages/core/src/hooks/useDrag/utils.ts b/packages/core/src/hooks/useDrag/utils.ts index f2c297a4..1e6d7693 100644 --- a/packages/core/src/hooks/useDrag/utils.ts +++ b/packages/core/src/hooks/useDrag/utils.ts @@ -71,6 +71,7 @@ export function getDragItems( parentNode: n.parentNode, width: n.width, height: n.height, + origin: n.origin, })); } @@ -87,14 +88,15 @@ export function calcNextPosition( if (node.extent === 'parent') { if (node.parentNode && node.width && node.height) { const parent = nodeInternals.get(node.parentNode); - const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, nodeOrigin).positionAbsolute; + const parentOrigin = parent?.origin || nodeOrigin; + const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, parentOrigin).positionAbsolute; currentExtent = parent && isNumeric(parentX) && isNumeric(parentY) && isNumeric(parent.width) && isNumeric(parent.height) ? [ - [parentX + node.width * nodeOrigin[0], parentY + node.height * nodeOrigin[1]], + [parentX + node.width * parentOrigin[0], parentY + node.height * parentOrigin[1]], [ - parentX + parent.width - node.width + node.width * nodeOrigin[0], - parentY + parent.height - node.height + node.height * nodeOrigin[1], + parentX + parent.width - node.width + node.width * parentOrigin[0], + parentY + parent.height - node.height + node.height * parentOrigin[1], ], ] : currentExtent; @@ -105,7 +107,7 @@ export function calcNextPosition( } } else if (node.extent && node.parentNode) { const parent = nodeInternals.get(node.parentNode); - const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, nodeOrigin).positionAbsolute; + const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, parent?.origin || nodeOrigin).positionAbsolute; currentExtent = [ [node.extent[0][0] + parentX, node.extent[0][1] + parentY], [node.extent[1][0] + parentX, node.extent[1][1] + parentY], @@ -116,7 +118,7 @@ export function calcNextPosition( if (node.parentNode) { const parentNode = nodeInternals.get(node.parentNode); - parentPosition = getNodePositionWithOrigin(parentNode, nodeOrigin).positionAbsolute; + parentPosition = getNodePositionWithOrigin(parentNode, parentNode?.origin || nodeOrigin).positionAbsolute; } const positionAbsolute = currentExtent diff --git a/packages/core/src/store/index.ts b/packages/core/src/store/index.ts index c4e408c7..a886b252 100644 --- a/packages/core/src/store/index.ts +++ b/packages/core/src/store/index.ts @@ -92,8 +92,8 @@ const createRFStore = () => [internalsSymbol]: { ...node[internalsSymbol], handleBounds: { - source: getHandleBounds('.source', update.nodeElement, zoom, nodeOrigin), - target: getHandleBounds('.target', update.nodeElement, zoom, nodeOrigin), + source: getHandleBounds('.source', update.nodeElement, zoom, node.origin || nodeOrigin), + target: getHandleBounds('.target', update.nodeElement, zoom, node.origin || nodeOrigin), }, }, ...dimensions, diff --git a/packages/core/src/store/utils.ts b/packages/core/src/store/utils.ts index 15438212..d6d69825 100644 --- a/packages/core/src/store/utils.ts +++ b/packages/core/src/store/utils.ts @@ -16,7 +16,7 @@ function calculateXYZPosition( return result; } const parentNode = nodeInternals.get(node.parentNode)!; - const parentNodePosition = getNodePositionWithOrigin(parentNode, nodeOrigin); + const parentNodePosition = getNodePositionWithOrigin(parentNode, parentNode?.origin || nodeOrigin); return calculateXYZPosition( parentNode, @@ -26,7 +26,7 @@ function calculateXYZPosition( y: (result.y ?? 0) + parentNodePosition.y, z: (parentNode[internalsSymbol]?.z ?? 0) > (result.z ?? 0) ? parentNode[internalsSymbol]?.z ?? 0 : result.z ?? 0, }, - nodeOrigin + parentNode.origin || nodeOrigin ); } @@ -41,6 +41,7 @@ export function updateAbsoluteNodePositions( } if (node.parentNode || parentNodes?.[node.id]) { + const parentNode = node.parentNode ? nodeInternals.get(node.parentNode) : null; const { x, y, z } = calculateXYZPosition( node, nodeInternals, @@ -48,7 +49,7 @@ export function updateAbsoluteNodePositions( ...node.position, z: node[internalsSymbol]?.z ?? 0, }, - nodeOrigin + parentNode?.origin || nodeOrigin ); node.positionAbsolute = { diff --git a/packages/minimap/src/MiniMap.tsx b/packages/minimap/src/MiniMap.tsx index 59b3f34d..faf0b9bb 100644 --- a/packages/minimap/src/MiniMap.tsx +++ b/packages/minimap/src/MiniMap.tsx @@ -56,7 +56,7 @@ function MiniMap({ nodeBorderRadius = 5, nodeStrokeWidth = 2, // We need to rename the prop to be `CapitalCase` so that JSX will render it as - // a component properly. + // a component properly. nodeComponent: NodeComponent = MiniMapNode, maskColor = 'rgb(240, 240, 240, 0.6)', maskStrokeColor = 'none', @@ -181,7 +181,7 @@ function MiniMap({ > {ariaLabel && {ariaLabel}} {nodes.map((node) => { - const { x, y } = getNodePositionWithOrigin(node, nodeOrigin).positionAbsolute; + const { x, y } = getNodePositionWithOrigin(node, node.origin || nodeOrigin).positionAbsolute; return ( { - const { x, y } = getNodePositionWithOrigin(node, nodeOrigin).positionAbsolute; + const { x, y } = getNodePositionWithOrigin(node, node.origin || nodeOrigin).positionAbsolute; return getBoundsOfBoxes( currBox, rectToBox({ @@ -256,7 +256,7 @@ export const getNodesInside = ( return res; } - const { positionAbsolute } = getNodePositionWithOrigin(node, nodeOrigin); + const { positionAbsolute } = getNodePositionWithOrigin(node, node.origin || nodeOrigin); const nodeRect = { x: positionAbsolute.x, @@ -316,7 +316,7 @@ export const getD3Transition = (selection: D3SelectionInstance, duration = 0) => }; export function fitView, Options extends FitViewOptionsBase>( - { nodes, width, height, d3Zoom, d3Selection, nodeOrigin, minZoom, maxZoom }: Params, + { nodes, width, height, d3Zoom, d3Selection, minZoom, maxZoom, nodeOrigin = [0, 0] }: Params, options?: Options ) { const filteredNodes = nodes.filter((n) => { diff --git a/packages/utils/src/utils.ts b/packages/utils/src/utils.ts index 43c96dc9..b2d6d802 100644 --- a/packages/utils/src/utils.ts +++ b/packages/utils/src/utils.ts @@ -172,13 +172,13 @@ export const getPositionWithOrigin = ({ y, width, height, - origin, + origin = [0, 0], }: { x: number; y: number; width: number; height: number; - origin: NodeOrigin; + origin?: NodeOrigin; }): XYPosition => { if (!width || !height) { return { x, y };