diff --git a/example/src/CustomNode/ColorSelectorNode.js b/example/src/CustomNode/ColorSelectorNode.js index 1b6381f3..cd76d3b0 100644 --- a/example/src/CustomNode/ColorSelectorNode.js +++ b/example/src/CustomNode/ColorSelectorNode.js @@ -15,8 +15,8 @@ export default memo(({ data }) => { Custom Color Picker Node: {data.color} - - + + ); }); diff --git a/example/src/CustomNode/index.js b/example/src/CustomNode/index.js index 6fa29443..7f184011 100644 --- a/example/src/CustomNode/index.js +++ b/example/src/CustomNode/index.js @@ -56,8 +56,8 @@ const CustomNodeFlow = () => { { id: '4', type: 'output', data: { label: 'Output B' }, position: { x: 550, y: 100 }, targetPosition: 'left' }, { id: 'e1-2', source: '1', target: '2', animated: true, style: { stroke: '#fff' } }, - { id: 'e2a-3', source: '2__a', target: '3', animated: true, style: { stroke: '#fff' } }, - { id: 'e2b-4', source: '2__b', target: '4', animated: true, style: { stroke: '#fff' } }, + { id: 'e2a-3', source: '2', sourceHandle: '0', target: '3', animated: true, style: { stroke: '#fff' } }, + { id: 'e2b-4', source: '2', sourceHandle: '1', target: '4', animated: true, style: { stroke: '#fff' } }, ]); }, []); diff --git a/example/src/Validation/index.js b/example/src/Validation/index.js index 7fe81cbe..eac2a998 100644 --- a/example/src/Validation/index.js +++ b/example/src/Validation/index.js @@ -43,7 +43,7 @@ const nodeTypes = { const HorizontalFlow = () => { const [elements, setElements] = useState(initialElements); const onConnect = (params) => { - // console.log('on connect', params); + console.log('on connect', params); setElements((els) => addEdge(params, els)); }; @@ -55,9 +55,9 @@ const HorizontalFlow = () => { onLoad={onLoad} className="validationflow" nodeTypes={nodeTypes} - // onConnectStart={onConnectStart} - // onConnectStop={onConnectStop} - // onConnectEnd={onConnectEnd} + onConnectStart={onConnectStart} + onConnectStop={onConnectStop} + onConnectEnd={onConnectEnd} /> ); }; diff --git a/example/src/index.js b/example/src/index.js index f0c9a95a..f90eee35 100644 --- a/example/src/index.js +++ b/example/src/index.js @@ -117,19 +117,14 @@ const Header = () => { }; ReactDOM.render( - , + +
+ + + {routes.map((route) => ( + } key={route.path} /> + ))} + + , document.getElementById('root') ); - -// ReactDOM.render( -// -//
-// -// -// {routes.map((route) => ( -// } key={route.path} /> -// ))} -// -// , -// document.getElementById('root') -// ); diff --git a/src/components/Handle/BaseHandle.tsx b/src/components/Handle/BaseHandle.tsx index 263d6289..6810ec35 100644 --- a/src/components/Handle/BaseHandle.tsx +++ b/src/components/Handle/BaseHandle.tsx @@ -85,8 +85,6 @@ function onMouseDown( // checks if element below mouse is a handle and returns connection in form of an object { source: 123, target: 312 } function checkElementBelowIsValid(event: MouseEvent) { const elementBelow = document.elementFromPoint(event.clientX, event.clientY); - // console.log(elementBelow) - // console.log(handleId) const result: Result = { elementBelow, @@ -194,9 +192,7 @@ const BaseHandle = ({ }, ]); - // const nodeIdWithHandleId = id ? `${nodeId}__${id}` : nodeId; const handleId = id ? `${id}`: '' - return (
{ const bounds = handle.getBoundingClientRect(); const dimensions = getDimensions(handle); - const nodeIdAttr = handle.getAttribute('data-nodeid'); + const handleId = handle.getAttribute('data-handleid'); const handlePosition = (handle.getAttribute('data-handlepos') as unknown) as Position; - const nodeIdSplitted = nodeIdAttr ? nodeIdAttr.split('__') : null; - - let handleId = null; - - if (nodeIdSplitted) { - handleId = (nodeIdSplitted.length ? nodeIdSplitted[1] : nodeIdSplitted) as string; - } return { id: handleId, diff --git a/src/container/EdgeRenderer/index.tsx b/src/container/EdgeRenderer/index.tsx index e3ba07bd..2c4de04a 100644 --- a/src/container/EdgeRenderer/index.tsx +++ b/src/container/EdgeRenderer/index.tsx @@ -132,8 +132,10 @@ function renderEdge( selectedElements: Elements | null, elementsSelectable: boolean ) { - const [sourceId, sourceHandleId] = edge.source.split('__'); - const [targetId, targetHandleId] = edge.target.split('__'); + const sourceId = edge.source + const sourceHandleId = edge.sourceHandle! + const targetId = edge.target + const targetHandleId = edge.targetHandle! const sourceNode = nodes.find((n) => n.id === sourceId); const targetNode = nodes.find((n) => n.id === targetId); diff --git a/src/types/index.ts b/src/types/index.ts index 721d2e96..1037b63e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -58,6 +58,8 @@ export interface Edge { type?: string; source: ElementId; target: ElementId; + sourceHandle?: ElementId; + targetHandle?: ElementId; label?: string; labelStyle?: CSSProperties; labelShowBg?: boolean; diff --git a/src/utils/graph.ts b/src/utils/graph.ts index a1dfdfab..700f982b 100644 --- a/src/utils/graph.ts +++ b/src/utils/graph.ts @@ -40,7 +40,19 @@ export const removeElements = (elementsToRemove: Elements, elements: Elements): }); }; -const getEdgeId = ({ source, target }: Connection): ElementId => `reactflow__edge-${source}-${target}`; +const getEdgeId = ({ source, sourceHandle, target, targetHandle }: Connection): ElementId => `reactflow__edge-${source}${sourceHandle}-${target}${targetHandle}`; + +const existingConnection = (edge: Edge, elements: Elements) => { + for (const element of elements) { + if (isEdge(element)) { + if (element.source === edge.source && element.sourceHandle === edge.sourceHandle && element.target === edge.target && element.targetHandle === edge.targetHandle) { + return true + } + } + } + return false +} + export const addEdge = (edgeParams: Edge | Connection, elements: Elements): Elements => { if (!edgeParams.source || !edgeParams.target) { @@ -49,22 +61,27 @@ export const addEdge = (edgeParams: Edge | Connection, elements: Elements): Elem // make sure that there is node with the target and one with the source id [edgeParams.source, edgeParams.target].forEach((id) => { - const nodeId = id.includes('__') ? id.split('__')[0] : id; - if (!elements.find((e) => isNode(e) && e.id === nodeId)) { - throw new Error(`Can't create edge. Node with id=${nodeId} does not exist.`); + if (!elements.find((e) => isNode(e) && e.id === id)) { + throw new Error(`Can't create edge. Node with id=${id} does not exist.`); } }); + // need to check if handles exist + // + // + // + let edge: Edge if (isEdge(edgeParams)) { - return elements.concat({ ...edgeParams }); + edge = {...edgeParams} + } else { + edge = { + ...edgeParams, + id: getEdgeId(edgeParams), + } as Edge; } - - const edge = { - ...edgeParams, - id: getEdgeId(edgeParams), - } as Edge; - - return elements.concat(edge); + + if (existingConnection(edge, elements)) {return elements} + return elements.concat(edge) }; export const pointToRendererPoint = ( @@ -112,6 +129,8 @@ export const parseElement = (element: Node | Edge): Node | Edge => { ...element, source: element.source.toString(), target: element.target.toString(), + sourceHandle: element.sourceHandle ? element.sourceHandle.toString() : '', + targetHandle: element.targetHandle ? element.targetHandle.toString() : '', id: element.id.toString(), type: element.type || 'default', };