From d9ba18d49c022d534c9509ccf9cd376d5edb6274 Mon Sep 17 00:00:00 2001 From: jasonpul Date: Thu, 1 Oct 2020 15:47:37 -0400 Subject: [PATCH] broke out handleId by itself rather than joined with nodeID, modded necessary functions to give handles not assigned IDs an empty string for backwards compadibility. Also modded handles so that only target-source and source-target connections are allowed, and no repeat connections are allowed. --- example/src/CustomNode/ColorSelectorNode.js | 4 +- example/src/CustomNode/index.js | 4 +- example/src/Validation/index.js | 8 ++-- example/src/index.js | 23 +++++------ src/components/Handle/BaseHandle.tsx | 4 -- src/components/Nodes/utils.ts | 9 +---- src/container/EdgeRenderer/index.tsx | 6 ++- src/types/index.ts | 2 + src/utils/graph.ts | 43 +++++++++++++++------ 9 files changed, 55 insertions(+), 48 deletions(-) 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', };