Feature: Draggable edge
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { memo, CSSProperties } from 'react';
|
||||
|
||||
import { useStoreState } from '../../store/hooks';
|
||||
import { useStoreState, useStoreActions } from '../../store/hooks';
|
||||
import ConnectionLine from '../../components/ConnectionLine/index';
|
||||
import { isEdge } from '../../utils/graph';
|
||||
import MarkerDefinitions from './MarkerDefinitions';
|
||||
@@ -14,7 +14,10 @@ import {
|
||||
Elements,
|
||||
ConnectionLineType,
|
||||
ConnectionLineComponent,
|
||||
Connection,
|
||||
OnEdgeUpdateFunc
|
||||
} from '../../types';
|
||||
import { onMouseDown, SetSourceIdFunc } from '../../components/Handle/BaseHandle';
|
||||
|
||||
interface EdgeRendererProps {
|
||||
edgeTypes: any;
|
||||
@@ -24,6 +27,7 @@ interface EdgeRendererProps {
|
||||
arrowHeadColor: string;
|
||||
markerEndId?: string;
|
||||
connectionLineComponent?: ConnectionLineComponent;
|
||||
onEdgeUpdate?: OnEdgeUpdateFunc;
|
||||
}
|
||||
|
||||
interface EdgePositions {
|
||||
@@ -130,7 +134,9 @@ function renderEdge(
|
||||
props: EdgeRendererProps,
|
||||
nodes: Node[],
|
||||
selectedElements: Elements | null,
|
||||
elementsSelectable: boolean
|
||||
elementsSelectable: boolean,
|
||||
setConnectionNodeId: SetSourceIdFunc,
|
||||
setPosition: (pos: XYPosition) => void,
|
||||
) {
|
||||
const [sourceId, sourceHandleId] = edge.source.split('__');
|
||||
const [targetId, targetHandleId] = edge.target.split('__');
|
||||
@@ -168,6 +174,30 @@ function renderEdge(
|
||||
|
||||
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,
|
||||
nodeId,
|
||||
setConnectionNodeId,
|
||||
setPosition,
|
||||
onConnect,
|
||||
isTarget,
|
||||
isValidConnection,
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<EdgeComponent
|
||||
key={edge.id}
|
||||
@@ -199,6 +229,7 @@ function renderEdge(
|
||||
elementsSelectable={elementsSelectable}
|
||||
markerEndId={props.markerEndId}
|
||||
isHidden={edge.isHidden}
|
||||
onEitherEndOfEdgePress={handleEitherEndOfEdgePress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -215,6 +246,8 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
|
||||
const elementsSelectable = useStoreState((state) => state.elementsSelectable);
|
||||
const width = useStoreState((state) => state.width);
|
||||
const height = useStoreState((state) => state.height);
|
||||
const setConnectionNodeId = useStoreActions((actions) => actions.setConnectionNodeId);
|
||||
const setPosition = useStoreActions((actions) => actions.setConnectionPosition);
|
||||
|
||||
const { connectionLineType, arrowHeadColor, connectionLineStyle, connectionLineComponent } = props;
|
||||
|
||||
@@ -229,7 +262,16 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
|
||||
<svg width={width} height={height} className="react-flow__edges">
|
||||
<MarkerDefinitions color={arrowHeadColor} />
|
||||
<g transform={transformStyle}>
|
||||
{edges.map((edge: Edge) => renderEdge(edge, props, nodes, selectedElements, elementsSelectable))}
|
||||
{edges.map((edge: Edge) =>
|
||||
renderEdge(
|
||||
edge,
|
||||
props,
|
||||
nodes,
|
||||
selectedElements,
|
||||
elementsSelectable,
|
||||
setConnectionNodeId,
|
||||
setPosition,
|
||||
))}
|
||||
{renderConnectionLine && (
|
||||
<ConnectionLine
|
||||
nodes={nodes}
|
||||
|
||||
@@ -25,7 +25,8 @@ import {
|
||||
OnConnectStartFunc,
|
||||
OnConnectStopFunc,
|
||||
OnConnectEndFunc,
|
||||
TranslateExtent,
|
||||
TranslateExtent,
|
||||
OnEdgeUpdateFunc,
|
||||
} from '../../types';
|
||||
|
||||
export interface GraphViewProps {
|
||||
@@ -77,6 +78,7 @@ export interface GraphViewProps {
|
||||
zoomOnScroll?: boolean;
|
||||
zoomOnDoubleClick?: boolean;
|
||||
paneMoveable?: boolean;
|
||||
onEdgeUpdate?: OnEdgeUpdateFunc;
|
||||
}
|
||||
|
||||
const GraphView = ({
|
||||
@@ -128,6 +130,7 @@ const GraphView = ({
|
||||
onPaneClick,
|
||||
onPaneScroll,
|
||||
onPaneContextMenu,
|
||||
onEdgeUpdate,
|
||||
}: GraphViewProps) => {
|
||||
const isInitialised = useRef<boolean>(false);
|
||||
const zoomPane = useRef<HTMLDivElement>(null);
|
||||
@@ -310,6 +313,7 @@ const GraphView = ({
|
||||
arrowHeadColor={arrowHeadColor}
|
||||
markerEndId={markerEndId}
|
||||
connectionLineComponent={connectionLineComponent}
|
||||
onEdgeUpdate={onEdgeUpdate}
|
||||
/>
|
||||
<UserSelection selectionKeyPressed={selectionKeyPressed} />
|
||||
{nodesSelectionActive && (
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
OnConnectStopFunc,
|
||||
OnConnectEndFunc,
|
||||
TranslateExtent,
|
||||
OnEdgeUpdateFunc,
|
||||
} from '../../types';
|
||||
|
||||
import '../../style.css';
|
||||
@@ -99,6 +100,7 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
||||
markerEndId?: string;
|
||||
zoomOnScroll?: boolean;
|
||||
zoomOnDoubleClick?: boolean;
|
||||
onEdgeUpdate?: OnEdgeUpdateFunc;
|
||||
}
|
||||
|
||||
const ReactFlow = ({
|
||||
@@ -153,6 +155,7 @@ const ReactFlow = ({
|
||||
onPaneScroll,
|
||||
onPaneContextMenu,
|
||||
children,
|
||||
onEdgeUpdate,
|
||||
...rest
|
||||
}: ReactFlowProps) => {
|
||||
const nodeTypesParsed = useMemo(() => createNodeTypes(nodeTypes), []);
|
||||
@@ -211,6 +214,7 @@ const ReactFlow = ({
|
||||
onSelectionDrag={onSelectionDrag}
|
||||
onSelectionDragStop={onSelectionDragStop}
|
||||
onSelectionContextMenu={onSelectionContextMenu}
|
||||
onEdgeUpdate={onEdgeUpdate}
|
||||
/>
|
||||
{onSelectionChange && <SelectionListener onSelectionChange={onSelectionChange} />}
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user