Reputation: 3145
I have an SVG element like so:
<ellipse class="solidLine" cx="649.9" cy="341.09" rx="39.49" ry="8.41"/>
and I need to find its length
so that I can animate it's dashoffset
to have it being "drawn".
I've done these calculations with the following tags: line
polyline
circle
path
, but now I need to calculate the length of an ellipse and I'm a little.. stuck. I've done some googling and can't seem to find a Javascript way to calculate the circumference of an ellipse.
Any help? Here's my function format so far:
const getEllipseLength = (ellipse) => {
let rx = ellipse.getAttribute('rx');
let ry = ellipse.getAttribute('ry');
let totalLength = //function to calculate ellipse circumference using radius-x (rx) and radius-y (ry) here!
return totalLength;
};
Thanks!
edit: if there's a quick way to do this that isn't 100% accurate (but close) that would be fine also. I just need to get in the ballpark of the actual circumference in order to do a smooth animation.
edit 2: I think using this equation will give me a close estimate without having to delve into Euler's series shenanigans.. gonna translate it into Javascript and see if it works.
Upvotes: 2
Views: 1097
Reputation: 12161
Here's my best approximation for the ellipse perimeter:
e = (a - b) / a
P = (1 - e) * (𝜋 * ((𝜋/2) * a + (2-(𝜋/2)) * b)) + (e * 4 * a)
function getEllipseLength (ellipse) {
let a = ellipse.getAttribute('rx');
let b = ellipse.getAttribute('ry');
if (a < b) {
var t = a;
a = b;
b = t;
}
var hpi = Math.PI/2;
var e = (a - b) / a; // e = 0 circle or 1 = line
return (1 - e) * (Math.PI * (hpi*a + (2-hpi)*b)) + (e * 4 * a);
}
Upvotes: 0
Reputation: 102198
There is a workaround. Using this code:
<path
d="
M cx cy
m -rx, 0
a rx,ry 0 1,1 (rx * 2),0
a rx,ry 0 1,1 -(rx * 2),0
"
/>
We can create a path that's similar to the ellipse. Then, it's just a matter of using getTotalLength()
. Check the demo snippet (I'm using a different cx
and cy
just to save some SVG space):
var length = document.getElementById("path").getTotalLength();
console.log(length)
<svg width="200" height="200">
<path id="path" fill="none" stroke="black" stroke-width="1" d="M 49.9, 41.09 m -39.49, 0 a 39.49,8.41 0 1,0 78.98,0 a 39.49,8.41 0 1,0 -78.98,0"/>
</svg>
It logs 166.82369995117188
, which is very close to 166.79
(the circumference calculated by Google's tool) .
Upvotes: 1
Reputation: 80257
Note that that approximation works good for circle-like ellipses and gives significant error for long ones (with high a/b ratio).
If you aware about the second case, use iterative Gauss-Kummer approach
A = Pi * (a + b) * (1 + h^2/4 + h^4/64 + h^6/256...)
summing until next addend h^k/2^m
becomes small enough
Upvotes: 1
Reputation: 3145
Alright this was actually easier than I thought.. welp.
Since I only needed an approximate length I translated this equation into Javascript and came up with this:
const getEllipseLength = (ellipse) => {
let rx = parseInt(ellipse.getAttribute('rx'));
let ry = parseInt(ellipse.getAttribute('ry'));
let h = Math.pow((rx-ry), 2) / Math.pow((rx+ry), 2);
let totalLength = (Math.PI * ( rx + ry )) * (1 + ( (3 * h) / ( 10 + Math.sqrt( 4 - (3 * h) )) ));
return totalLength;
};
When used with rx="39.49"
and ry="8.41"
it gave me a value of 164.20811705227723
, and google tells me the actual circumference is about 166.79
. Not too bad, and just fine for SVG animation.
Upvotes: 3