shan
shan

Reputation: 3145

Calculate apprx. SVG Ellipse length? (calculate apprx. ellipse circumference with Javascript)

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

Answers (4)

rafaelcastrocouto
rafaelcastrocouto

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

Gerardo Furtado
Gerardo Furtado

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

MBo
MBo

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

shan
shan

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

Related Questions