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