5

I am using react-flow to create a node graph. There are little dots that appear above and below each node to create new edges. The selection and drop zones for these edges are so pixel accurate that it makes it hard for users to link items. Is there any way to increase the connection zone? I want users to be able to drag an edge to anywhere on the node and it will link the two together.

import ReactFlow, { removeElements, addEdge, isNode, Background, Elements, BackgroundVariant, FlowElement, Node, Edge, Connection, OnLoadParams } from 'react-flow-renderer';

const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element);

const initialElements: Elements = [
    { id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light' },
    { id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' },
    { id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' },
    { id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' },
    { id: 'e1-2', source: '1', target: '2', animated: true },
];

const BasicFlow = () =>
{
    const [rfInstance, setRfInstance] = useState<OnLoadParams | null>(null);
    const [elements, setElements] = useState<Elements>(initialElements);
    const onElementsRemove = (elementsToRemove: Elements) => setElements((els) => removeElements(elementsToRemove, els));
    const onConnect = (params: Edge | Connection) => setElements((els) => addEdge(params, els));
    const onLoad = (reactFlowInstance: OnLoadParams) => setRfInstance(reactFlowInstance);

    return (
        <ReactFlow
            elements={elements}
            onLoad={onLoad}
            onElementClick={onElementClick}
            onElementsRemove={onElementsRemove}
            onConnect={onConnect}
            onNodeDragStop={onNodeDragStop}
        >
            <Background variant={BackgroundVariant.Lines} />
        </ReactFlow>
    );
};

export default BasicFlow;```
Hughes
  • 339
  • 3
  • 15

2 Answers2

3

I did that passing a custom node with its own handles:

const NODE_TYPES = {
  yourType: CustomNode,
};

...
<ReactFlow
  nodeTypes={NODE_TYPES}
  ... 
/>

Then, at the CustomNode, I used the Handle component with custom height and width:

import { Handle, Position } from 'react-flow-renderer';

const CustomNode = (...) => {
  ...
  return <Box>
    ...
    <Handle
      type="target"
      position={Position.Left}
      style={{ // Make the handle invisible and increase the touch area
        background: 'transparent',
        zIndex: 999,
        border: 'none',
        width: '20px',
        height: '20px',
      }}
    />
    <CircleIcon
      style={{}} // Fix the position of the icon over here
    />
  </Box>;
}

I think its a bit hacky, but that's the way I found to accomplish it.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
0

Based on adding a width and height suggested by Leonardo, I added a class and this worked for me too. Background, border etc are optional possibilities as per your need.

I had to add !important as it wasn't overriding the default settings otherwise.

.node-custom-handle {

  width: 15px!important;
  height: 15px!important;

  background: whitesmoke!important;
  border: 1px solid black!important;
  border-radius: 4px!important;
}

<Handle
    type="target"
    position="top"
    id="t"
    className="node-custom-handle"
    onConnect={(params) => console.log("handle onConnect", params)}
  />
msanjay
  • 2,255
  • 2
  • 19
  • 19