Вычислить ок. Длина эллипса SVG? (вычислить ок. окружность эллипса с помощью Javascript)

#javascript #math #svg #ellipse

#javascript #математика #svg #эллипс

Вопрос:

У меня есть элемент SVG, например:

 <ellipse class="solidLine" cx="649.9" cy="341.09" rx="39.49" ry="8.41"/>
  

и мне нужно найти его length , чтобы я мог анимировать его dashoffset , чтобы он был «нарисован».

Я выполнил эти вычисления со следующими тегами: line polyline circle path , но теперь мне нужно вычислить длину эллипса, и я немного .. застрял. Я немного погуглил и, похоже, не могу найти способ вычисления окружности эллипса на Javascript.

Любая помощь? Вот мой формат функции до сих пор:

 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;
};
  

Спасибо!

редактировать: если есть быстрый способ сделать это, который не является точным на 100% (но близким), это тоже было бы хорошо. Мне просто нужно приблизиться к фактической окружности, чтобы сделать плавную анимацию.

редактировать 2: я думаю, что использование этого уравнения даст мне приблизительную оценку без необходимости вникать в махинации серии Эйлера.. собираюсь перевести это на Javascript и посмотреть, работает ли это.

Комментарии:

1. Я предполагаю, исходя из этого: en.wikipedia.org/wiki/Ellipse#Circumference что ответ на ваш вопрос не будет чем-то простым.

2. С другой стороны, этот сайт, похоже, использует подход, основанный на JS: csgnetwork.com/circumellipse.html

3. на приведенном выше сайте используется: ellipse = ((Math.sqrt(.5 * ((len * len) (wid * wid)))) * (PI * 2)) / 2;

4. хм, этот сайт на самом деле дал мне значение ~ 89, когда я запускал свои два тестовых варианта, когда реальное значение было ~ 166. думаю, там что-то сломано: c

5. @shanling этот сайт на самом деле дает 179,38. В отличие от инструмента Google, они используют ось, а не радиус, поэтому вам придется умножить ваши rx и ry на 2.

Ответ №1:

Хорошо, это было на самом деле проще, чем я думал.. хорошо.

Поскольку мне нужна была только приблизительная длина, я перевел это уравнение на Javascript и придумал это:

 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;
};
  

При использовании с rx="39.49" и ry="8.41" это дало мне значение 164.20811705227723 , и Google сообщает мне, что фактическая окружность равна примерно 166.79 . Не так уж плохо, и просто отлично для анимации SVG.

Ответ №2:

Обратите внимание, что это приближение хорошо работает для эллипсов, похожих на круги, и дает значительную ошибку для длинных (с высоким соотношением a / b).

Если вы знаете о втором случае, используйте итеративный подход Гаусса-Куммера

 A = Pi * (a   b) * (1   h^2/4   h^4/64   h^6/256...)
  

суммирование до тех пор, пока следующее добавление h^k/2^m не станет достаточно маленьким

Ответ №3:

Существует обходной путь. Используя этот код:

 <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
"
/>
  

Мы можем создать путь, похожий на эллипс. Тогда это просто вопрос использования getTotalLength() . Проверьте демонстрационный фрагмент (я использую другой cx и cy просто для экономии пространства SVG):

 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>  

Он регистрирует 166.82369995117188 , что очень близко к 166.79 (окружности, рассчитанной с помощью инструмента Google).

Комментарии:

1. Хм, интересно! У меня довольно много эллипсов в этом SVG, поэтому просмотр и изменение их всех было бы проблемой, но это было бы полезно знать при создании нового SVG / более простого. Знаете ли вы, будет ли запуск getTotalLength() быстрее, чем метод, который я опубликовал выше?

2. Я не знаю, мы можем сравнить его. Но я считаю, что в этих современных браузерах, если у вас нет астрономического количества эллипсов, разница должна быть незначительной.

3. Кстати, вам не нужно вручную изменять все ваши эллипсы на пути… вы можете создать функцию для этого.

Ответ №4:

Вот мое наилучшее приближение для периметра эллипса:

 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);
}