|
| 1 | +import React, { useMemo } from 'react' |
| 2 | + |
| 3 | +import { chakra, keyframes, usePrefersReducedMotion } from '@chakra-ui/react' |
| 4 | + |
| 5 | +import { EdgeLabel } from './EdgeLabel' |
| 6 | +import { grey } from '@mui/material/colors' |
| 7 | +import type { EdgeProps } from './Edge' |
| 8 | + |
| 9 | +const ChakraPolyline = chakra('polyline') // need to use animation prop |
| 10 | +const marchingAnts = keyframes({ from: { strokeDashoffset: 60 }, to: { strokeDashoffset: 0 } }) |
| 11 | + |
| 12 | +export const ElbowEdge = ({ edge, isMiniMap }: EdgeProps) => { |
| 13 | + const reducedMotion = usePrefersReducedMotion() || isMiniMap // do not animate the minimap |
| 14 | + |
| 15 | + const points = useMemo(() => { |
| 16 | + const { startPoint, bendPoints, endPoint } = edge |
| 17 | + |
| 18 | + return [ |
| 19 | + // source |
| 20 | + { x: startPoint.x, y: startPoint.y }, |
| 21 | + ...(bendPoints?.map((bendPoint) => ({ x: bendPoint.x, y: bendPoint.y })) ?? []), |
| 22 | + // target |
| 23 | + { x: endPoint.x, y: endPoint.y }, |
| 24 | + ] |
| 25 | + }, [edge]) |
| 26 | + |
| 27 | + // Find the longest edge that the label would be near |
| 28 | + let longestEdge: { y: number; length: number } | undefined |
| 29 | + if (edge.label) { |
| 30 | + points.forEach((p, i) => { |
| 31 | + if (i > 0) { |
| 32 | + const length = p.x - points[i - 1].x |
| 33 | + if (!longestEdge || longestEdge.length < length) longestEdge = { y: p.y, length } |
| 34 | + } |
| 35 | + }) |
| 36 | + } |
| 37 | + return ( |
| 38 | + <> |
| 39 | + <polyline |
| 40 | + id={`${edge.sourceNodeId}-${edge.targetNodeId}`} |
| 41 | + fill='none' |
| 42 | + stroke={edge.color || grey['600']} |
| 43 | + strokeWidth={edge.strokeWidth || 2} |
| 44 | + strokeLinejoin='round' |
| 45 | + points={points.map(({ x, y }) => `${x},${y}`).join(' ')} |
| 46 | + /> |
| 47 | + <EdgeLabel label={edge.label} endPointY={longestEdge?.y} /> |
| 48 | + {!reducedMotion && edge.isAnimated && ( |
| 49 | + <ChakraPolyline |
| 50 | + id={`${edge.sourceNodeId}-${edge.targetNodeId}-animated`} |
| 51 | + fill='none' |
| 52 | + strokeLinecap='round' |
| 53 | + stroke={edge.color || grey['600']} |
| 54 | + strokeWidth={edge.strokeWidth || 5} |
| 55 | + strokeLinejoin='round' |
| 56 | + strokeDasharray='0px 60px' |
| 57 | + animation={`${marchingAnts} infinite 2s linear`} |
| 58 | + points={points.map(({ x, y }) => `${x},${y}`).join(' ')} |
| 59 | + /> |
| 60 | + )} |
| 61 | + </> |
| 62 | + ) |
| 63 | +} |
0 commit comments