Reputation: 51
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.
Here is the result:
Upvotes: 1
Views: 92
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