import ConnectionLine from '../../components/ConnectionLine/index'; import { isEdge } from '../../utils/graph'; import MarkerDefinitions from './MarkerDefinitions'; import { getEdgePositions, getHandle, isEdgeVisible, getSourceTargetNodes } from './utils'; import { Position, Edge, Node, Elements, Connection, ConnectionLineType, ConnectionLineComponent, ConnectionMode, Transform, OnEdgeUpdateFunc } from '../../types'; import { computed, CSSProperties, defineComponent, PropType, ref } from 'vue'; import store from '../../store'; interface EdgeRendererProps { edgeTypes: any; connectionLineType: ConnectionLineType; connectionLineStyle?: CSSProperties; connectionLineComponent?: ConnectionLineComponent; connectionMode?: ConnectionMode; onElementClick?: (event: MouseEvent, element: Node | Edge) => void; onEdgeDoubleClick?: (event: MouseEvent, edge: Edge) => void; arrowHeadColor: string; markerEndId?: string; onlyRenderVisibleElements: boolean; onEdgeUpdate?: OnEdgeUpdateFunc; onEdgeContextMenu?: (event: MouseEvent, edge: Edge) => void; onEdgeMouseEnter?: (event: MouseEvent, edge: Edge) => void; onEdgeMouseMove?: (event: MouseEvent, edge: Edge) => void; onEdgeMouseLeave?: (event: MouseEvent, edge: Edge) => void; onEdgeUpdateStart?: (event: MouseEvent, edge: Edge) => void; onEdgeUpdateEnd?: (event: MouseEvent, edge: Edge) => void; edgeUpdaterRadius?: number; } interface EdgeWrapperProps { edge: Edge; props: EdgeRendererProps; nodes: Node[]; selectedElements: Elements | null; elementsSelectable: boolean; transform: Transform; width: number; height: number; onlyRenderVisibleElements: boolean; connectionMode?: ConnectionMode; } const EdgeCmp = defineComponent({ props: { edge: { type: Object as PropType, required: true }, props: { type: Object as PropType, required: true }, nodes: { type: Array as unknown as PropType, required: true }, selectedElements: { type: Array as unknown as PropType, required: false, default: undefined }, elementsSelectable: { type: Boolean as PropType, required: false, default: false }, transform: { type: Array as unknown as PropType, required: false, default: () => [] }, width: { type: Number as PropType, required: false, default: undefined }, height: { type: Number as PropType, required: false, default: undefined }, onlyRenderVisibleElements: { type: Boolean as PropType, required: false, default: false }, connectionMode: { type: String as PropType, required: false, default: undefined } }, setup(props) { const sourceHandleId = props.edge.sourceHandle || null; const targetHandleId = props.edge.targetHandle || null; const nodes = computed(() => { console.log('foo'); return getSourceTargetNodes(props.edge, props.nodes); }); const { sourceNode, targetNode } = nodes.value; console.log(nodes.value); const onConnectEdge = (connection: Connection) => { props.props.onEdgeUpdate?.(props.edge, connection); }; if (!sourceNode) { console.log(`couldn't create edge for source id: ${props.edge.source}; edge id: ${props.edge.id}`); return null; } if (!targetNode) { console.log(`couldn't create edge for target id: ${props.edge.target}; edge id: ${props.edge.id}`); return null; } // source and target node need to be initialized if (!sourceNode.__rf.width || !targetNode.__rf.width) { return null; } const edgeType = props.edge.type || 'default'; const EdgeComponent: any = props.props.edgeTypes[edgeType] || props.props.edgeTypes.default; const targetNodeBounds = targetNode.__rf.handleBounds; // when connection type is loose we can define all handles as sources const targetNodeHandles = props.connectionMode === ConnectionMode.Strict ? targetNodeBounds.target : targetNodeBounds.target || targetNodeBounds.source; const sourceHandle = getHandle(sourceNode.__rf.handleBounds.source, sourceHandleId); const targetHandle = getHandle(targetNodeHandles, targetHandleId); const sourcePosition = sourceHandle ? sourceHandle.position : Position.Bottom; const targetPosition = targetHandle ? targetHandle.position : Position.Top; if (!sourceHandle) { console.log(`couldn't create edge for source handle id: ${sourceHandleId}; edge id: ${props.edge.id}`); return null; } if (!targetHandle) { console.log(`couldn't create edge for target handle id: ${targetHandleId}; edge id: ${props.edge.id}`); return null; } const { sourceX, sourceY, targetX, targetY } = getEdgePositions( sourceNode, sourceHandle, sourcePosition, targetNode, targetHandle, targetPosition ); const isVisible = computed(() => { return props.onlyRenderVisibleElements ? isEdgeVisible({ sourcePos: { x: sourceX, y: sourceY }, targetPos: { x: targetX, y: targetY }, width: props.width || 0, height: props.height || 0, transform: props.transform }) : true; }); if (!isVisible.value) { return null; } const isSelected = computed(() => props.selectedElements?.some((elm) => isEdge(elm) && elm.id === props.edge.id) || false); return () => ( ); } }); const EdgeRenderer = defineComponent({ name: 'EdgeRenderer', components: { EdgeCmp, ConnectionLine }, props: { edgeTypes: { type: Object, required: false, default: undefined }, connectionLineType: { type: String as PropType, required: false, default: undefined }, connectionLineStyle: { type: Object as PropType, required: false, default: undefined }, connectionLineComponent: { type: Object as PropType, required: false, default: undefined }, connectionMode: { type: String as PropType, required: false, default: undefined }, onElementClick: { type: Function() as PropType, required: false, default: undefined }, onEdgeDoubleClick: { type: Function() as PropType, required: false, default: undefined }, arrowHeadColor: { type: String as PropType, required: false, default: undefined }, markerEndId: { type: String as PropType, required: false, default: undefined }, onlyRenderVisibleElements: { type: Boolean as PropType, required: false, default: undefined }, onEdgeUpdate: { type: Function() as PropType, required: false, default: undefined }, onEdgeContextMenu: { type: Function() as PropType, required: false, default: undefined }, onEdgeMouseEnter: { type: Function() as PropType, required: false, default: undefined }, onEdgeMouseMove: { type: Function() as PropType, required: false, default: undefined }, onEdgeMouseLeave: { type: Function() as PropType, required: false, default: undefined }, onEdgeUpdateStart: { type: Function() as PropType, required: false, default: undefined }, onEdgeUpdateEnd: { type: Function() as PropType, required: false, default: undefined }, edgeUpdaterRadius: { type: Number as PropType, required: false, default: undefined } }, setup(props) { const pinia = store(); const transformStyle = `translate(${pinia.transform[0]},${pinia.transform[1]}) scale(${pinia.transform[2]})`; const renderConnectionLine = pinia.connectionNodeId && pinia.connectionHandleType; return () => ( {pinia.edges.map((edge: Edge) => ( ))} {renderConnectionLine && ( )} ); } }); export default EdgeRenderer;