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
22.07k stars 1.46k forks source link

Is there a way to increase select-ability size of edges? #1211

Closed BenBrewerBowman closed 2 years ago

BenBrewerBowman commented 3 years ago

Right now, especially when using dashed edge connection lines, they are quite difficult to select with the mouse for deletion. It would be nice to be able to add some padding around the edge connections so they are easier to select with the mouse and can be deleted easier. Is there a solution for this that already exists? Padding prop to the edges perhaps?

ChuckJonas commented 3 years ago

I'm also running into this issue.

I guess you could increase the edge width, but it would be nice if there was some way to make the selection a little easier and maintain the narrow lines.

Increasing the width on hover might have this effect.

ChuckJonas commented 3 years ago

Was able to do this with css:

path.react-flow__edge-path:hover {
  stroke-width: 4;
}

There might be a better way to do this, but the effect is actually quite nice.

BenBrewerBowman commented 3 years ago

Thanks @ChuckJonas I'll check this out. Appreciate the help

moklick commented 3 years ago

We changed the pointer-events of the edges to visiblestroke. That was a bad idea.. I will look into it.

atompie commented 3 years ago

HI I have the same issue. I could not find the way to increase edge select region.

This a a workaround be not very effective. Still a bit too narrow for some users.

path.react-flow__edge-path:hover {
  stroke-width: 4;
}

Is there any solution for this.

Maybe this approach could help. https://www.youtube.com/watch?v=VS738eijP4U (this is something different - but background could be transparent and maybe this way selection would be easier. Just an idea

RickeyWard commented 2 years ago

The solution I used was to use a custom edge that rendered 2 copies of the path, one transparent with a large stroke, and one that I wanted to see. Works really well,

jsx

<path style={style} className="react-flow__edge-path-selector" d={path} markerEnd={markerEnd} fillRule="evenodd" />
<path style={style} className="react-flow__edge-path" d={path} markerEnd={markerEnd} fillRule="evenodd" />

css

.react-flow__edge-path-selector:hover { cursor: pointer }
.react-flow__edge-path-selector:hover + .react-flow__edge-path, .react-flow__edge-path:hover  {
    stroke: #555;
    cursor: pointer;
}
.react-flow__edge-path-selector {
    fill: none;
    stroke: transparent;
    stroke-width: 28;
}

I implemented this 6 months ago haven't had a single complaint from users.

EmanueleGurini commented 2 years ago

The solution I used was to use a custom edge that rendered 2 copies of the path, one transparent with a large stroke, and one that I wanted to see. Works really well,

jsx

<path style={style} className="react-flow__edge-path-selector" d={path} markerEnd={markerEnd} fillRule="evenodd" />
<path style={style} className="react-flow__edge-path" d={path} markerEnd={markerEnd} fillRule="evenodd" />

css

.react-flow__edge-path-selector:hover { cursor: pointer }
.react-flow__edge-path-selector:hover + .react-flow__edge-path, .react-flow__edge-path:hover  {
    stroke: #555;
    cursor: pointer;
}
.react-flow__edge-path-selector {
    fill: none;
    stroke: transparent;
    stroke-width: 28;
}

I implemented this 6 months ago haven't had a single complaint from users.

Hi RickeyWard, sorry about my question, but where did you create that two new path?

RickeyWard commented 2 years ago

@EmanueleGurini You'll need to create a copy of an existing edge (or make a custom one from scratch) to modify it and set it as a custom edge type. Basic understanding can be pulled from the Edges example https://reactflow.dev/examples/edges/

I apologize I don't have time to produce the full example at the moment. Happy holidays.

EmanueleGurini commented 2 years ago

@EmanueleGurini You'll need to create a copy of an existing edge (or make a custom one from scratch) to modify it and set it as a custom edge type. Basic understanding can be pulled from the Edges example https://reactflow.dev/examples/edges/

I apologize I don't have time to produce the full example at the moment. Happy holidays.

Amazing: solution works well!

Thank's indeed for your contribution and answer. Happy holidays!

staticfire commented 2 years ago

I'm facing this issue today, and there is my solution. Base on the CustomEdge.js example, add this below the <path> line:

{/* A transparent path to extend the path width*/}
<path
  className="react-flow__edge-path"
  style={{ strokeWidth: 40, stroke: "initial" }}
  d={edgePath}
/>
moklick commented 2 years ago

This is the preferred solution: https://github.com/wbkd/react-flow/issues/1211#issuecomment-883673705 Thanks @RickeyWard

benlongo commented 1 year ago

If anybody else stumbles into this issue, it looks like interactionWidth was added to the edge options which seems to achieve this natively https://github.com/wbkd/react-flow/commit/51e957e5dbafb55578ad432d348c582b73c8b9c9

moklick commented 1 year ago

Good point @benlongo . We added this feature in v11 :)

AmmarZeer commented 1 year ago

Does this not work for custom edges? I send interactionWidth to it, but it doesn't get affected (interaction stays the same)

moklick commented 1 year ago

@AmmarZeer you can use the BaseEdge if you want to use interactionWidth https://reactflow.dev/docs/api/edges/base-edge/

nikolay-codeit commented 1 year ago

Tried to use BaseEdge with EdgeLabelRenderer and pass interactionWidth -> no lucky. No interaction zone at all.

oshanley commented 1 year ago

Tried to use BaseEdge with EdgeLabelRenderer and pass interactionWidth -> no lucky. No interaction zone at all.

I ran into this issue today, with the added difficulty of wanting to display an add-node button on hover. Thought I'd document my solution in case anyone else ran into a similar issue.

Overview The first step was using BaseEdge as mentioned above. Second, was applying pointer-events: all on the "hidden" interactive path to get the hover state to apply.

Code Example Note: this uses styled components but the premise is the same for stylesheets and inline styling.


This is my custom edge:

     export function AddNodeEdge(){
     {/* ... */}
     return (
          <EdgePathContainer>
                <BaseEdge
                    path={edgePath}
                    markerEnd={markerEnd}
                    interactionWidth={160}
                />
                <AddNodeButton
                    transform={`translate(${edgeCenterX}, ${edgeCenterY})`}
                    onClick={onClick}
                >
                    <Rect x={-10} y={-10} width={20} ry={4} rx={4} height={20} />
                    <AddNodeText y={4} x={-4}>
                        +
                    </AddNodeText>
                </AddNodeButton>
            </EdgePathContainer>
);

And this is the styled component definition for EdgePathContainer

const EdgePathContainer = styled.g`
// Select the second path aka the invisible interactive path
   path:nth-child(2) {
        pointer-events: all; // This is the key to getting the hover to work
        &:hover {
            & + g { // Alternatively, you can use & + ${AddNodeButton}
                // Make add node button visible
                visibility: visible;
            }
        }
    }`

And now we have a very discoverable edge interaction!

GIF Recording 2023-06-09 at 3 40 07 PM (2)

bsfkaustubh commented 4 months ago

For those using Custom Edge with BaseEdge and who hate writing CSS. This pretty much gets the job done:

    <BaseEdge
        path={edgePath}
        {...props}
        style={{
          stroke:
            isNodeHovered 
              ? "#EF4444"
              : "white",
        }}
      />

      <BaseEdge
        path={edgePath}
        {...props}
        style={{
          strokeWidth: "25px",
          opacity: 0,
        }}
      />