refactor(drag-edge): cleanup drag edge handlers
This commit is contained in:
@@ -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}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ export function onMouseDown(
|
|||||||
|
|
||||||
function onMouseUp(event: MouseEvent) {
|
function onMouseUp(event: MouseEvent) {
|
||||||
const { connection, isValid } = checkElementBelowIsValid(event);
|
const { connection, isValid } = checkElementBelowIsValid(event);
|
||||||
|
|
||||||
if (onConnectStop) {
|
if (onConnectStop) {
|
||||||
onConnectStop(event);
|
onConnectStop(event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
+4
-3
@@ -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 {
|
||||||
@@ -322,4 +323,4 @@ export type FlowTransform = {
|
|||||||
|
|
||||||
export type TranslateExtent = [[number, number], [number, number]];
|
export type TranslateExtent = [[number, number], [number, number]];
|
||||||
|
|
||||||
export type OnEdgeUpdateFunc = (oldEdge: Edge, newConnection: Connection) => void;
|
export type OnEdgeUpdateFunc = (oldEdge: Edge, newConnection: Connection) => void;
|
||||||
|
|||||||
+2
-11
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user