import { MouseEvent, memo } from 'react'; import { EdgeArrowMarker } from './EdgeArrowMarker'; import { computeNodeCircumferenceStrokeWidth, nodeR } from './Node'; import { EdgeDatumLayout, NodeDatum } from './types'; import { shortenLine } from './utils'; export const defaultHighlightedEdgeColor = '#a00'; export const defaultEdgeColor = '#999'; interface Props { edge: EdgeDatumLayout; hovering: boolean; svgIdNamespace: string; onClick: (event: MouseEvent, link: EdgeDatumLayout) => void; onMouseEnter: (id: string) => void; onMouseLeave: (id: string) => void; processedNodesLength: number; } export const Edge = memo(function Edge(props: Props) { const { edge, onClick, onMouseEnter, onMouseLeave, hovering, svgIdNamespace, processedNodesLength } = props; // Not great typing but after we do layout these properties are full objects not just references const { source, target, sourceNodeRadius, targetNodeRadius } = edge as { source: NodeDatum; target: NodeDatum; sourceNodeRadius: number; targetNodeRadius: number; }; const arrowHeadHeight = 10 + edge.thickness * 2; // resized value, just to make the UI nicer // As the nodes have some radius we want edges to end outside of the node circle. const line = shortenLine( { x1: source.x!, y1: source.y!, x2: target.x!, y2: target.y!, }, sourceNodeRadius + computeNodeCircumferenceStrokeWidth(sourceNodeRadius) / 2 || nodeR, targetNodeRadius + computeNodeCircumferenceStrokeWidth(targetNodeRadius) / 2 || nodeR, arrowHeadHeight ); const edgeColor = edge.color || defaultEdgeColor; // @deprecated -- until 'highlighted' is removed we'll prioritize 'color' // in case both are provided const highlightedEdgeColor = edge.color || defaultHighlightedEdgeColor; const markerId = `triangle-${svgIdNamespace}-${edge.id}`; const coloredMarkerId = `triangle-colored-${svgIdNamespace}-${edge.id}`; return ( <> onClick(event, edge)} style={{ cursor: 'pointer' }} aria-label={`Edge from: ${source.id} to: ${target.id}`} > { onMouseEnter(edge.id); }} onMouseLeave={() => { onMouseLeave(edge.id); }} /> ); });