refactor(drag-edge): cleanup drag edge handlers

This commit is contained in:
moklick
2020-11-05 17:28:21 +01:00
parent 9dfe7ea8e3
commit 2f40a83b47
5 changed files with 47 additions and 64 deletions
+37 -21
View File
@@ -2,7 +2,8 @@ import React, { memo, ComponentType, useCallback } from 'react';
import cc from 'classcat'; import cc from 'classcat';
import { useStoreActions } from '../../store/hooks'; import { useStoreActions } from '../../store/hooks';
import { Edge, EdgeProps, WrapEdgeProps } from '../../types'; import { Edge, EdgeProps, WrapEdgeProps, Connection } from '../../types';
import { onMouseDown } from '../../components/Handle/BaseHandle';
export default (EdgeComponent: ComponentType<EdgeProps>) => { export default (EdgeComponent: ComponentType<EdgeProps>) => {
const EdgeWrapper = ({ const EdgeWrapper = ({
@@ -32,9 +33,13 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
elementsSelectable, elementsSelectable,
markerEndId, markerEndId,
isHidden, isHidden,
onEitherEndOfEdgePress, sourceHandleId,
targetHandleId,
onEdgeUpdate,
}: WrapEdgeProps) => { }: WrapEdgeProps) => {
const addSelectedElements = useStoreActions((actions) => actions.addSelectedElements); const addSelectedElements = useStoreActions((actions) => actions.addSelectedElements);
const setConnectionNodeId = useStoreActions((actions) => actions.setConnectionNodeId);
const setPosition = useStoreActions((actions) => actions.setConnectionPosition);
const inactive = !elementsSelectable && !onClick; const inactive = !elementsSelectable && !onClick;
const edgeClasses = cc([ const edgeClasses = cc([
@@ -63,35 +68,46 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
[elementsSelectable, id, source, target, type, data, onClick] [elementsSelectable, id, source, target, type, data, onClick]
); );
const handleEdgeUpdaterMouseDown = useCallback( const handleEdgeUpdater = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>, isEdgeHeader?: boolean): void => { (event: React.MouseEvent<SVGGElement, MouseEvent>, isSourceHandle: boolean) => {
if (elementsSelectable) { const nodeId = isSourceHandle ? target : source;
addSelectedElements({ id, source, target }); const handleId = isSourceHandle ? targetHandleId : sourceHandleId;
}
const edgeElement: Edge = { id, source, target, type }; const onConnect = (connection: Connection) => {
if (onEdgeUpdate) {
const edgeElement: Edge = {
id,
source,
target,
sourceHandle: sourceHandleId,
targetHandle: targetHandleId,
type,
};
if (typeof data !== 'undefined') { onEdgeUpdate(edgeElement, connection);
edgeElement.data = data; }
} };
onEitherEndOfEdgePress(event, edgeElement, isEdgeHeader); const isValidConnection = () => true;
const isTarget = isSourceHandle;
onMouseDown(event, handleId, nodeId, setConnectionNodeId, setPosition, onConnect, isTarget, isValidConnection);
}, },
[elementsSelectable, id, source, target, type, data, onEitherEndOfEdgePress] [id, source, target, type, sourceHandleId, targetHandleId, setConnectionNodeId, setPosition]
); );
const handleEdgeTargetMouseDown = useCallback( const onEdgeUpdaterSourceMouseDown = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => { (event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
handleEdgeUpdaterMouseDown(event, true); handleEdgeUpdater(event, true);
}, },
[handleEdgeUpdaterMouseDown] [id, source, sourceHandleId, handleEdgeUpdater]
); );
const handleEdgeSourceMouseDown = useCallback( const onEdgeUpdaterTargetMouseDown = useCallback(
(event: React.MouseEvent<SVGGElement, MouseEvent>): void => { (event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
handleEdgeUpdaterMouseDown(event); handleEdgeUpdater(event, false);
}, },
[handleEdgeUpdaterMouseDown] [id, target, targetHandleId, handleEdgeUpdater]
); );
if (isHidden) { if (isHidden) {
@@ -100,7 +116,7 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
return ( return (
<g className={edgeClasses} onClick={onEdgeClick}> <g className={edgeClasses} onClick={onEdgeClick}>
<g onMouseDown={handleEdgeSourceMouseDown}> <g onMouseDown={onEdgeUpdaterSourceMouseDown}>
<circle <circle
className="react-flow__edgeupdater" className="react-flow__edgeupdater"
cx={sourceX} cx={sourceX}
@@ -133,7 +149,7 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
targetPosition={targetPosition} targetPosition={targetPosition}
markerEndId={markerEndId} markerEndId={markerEndId}
/> />
<g onMouseDown={handleEdgeTargetMouseDown}> <g onMouseDown={onEdgeUpdaterTargetMouseDown}>
<circle <circle
className="react-flow__edgeupdater" className="react-flow__edgeupdater"
cx={targetX} cx={targetX}
+3 -28
View File
@@ -1,6 +1,6 @@
import React, { memo, CSSProperties } from 'react'; import React, { memo, CSSProperties } from 'react';
import { useStoreState, useStoreActions } from '../../store/hooks'; import { useStoreState } from '../../store/hooks';
import ConnectionLine from '../../components/ConnectionLine/index'; import ConnectionLine from '../../components/ConnectionLine/index';
import { isEdge } from '../../utils/graph'; import { isEdge } from '../../utils/graph';
import MarkerDefinitions from './MarkerDefinitions'; import MarkerDefinitions from './MarkerDefinitions';
@@ -14,10 +14,8 @@ import {
Elements, Elements,
ConnectionLineType, ConnectionLineType,
ConnectionLineComponent, ConnectionLineComponent,
Connection,
OnEdgeUpdateFunc, OnEdgeUpdateFunc,
} from '../../types'; } from '../../types';
import { onMouseDown, SetSourceIdFunc } from '../../components/Handle/BaseHandle';
interface EdgeRendererProps { interface EdgeRendererProps {
edgeTypes: any; edgeTypes: any;
@@ -138,9 +136,7 @@ function renderEdge(
props: EdgeRendererProps, props: EdgeRendererProps,
nodes: Node[], nodes: Node[],
selectedElements: Elements | null, selectedElements: Elements | null,
elementsSelectable: boolean, elementsSelectable: boolean
setConnectionNodeId: SetSourceIdFunc,
setPosition: (pos: XYPosition) => void
) { ) {
const sourceId = edge.source; const sourceId = edge.source;
const sourceHandleId = edge.sourceHandle || null; const sourceHandleId = edge.sourceHandle || null;
@@ -192,22 +188,6 @@ function renderEdge(
const isSelected = selectedElements ? selectedElements.some((elm) => isEdge(elm) && elm.id === edge.id) : false; const isSelected = selectedElements ? selectedElements.some((elm) => isEdge(elm) && elm.id === edge.id) : false;
const onConnect = (connection: Connection) => {
const { onEdgeUpdate } = props;
if (onEdgeUpdate) {
onEdgeUpdate(edge, connection);
}
};
const handleEitherEndOfEdgePress = (event: React.MouseEvent, edge: Edge, isEdgeHeader = false) => {
const { source, target } = edge;
const nodeId = isEdgeHeader ? source : target;
const isValidConnection = () => true;
const isTarget = !isEdgeHeader;
onMouseDown(event, null, nodeId, setConnectionNodeId, setPosition, onConnect, isTarget, isValidConnection);
};
return ( return (
<EdgeComponent <EdgeComponent
key={edge.id} key={edge.id}
@@ -239,7 +219,6 @@ function renderEdge(
elementsSelectable={elementsSelectable} elementsSelectable={elementsSelectable}
markerEndId={props.markerEndId} markerEndId={props.markerEndId}
isHidden={edge.isHidden} isHidden={edge.isHidden}
onEitherEndOfEdgePress={handleEitherEndOfEdgePress}
/> />
); );
} }
@@ -257,8 +236,6 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
const elementsSelectable = useStoreState((state) => state.elementsSelectable); const elementsSelectable = useStoreState((state) => state.elementsSelectable);
const width = useStoreState((state) => state.width); const width = useStoreState((state) => state.width);
const height = useStoreState((state) => state.height); const height = useStoreState((state) => state.height);
const setConnectionNodeId = useStoreActions((actions) => actions.setConnectionNodeId);
const setPosition = useStoreActions((actions) => actions.setConnectionPosition);
const { connectionLineType, arrowHeadColor, connectionLineStyle, connectionLineComponent } = props; const { connectionLineType, arrowHeadColor, connectionLineStyle, connectionLineComponent } = props;
@@ -273,9 +250,7 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
<svg width={width} height={height} className="react-flow__edges"> <svg width={width} height={height} className="react-flow__edges">
<MarkerDefinitions color={arrowHeadColor} /> <MarkerDefinitions color={arrowHeadColor} />
<g transform={transformStyle}> <g transform={transformStyle}>
{edges.map((edge: Edge) => {edges.map((edge: Edge) => renderEdge(edge, props, nodes, selectedElements, elementsSelectable))}
renderEdge(edge, props, nodes, selectedElements, elementsSelectable, setConnectionNodeId, setPosition)
)}
{renderConnectionLine && ( {renderConnectionLine && (
<ConnectionLine <ConnectionLine
nodes={nodes} nodes={nodes}
+3 -2
View File
@@ -111,7 +111,8 @@ export interface WrapEdgeProps {
arrowHeadType?: ArrowHeadType; arrowHeadType?: ArrowHeadType;
source: ElementId; source: ElementId;
target: ElementId; target: ElementId;
sourceHandleId?: string; sourceHandleId: ElementId | null;
targetHandleId: ElementId | null;
sourceX: number; sourceX: number;
sourceY: number; sourceY: number;
targetX: number; targetX: number;
@@ -121,7 +122,7 @@ export interface WrapEdgeProps {
elementsSelectable?: boolean; elementsSelectable?: boolean;
markerEndId?: string; markerEndId?: string;
isHidden?: boolean; isHidden?: boolean;
onEitherEndOfEdgePress: (event: React.MouseEvent, edge: Edge, isEdgeHeader?: boolean) => void; onEdgeUpdate?: OnEdgeUpdateFunc;
} }
export interface EdgeProps { export interface EdgeProps {
+2 -11
View File
@@ -82,16 +82,8 @@ export const updateEdge = (oldEdge: Edge, newConnection: Connection, elements: E
throw new Error("Can't create new edge. An edge needs a source and a target."); throw new Error("Can't create new edge. An edge needs a source and a target.");
} }
// make sure that there is node with the target and one with the source id const foundEdge = elements.find((e) => isEdge(e) && e.id === oldEdge.id) as Edge;
[newConnection.source, newConnection.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.`);
}
});
const foundEdge = elements.find(e => isEdge(e) && e.id === oldEdge.id) as Edge;
if (!foundEdge) { if (!foundEdge) {
throw new Error(`The old edge with id=${oldEdge.id} does not exist.`); throw new Error(`The old edge with id=${oldEdge.id} does not exist.`);
} }
@@ -104,10 +96,9 @@ export const updateEdge = (oldEdge: Edge, newConnection: Connection, elements: E
target: newConnection.target, target: newConnection.target,
} as Edge; } as Edge;
return elements.filter(e => e.id !== oldEdge.id).concat(edge); return elements.filter((e) => e.id !== oldEdge.id).concat(edge);
}; };
export const pointToRendererPoint = ( export const pointToRendererPoint = (
{ x, y }: XYPosition, { x, y }: XYPosition,
[tx, ty, tScale]: Transform, [tx, ty, tScale]: Transform,