reactjsreact-typescriptreact-flow

Resize Group type node in react-flow-renderer using mouse


I want to add subflow (group type node) on button click and resize it later with mouse and add nodes inside this group with drag and drop. I have searched a lot but all I found is you have set parentNode of child to do this.

I want all this with mouse drag and drop. Is it possible with free version of React-flow-renderer ?

Edit

SandBox- > https://codesandbox.io/embed/headless-architecture-6xbzu9?fontsize=14&hidenavigation=1&theme=dark

Below I have attached onDragEnd function.. It works but when I drop a node inside group, node position changes and it goes outside group. upon moving group it moves with the group which means its parent is set correctly but position is not correct. tried to set manual position but still it is not working.

const handleDragEnd = useCallback(
(event: React.MouseEvent<Element>, node: Node) => {
  let groupNode: Node | undefined = undefined;
  if (node.type === ConstantsFlowChartNodeTypes.GROUP) return;
  nodes.map((nds: Node) => {
    if (nds.type === ConstantsFlowChartNodeTypes.GROUP) {
      console.log(
        nds.type,
        nds,
        nds.type === ConstantsFlowChartNodeTypes.GROUP
      );
      if (
        nds.position.x <= node.position.x &&
        nds.position.x + parseInt(nds.style?.width?.toString() || "0") >=
          node.position.x &&
        nds.position.y <= node.position.y &&
        nds.position.y + parseInt(nds.style?.height?.toString() || "0") >=
          node.position.y
      ) {
        groupNode = nds;
      }
    }
  });
  console.log(groupNode);
  if (groupNode) {
    const position = {
      x: event.clientX,
      y: event.clientY,
    };
    setNodes((prevNodes) => {
      return prevNodes.map((nds) => {
        nds.parentNode =
          nds.id === node.id ? groupNode?.id : nds.parentNode;
        // nds.positionAbsolute = position;
        console.log(event);
        return { ...nds };
      });
    });
  }
},
[]);

Solution

  • Resize Group

    As of v11.3, Resizing node is possible and reactflow(previously react-flow-renderer) library has a component for that.

    So after pondering upon the issue so many times, I realized, I was actually getting position of mousePointer instead of actual node. I had 2 scenarios to deal with.

    Outside to inside Group

    nodeWithUpdatedPosition.position = {
                x: draggedNode.positionAbsolute?.x! - targetGroupNode.position.x,
                y: draggedNode.positionAbsolute?.y! - targetGroupNode.position.y,
              };
    

    You have to subtract position of targetGroupNode because if you add parent to any node, its position will be relative to that group(targetGroupNode) meaning if you give draggedNode position of {x:0, y:0} then it will be placed at top-left corner inside targetGroupNode. Subtracting from positionAbsolute will make the position relative to groupNode.

    Inside to Outside Group

    nodeWithUpdatedPosition.position = draggedNode.positionAbsolute!
    

    This resolved all of the issues related to positioning of nodes. It works even if user drag, zoom in or zoom out the canvas.

    Working codeSandbox