Skip to content

Instantly share code, notes, and snippets.

@OrionReed
Last active June 28, 2024 17:33
Show Gist options
  • Save OrionReed/ad8c9a1f1a7d1c34dee75bff0af49cb6 to your computer and use it in GitHub Desktop.
Save OrionReed/ad8c9a1f1a7d1c34dee75bff0af49cb6 to your computer and use it in GitHub Desktop.
StickyLine.tsx
interface CurvedLineProps {
start: VecLike;
end: VecLike;
stress: number;
radius: number;
}
const CurvedLine: React.FC<CurvedLineProps> = ({
start,
end,
stress,
radius,
}) => {
const numSegments = 26; // Number of segments for smoothness
const pathDataOuter: string[] = [];
const pathDataInner: string[] = [];
for (let i = 0; i <= numSegments; i++) {
const t = i / numSegments;
const x = start.x + t * (end.x - start.x);
const y = start.y + t * (end.y - start.y);
// Parabolic thickness adjustment: thickness is smallest in the middle
const thickness = radius * (1 - stress * (1 - 4 * (t - 0.5) ** 2));
const angle = Math.atan2(end.y - start.y, end.x - start.x);
const offsetX = thickness * Math.cos(angle + Math.PI / 2);
const offsetY = thickness * Math.sin(angle + Math.PI / 2);
pathDataOuter.push(`${x + offsetX},${y + offsetY}`);
pathDataInner.push(`${x - offsetX},${y - offsetY}`);
}
const outerPath = `M ${pathDataOuter.join(" L ")}`;
const innerPath = `L ${pathDataInner.reverse().join(" L ")}`;
const color = `hsla(${122 * (1 - stress)}, 75%, 65%, 0.8)`;
return (
<SVGContainer style={{ zIndex: 999999, opacity: stress }}>
{/* Draw the circles at the start and end points */}
<circle cx={start.x} cy={start.y} r={radius} fill={color} />
<circle cx={end.x} cy={end.y} r={radius} fill={color} />
{/* Draw the stretchy shape */}
<path d={`${outerPath} ${innerPath} Z`} fill={color} stroke="none" />
</SVGContainer>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment