You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Application-Web/front/components/arrows/BendableArrow.tsx

82 lines
2.1 KiB

import { CSSProperties, ReactElement, useCallback, useEffect, useRef } from "react"
import { add, Pos, relativeTo, size } from "./Pos"
export interface BendableArrowProps {
basePos: Pos
startPos: Pos
endPos: Pos
startRadius?: number
endRadius?: number
style?: ArrowStyle
}
export interface ArrowStyle {
width?: number,
head?: () => ReactElement,
tail?: () => ReactElement,
}
const ArrowStyleDefaults = {
width: 4
}
export default function BendableArrow({ basePos, startPos, endPos, style, startRadius = 0, endRadius = 0 }: BendableArrowProps) {
const svgRef = useRef<SVGSVGElement>(null)
const pathRef = useRef<SVGPathElement>(null);
const styleWidth = style?.width ?? ArrowStyleDefaults.width
const update = () => {
const startRelative = relativeTo(startPos, basePos)
const endRelative = relativeTo(endPos, basePos)
// the width and height of the arrow svg
const svgBoxBounds = size(startPos, endPos)
const left = Math.min(startRelative.x, endRelative.x)
const top = Math.min(startRelative.y, endRelative.y)
const svgStyle: CSSProperties = {
width: `${svgBoxBounds.x}px`,
height: `${svgBoxBounds.y}px`,
left: `${left}px`,
top: `${top}px`,
}
const d = `M${startRelative.x - left} ${startRelative.y - top} L${endRelative.x - left} ${endRelative.y - top}`
pathRef.current!.setAttribute("d", d)
Object.assign(svgRef.current!.style, svgStyle)
}
useEffect(() => {
//update on resize
window.addEventListener('resize', update)
return () => window.removeEventListener('resize', update)
}, [svgRef, basePos, startPos, endPos])
//update on position changes
useEffect(update, [svgRef, basePos, startPos, endPos])
return (
<svg ref={svgRef} style={{
overflow: "visible",
position: "absolute",
}}>
<path
ref={pathRef}
stroke={"#000"}
strokeWidth={styleWidth} />
</svg>
)
}