Merge branch 'next' into feat/dragedge

This commit is contained in:
moklick
2020-11-26 15:26:48 +01:00
32 changed files with 9834 additions and 28326 deletions
+52 -124
View File
@@ -4,16 +4,15 @@ import { useStoreState } from '../../store/hooks';
import ConnectionLine from '../../components/ConnectionLine/index';
import { isEdge } from '../../utils/graph';
import MarkerDefinitions from './MarkerDefinitions';
import { getEdgePositions, getHandle, isEdgeVisible, getSourceTargetNodes } from './utils';
import {
XYPosition,
Position,
Edge,
Node,
ElementId,
HandleElement,
Elements,
ConnectionLineType,
ConnectionLineComponent,
Transform,
OnEdgeUpdateFunc,
Connection,
} from '../../types';
@@ -26,134 +25,32 @@ interface EdgeRendererProps {
arrowHeadColor: string;
markerEndId?: string;
connectionLineComponent?: ConnectionLineComponent;
onlyRenderVisibleElements: boolean;
onEdgeUpdate?: OnEdgeUpdateFunc;
}
interface EdgePositions {
sourceX: number;
sourceY: number;
targetX: number;
targetY: number;
}
function getHandlePosition(position: Position, node: Node, handle: any | null = null): XYPosition {
if (!handle) {
switch (position) {
case Position.Top:
return {
x: node.__rf.width / 2,
y: 0,
};
case Position.Right:
return {
x: node.__rf.width,
y: node.__rf.height / 2,
};
case Position.Bottom:
return {
x: node.__rf.width / 2,
y: node.__rf.height,
};
case Position.Left:
return {
x: 0,
y: node.__rf.height / 2,
};
}
}
switch (position) {
case Position.Top:
return {
x: handle.x + handle.width / 2,
y: handle.y,
};
case Position.Right:
return {
x: handle.x + handle.width,
y: handle.y + handle.height / 2,
};
case Position.Bottom:
return {
x: handle.x + handle.width / 2,
y: handle.y + handle.height,
};
case Position.Left:
return {
x: handle.x,
y: handle.y + handle.height / 2,
};
}
}
function getHandle(bounds: HandleElement[], handleId: ElementId | null): HandleElement | null | undefined {
let handle = null;
if (!bounds) {
return null;
}
// there is no handleId when there are no multiple handles/ handles with ids
// so we just pick the first one
if (bounds.length === 1 || !handleId) {
handle = bounds[0];
} else if (handleId) {
handle = bounds.find((d) => d.id === handleId);
}
if (typeof handle === 'undefined') {
return null;
}
return handle;
}
function getEdgePositions(
sourceNode: Node,
sourceHandle: HandleElement | unknown,
sourcePosition: Position,
targetNode: Node,
targetHandle: HandleElement | unknown,
targetPosition: Position
): EdgePositions {
const sourceHandlePos = getHandlePosition(sourcePosition, sourceNode, sourceHandle);
const sourceX = sourceNode.__rf.position.x + sourceHandlePos.x;
const sourceY = sourceNode.__rf.position.y + sourceHandlePos.y;
const targetHandlePos = getHandlePosition(targetPosition, targetNode, targetHandle);
const targetX = targetNode.__rf.position.x + targetHandlePos.x;
const targetY = targetNode.__rf.position.y + targetHandlePos.y;
return {
sourceX,
sourceY,
targetX,
targetY,
};
}
function renderEdge(
edge: Edge,
props: EdgeRendererProps,
nodes: Node[],
selectedElements: Elements | null,
elementsSelectable: boolean
elementsSelectable: boolean,
transform: Transform,
width: number,
height: number,
onlyRenderVisibleElements: boolean
) {
const sourceId = edge.source;
const sourceHandleId = edge.sourceHandle || null;
const targetId = edge.target;
const targetHandleId = edge.targetHandle || null;
const sourceNode = nodes.find((n) => n.id === sourceId);
const targetNode = nodes.find((n) => n.id === targetId);
const { sourceNode, targetNode } = getSourceTargetNodes(edge, nodes);
if (!sourceNode) {
console.warn(`couldn't create edge for source id: ${sourceId}`);
console.warn(`couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`);
return null;
}
if (!targetNode) {
console.warn(`couldn't create edge for target id: ${targetId}`);
console.warn(`couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`);
return null;
}
@@ -169,12 +66,12 @@ function renderEdge(
const targetPosition = targetHandle ? targetHandle.position : Position.Top;
if (!sourceHandle) {
console.warn(`couldn't create edge for source handle id: ${sourceHandleId}`);
console.warn(`couldn't create edge for source handle id: ${sourceHandleId}; edge id: ${edge.id}`);
return null;
}
if (!targetHandle) {
console.warn(`couldn't create edge for source handle id: ${targetHandleId}`);
console.warn(`couldn't create edge for target handle id: ${targetHandleId}; edge id: ${edge.id}`);
return null;
}
@@ -187,7 +84,21 @@ function renderEdge(
targetPosition
);
const isSelected = selectedElements ? selectedElements.some((elm) => isEdge(elm) && elm.id === edge.id) : false;
const isVisible = onlyRenderVisibleElements
? isEdgeVisible({
sourcePos: { x: sourceX, y: sourceY },
targetPos: { x: targetX, y: targetY },
width,
height,
transform,
})
: true;
if (!isVisible) {
return null;
}
const isSelected = selectedElements?.some((elm) => isEdge(elm) && elm.id === edge.id) || false;
const onConnectEdge = (connection: Connection) => {
props.onEdgeUpdate?.(edge, connection);
@@ -231,9 +142,8 @@ function renderEdge(
}
const EdgeRenderer = (props: EdgeRendererProps) => {
const [tX, tY, tScale] = useStoreState((state) => state.transform);
const transform = useStoreState((state) => state.transform);
const edges = useStoreState((state) => state.edges);
const nodes = useStoreState((state) => state.nodes);
const connectionNodeId = useStoreState((state) => state.connectionNodeId);
const connectionHandleId = useStoreState((state) => state.connectionHandleId);
const connectionHandleType = useStoreState((state) => state.connectionHandleType);
@@ -243,21 +153,39 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
const elementsSelectable = useStoreState((state) => state.elementsSelectable);
const width = useStoreState((state) => state.width);
const height = useStoreState((state) => state.height);
const { connectionLineType, arrowHeadColor, connectionLineStyle, connectionLineComponent } = props;
const nodes = useStoreState((state) => state.nodes);
if (!width) {
return null;
}
const transformStyle = `translate(${tX},${tY}) scale(${tScale})`;
const {
connectionLineType,
arrowHeadColor,
connectionLineStyle,
connectionLineComponent,
onlyRenderVisibleElements,
} = props;
const transformStyle = `translate(${transform[0]},${transform[1]}) scale(${transform[2]})`;
const renderConnectionLine = connectionNodeId && connectionHandleType;
return (
<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,
transform,
width,
height,
onlyRenderVisibleElements
)
)}
{renderConnectionLine && (
<ConnectionLine
nodes={nodes}
@@ -266,7 +194,7 @@ const EdgeRenderer = (props: EdgeRendererProps) => {
connectionHandleType={connectionHandleType!}
connectionPositionX={connectionPosition.x}
connectionPositionY={connectionPosition.y}
transform={[tX, tY, tScale]}
transform={transform}
connectionLineStyle={connectionLineStyle}
connectionLineType={connectionLineType}
isConnectable={nodesConnectable}