AgileDom
AgileDom

Reputation: 51

Curve the vertex of a rotating triangle in SVG

I have a function which generates a SVG "needle", which is part of a gauge (think speedometer).

function calculateNeedlePath(params: {
  percentage: number;
  needleLength: number;
  needleRadius: number;
}) {
  const { percentage, needleLength, needleRadius } = params;
  const thetaRad = percentageToRadians(percentage / arcSegmentSize);
  const centerX = 0;
  const centerY = 0;

  const topX = centerX - needleLength * Math.cos(thetaRad);
  const topY = centerY - needleLength * Math.sin(thetaRad);

  const leftX = centerX - needleRadius * Math.cos(thetaRad - Math.PI / 2);
  const leftY = centerY - needleRadius * Math.sin(thetaRad - Math.PI / 2);

  const rightX = centerX - needleRadius * Math.cos(thetaRad + Math.PI / 2);
  const rightY = centerY - needleRadius * Math.sin(thetaRad + Math.PI / 2);

  return `M ${leftX} ${leftY} C ${p1.x} ${p1.y} ${topX} ${topY} T ${rightX} ${rightY}`;
}

I have adapted this from Jake Trents very helpful tutorial here: https://jaketrent.com/post/rotate-gauge-needle-in-d3

I need to utilise a quadratic curve to curve the tip of the needle (the vertex of the triangle).

I have tried to position the point so that it will always be to one side of the triangle (whilst always remaining parallel to the base of the triangle) by adding these lines and adjusting the return statement as so:

  const angleOfHalfNeedlePoint = Math.atan(needleLength / needleRadius);
  const angleOfLineVector =
    (degreesToRadians(180) - angleOfHalfNeedlePoint * 2) / 2;

  const lengthOfBezierCurve = 10;

  const q = {
    x: centerX - lengthOfBezierCurve * Math.cos(angleOfLineVector),
    y: centerY - lengthOfBezierCurve * Math.sin(angleOfLineVector)
  };

  return `M ${leftX} ${leftY} Q ${q.x} ${q.y} ${topX} ${topY} T ${rightX} ${rightY}`;

The result is the needle mutates as it rotates in the gauge, and I need it to maintain a consistent shape.

A diagram: enter image description here

Here is the result:

enter image description here enter image description here

Upvotes: 1

Views: 92

Answers (1)

Arjan
Arjan

Reputation: 1113

The easiest way to solve this kinds of problems in SVG is by not calculating all vertices of your complex path, but only the easiest set of vertices(for example the vertices for a rotation of zero degrees)

This path you wrap in a group with a transform

<g transform="rotate(<the angle>, <origin_x_of_needle>, <origin_y_of_needle>">

  <path d="... <very complex> path" />

</g>

Though this is not exactly the answer you asked for, I hope this will help

Upvotes: 1

Related Questions