xyflow / xyflow

React Flow | Svelte Flow - Powerful open source libraries for building node-based UIs with React (https://reactflow.dev) or Svelte (https://svelteflow.dev). Ready out-of-the-box and infinitely customizable.
https://xyflow.com
MIT License
26.06k stars 1.67k forks source link

Edges overlap on nodes using Dagre algorithm [pro-example] #4800

Open imsupercode opened 1 week ago

imsupercode commented 1 week ago

What platform were you using when you found the bug?

Live code example

No response

Describe the Bug

this is an follow up of issue https://github.com/xyflow/xyflow/issues/4762 , when I tried the solution @chrtze gave the node is overlapping on the bottom node in dagre algorithm

Steps to reproduce the bug or issue

increase the height of the node

Expected behavior

Bottom node should displace on increase of the top node's height

Screenshots or Videos

https://github.com/user-attachments/assets/7ba806ab-7351-4a1a-9c4f-00c8c38f19da

Additional context

No response

imsupercode commented 1 week ago

Hi @chrtze, Any updates on this issue?

chrtze commented 1 week ago

@imsupercode could you post the code of your custom node here so that i can reproduce it in the example?

imsupercode commented 1 week ago

@imsupercode could you post the code of your custom node here so that i can reproduce it in the example?

Sure

imsupercode commented 1 week ago
// CustomNode
import React from "react";
import { Position, Handle, useNodes, useEdges } from "@xyflow/react";

export function AddNode({ data, ...rest }) {
  // console.log("rest", rest);
  const { onAddNode, onIncreaseHeight } = data;
  const allNodes = useNodes();
  const allEdges = useEdges();

  return (
    <div style={{ width: 200, height: "100%", border: "1px solid blue" }}>
      <Handle
        type="source"
        position={Position.Bottom}
        id="a"
        style={{ background: "#555" }}
        isConnectable={false}
      />
      <div>{data.label}</div>
      <button
        onClick={() => {
          onAddNode({
            allNodes,
            allEdges,
            nodeData: {
              x: rest.positionAbsoluteX,
              y: rest.positionAbsoluteY,
              measured: {
                width: rest.width,
                height: rest.height,
              },
            },
            edgeData: { source: rest.id },
          });
        }}
      >
        <b>+</b>
      </button>
      <button
        onClick={() => {
          onIncreaseHeight({
            allNodes,
            allEdges,
            id: rest.id,
            height: rest.height,
          });
        }}
      >
        <b>^</b>
      </button>
      <Handle
        type="target"
        position={Position.Top}
        id="b"
        style={{ background: "#555" }}
        isConnectable={false}
      />
    </div>
  );
}
function onIncreaseHeight({ allNodes, allEdges, id, height }) {
      allNodes = allNodes.map((node) => {
        if (node.id === id) {
          return {
            ...node,
            style: {
              height: height + 20,
            },
          };
        }
        return node;
      });

      setNodes(allNodes);
      // setEdges(layoutedEdges);
    }
chrtze commented 5 days ago

This might be caused by this bit:

  measured: {
    width: rest.width,
    height: rest.height,
  },

You shouldn't pass the initial dimensions to the measured option which is set by React Flow internally. You can use the style option instead.

Additionally, you can make sure to always use the actual height of the node by changing this in the onIncreaseHeight:

  style: {
    height: height + 20,
  },

to:

  style: {
    height: node.measured.height + 20
  },
imsupercode commented 1 day ago

Can we have the y value as same as the other nodes on the same axis ? @chrtze . I can send a sandbox link if you want.

https://github.com/user-attachments/assets/294029e8-cf4e-4aa6-a358-e4a830408bd7