Created
January 16, 2020 22:56
-
-
Save ColemanCollins/541b5987c312e02beb1c10b323db4933 to your computer and use it in GitHub Desktop.
Quick-and-dirty attempt to add arrowheads on links in @mrblenny/react-flow-chart; required redoing the curve generation logic.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import styles from './Link.module.scss'; | |
const generateCurvePath = (startPos, endPos) => { | |
const width = Math.abs(startPos.x - endPos.x); | |
const height = Math.abs(startPos.y - endPos.y); | |
const isHorizontal = width > height; | |
const isVertical = !isHorizontal; | |
const topToBottom = startPos.y < endPos.y; | |
const bottomToTop = !topToBottom; | |
const leftToRight = startPos.x < endPos.x; | |
const rightToLeft = !leftToRight; | |
const straightLine = (isHorizontal && height < 50 && endPos.x > startPos.x) || (isVertical && width < 50 && endPos.y > startPos.y); | |
const endOffset = 13; | |
const curve = Math.min((width + height) / 4, 100); | |
let curveString; | |
if (topToBottom && leftToRight) curveString = `C ${endPos.x - curve},${endPos.y - curve} ${startPos.x + curve},${startPos.y + curve}` | |
if (topToBottom && rightToLeft) curveString = `C ${startPos.x + curve * 2},${startPos.y + curve} ${endPos.x - curve * 2},${endPos.y - curve}` | |
if (bottomToTop && leftToRight) curveString = `C ${startPos.x + curve}, ${startPos.y + curve / 3} ${endPos.x - curve}, ${endPos.y - curve / 3} ` | |
if (bottomToTop && rightToLeft) curveString = `C ${startPos.x + curve * 2}, ${startPos.y + curve} ${endPos.x - curve * 2}, ${endPos.y - curve} ` | |
return `M${startPos.x}, ${startPos.y} ${straightLine ? '' : curveString} ${endPos.x - endOffset}, ${endPos.y} `; | |
}; | |
const colors = { | |
1: '#002bff', | |
2: '#2d4ad7', | |
3: '#5b69b0', | |
4: '#a4a4a4' | |
}; | |
const Link = ({ | |
config, | |
link, | |
startPos, | |
endPos, | |
onLinkMouseEnter, | |
onLinkMouseLeave, | |
onLinkClick, | |
isHovered, | |
isSelected | |
}) => { | |
const { properties = {} } = link; | |
const points = generateCurvePath(startPos, endPos); | |
const stroke = | |
properties.percentage * 8 > 1.5 ? properties.percentage * 8 : 1.5; | |
const color = colors[properties.recentRun] | |
? colors[properties.recentRun] | |
: '#dddddd'; | |
const dashes = properties.recentRun === 'never' ? '3' : null; | |
const markerID = Math.random() | |
.toString(36) | |
.substring(2, 15); //gotta be unique-ish or the defs reference stuff gets screwy | |
const centerX = startPos.x + (endPos.x - startPos.x) / 2; | |
const centerY = startPos.y + (endPos.y - startPos.y) / 2; | |
return ( | |
<> | |
<svg | |
style={{ | |
overflow: 'visible', | |
position: 'absolute', | |
cursor: 'pointer', | |
left: 0, | |
right: 0 | |
}} | |
> | |
<defs> | |
<marker | |
id={markerID} | |
viewBox="0 0 10 10" | |
refX="0" | |
refY="5" | |
markerWidth="10" | |
markerHeight="10" | |
fill={color} | |
orient="auto" | |
markerUnits="userSpaceOnUse" | |
> | |
<path d="M 0 0 L 10 5 L 0 10 z" /> | |
</marker> | |
</defs> | |
{/* Main line */} | |
<path | |
d={points} | |
stroke={color} | |
strokeWidth={stroke} | |
fill="none" | |
markerEnd={`url(#${markerID})`} | |
strokeDasharray={dashes} | |
/> | |
{/* Thick line to make selection easier */} | |
<path | |
d={points} | |
stroke="#aaa" | |
strokeWidth="15" | |
fill="none" | |
strokeLinecap="round" | |
strokeOpacity={isHovered || isSelected ? 0.1 : 0} | |
onMouseEnter={() => | |
onLinkMouseEnter({ config, linkId: link.id }) | |
} | |
onMouseLeave={() => | |
onLinkMouseLeave({ config, linkId: link.id }) | |
} | |
onClick={e => { | |
onLinkClick({ config, linkId: link.id }); | |
e.stopPropagation(); | |
}} | |
/> | |
</svg> | |
<p | |
className={styles.label} | |
style={{ | |
left: centerX, | |
top: centerY | |
}} | |
onMouseEnter={() => | |
onLinkMouseEnter({ config, linkId: link.id }) | |
} | |
onMouseLeave={() => | |
onLinkMouseLeave({ config, linkId: link.id }) | |
} | |
onClick={e => { | |
onLinkClick({ config, linkId: link.id }); | |
e.stopPropagation(); | |
}} | |
> | |
{properties.label === '*' ? '' : properties.label} | |
</p> | |
</> | |
); | |
}; | |
export default Link; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment