Edge.tsx 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import React, { MouseEvent, memo } from 'react';
  2. import { EdgeDatum, NodeDatum } from './types';
  3. import { shortenLine } from './utils';
  4. interface Props {
  5. edge: EdgeDatum;
  6. hovering: boolean;
  7. onClick: (event: MouseEvent<SVGElement>, link: EdgeDatum) => void;
  8. onMouseEnter: (id: string) => void;
  9. onMouseLeave: (id: string) => void;
  10. }
  11. export const Edge = memo(function Edge(props: Props) {
  12. const { edge, onClick, onMouseEnter, onMouseLeave, hovering } = props;
  13. // Not great typing but after we do layout these properties are full objects not just references
  14. const { source, target } = edge as { source: NodeDatum; target: NodeDatum };
  15. // As the nodes have some radius we want edges to end outside of the node circle.
  16. const line = shortenLine(
  17. {
  18. x1: source.x!,
  19. y1: source.y!,
  20. x2: target.x!,
  21. y2: target.y!,
  22. },
  23. 90
  24. );
  25. return (
  26. <g
  27. onClick={(event) => onClick(event, edge)}
  28. style={{ cursor: 'pointer' }}
  29. aria-label={`Edge from: ${(edge.source as NodeDatum).id} to: ${(edge.target as NodeDatum).id}`}
  30. >
  31. <line
  32. strokeWidth={hovering ? 2 : 1}
  33. stroke={'#999'}
  34. x1={line.x1}
  35. y1={line.y1}
  36. x2={line.x2}
  37. y2={line.y2}
  38. markerEnd="url(#triangle)"
  39. />
  40. <line
  41. stroke={'transparent'}
  42. x1={line.x1}
  43. y1={line.y1}
  44. x2={line.x2}
  45. y2={line.y2}
  46. strokeWidth={20}
  47. onMouseEnter={() => {
  48. onMouseEnter(edge.id);
  49. }}
  50. onMouseLeave={() => {
  51. onMouseLeave(edge.id);
  52. }}
  53. />
  54. </g>
  55. );
  56. });