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.

Revisions

  1. OrionReed revised this gist Jun 7, 2024. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions gistfile1.tsx
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,10 @@
    interface CurvedLineProps {
    start: VecLike;
    end: VecLike;
    stress: number;
    radius: number;
    }

    const CurvedLine: React.FC<CurvedLineProps> = ({
    start,
    end,
  2. OrionReed renamed this gist Jun 7, 2024. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. OrionReed created this gist Jun 7, 2024.
    42 changes: 42 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    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>
    );
    };