Javascript-форум (https://javascript.ru/forum/)
-   (X)HTML/CSS (https://javascript.ru/forum/xhtml-html-css/)
-   -   CSS animation математический маятник (https://javascript.ru/forum/xhtml-html-css/77002-css-animation-matematicheskijj-mayatnik.html)

Блондинка 12.03.2019 01:13

CSS animation математический маятник
 
Есть специалисты по физике?
сделать анимацию не сложно, вопрос в другом, чисто по физике, как рассчитать траекторию маятника если известны первоначальный угол отклонения 90° длина нити 1м и ускорение под действием земного притяжения 9.8м/с.

надо высчитать на какой угол отклониться в противоположную сторону, и сколько надо времени для достижения этого угла, и второй момент - надо высчитать угол поворота через равные промежутки времени(например 0.1сек) для задания шагов анимации

просто дайте формулы для этих рассчётов.

Malleys 12.03.2019 03:45

Дифференциальное уравнение, описывающее движение маятника


Если вам не нужна большая точность (для первоначального угла 90°), то можно ограничиться таким приближением (приближённым решением уравнения, выдаёт более точные результаты от -20° до 20°, вне пределов с некой погрешностью)



<div class="pendulum"></div>

<style>

.pendulum {
	width: 1px;
	height: 200px;
	background: red;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	transform-origin: 50% 0;
	margin: auto;
}

.pendulum::after {
	content: "";
	display: block;
	width: 10px;
	height: 10px;
	margin-left: -4.5px;
	border-radius: 100%;
	background: inherit;
}

</style>

<script>(function loop() {
	document.querySelector(".pendulum").style.transform = `rotate(${0.5*Math.PI*Math.cos(Math.sqrt(9.8) * Date.now() / 1000)}rad)`;
	requestAnimationFrame(loop);
})();</script>


Если необходимы более точные результаты, воспользуйтесь разложением Фурье... en.wikipedia.org/wiki/Pendulum_(mathematics) (или просмотрите всю статью)

Графики к упомянутому маятнику wolframalpha.com

Блондинка 12.03.2019 20:59

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Математический маятник</title>
<style>
#a { width: 255px; height: 125px;  background: #cfe6cf; border-radius: 15px/12px; border: 1px solid #c0c0c0; position: absolute; }

#b { width: 25px; height: 100px; display: inline-block;  position: absolute; top: 15px; left: 122.5px; -webkit-transform-origin: 50% 0 ;-moz-transform-origin: 50% 0; -o-transform-origin: 50% 0; -ms-transform-origin: 50% 0; transform-origin: 50% 0; -webkit-animation: pendulum-1 1.79s linear 0s 1 normal forwards; -moz-animation: pendulum-1 1.79s linear 0s 1 normal forwards; -o-animation: pendulum-1 1.79s linear 0s 1 normal forwards; -ms-animation: pendulum-1 1.79s linear 0s 1 normal forwards; animation: pendulum-1 1.79s linear 0s 1 normal forwards; }
#c { width: 1px; height: 75px; background: #999999; position: absolute; left: 12px; }
#d { width: 1px; height: 1px; background: transparent; border-top: 15px solid #000080; border-left: 15px solid transparent; border-right: 15px solid transparent; border-bottom: 15px solid transparent; position: absolute; left: 120px; }
#U_2e { width: 25px; height: 25px; display: inline-block; border-radius: 50%; background: -moz-radial-gradient(60% 40%, circle cover, #9999ff 0%, #0000ff 100%); background: -webkit-radial-gradient(60% 40%, circle cover, #9999ff 0%, #0000ff 100%); background: -o-radial-gradient(60% 40%, circle cover, #9999ff 0%, #0000ff 100%); background: -ms-radial-gradient(60% 40%, circle cover, #9999ff 0%, #0000ff 100%); background: radial-gradient(60% 40%, circle cover, #9999ff 0%, #0000ff 100%); position: absolute; top: 75px; }
@-webkit-keyframes pendulum-1 { 0% { -moz-transform: rotate(90deg); -ms-transform: rotate(90deg); -webkit-transform: rotate(90deg); -o-transform: rotate(90deg); transform: rotate(90deg); } 100% { -moz-transform: rotate(-45deg); -ms-transform: rotate(-45deg); -webkit-transform: rotate(-45deg); -o-transform: rotate(-45deg); transform: rotate(-45deg); } }
@-moz-keyframes pendulum-1 { 0% { -moz-transform: rotate(90deg); -ms-transform: rotate(90deg); -webkit-transform: rotate(90deg); -o-transform: rotate(90deg); transform: rotate(90deg); } 100% { -moz-transform: rotate(-45deg); -ms-transform: rotate(-45deg); -webkit-transform: rotate(-45deg); -o-transform: rotate(-45deg); transform: rotate(-45deg); } }
@-o-keyframes pendulum-1 { 0% { -moz-transform: rotate(90deg); -ms-transform: rotate(90deg); -webkit-transform: rotate(90deg); -o-transform: rotate(90deg); transform: rotate(90deg); } 100% { -moz-transform: rotate(-45deg); -ms-transform: rotate(-45deg); -webkit-transform: rotate(-45deg); -o-transform: rotate(-45deg); transform: rotate(-45deg); } }
@-ms-keyframes pendulum-1 { 0% { -moz-transform: rotate(90deg); -ms-transform: rotate(90deg); -webkit-transform: rotate(90deg); -o-transform: rotate(90deg); transform: rotate(90deg); } 100% { -moz-transform: rotate(-45deg); -ms-transform: rotate(-45deg); -webkit-transform: rotate(-45deg); -o-transform: rotate(-45deg); transform: rotate(-45deg); } }
@keyframes pendulum-1 { 0% { -moz-transform: rotate(90deg); -ms-transform: rotate(90deg); -webkit-transform: rotate(90deg); -o-transform: rotate(90deg); transform: rotate(90deg); } 100% { -moz-transform: rotate(-45deg); -ms-transform: rotate(-45deg); -webkit-transform: rotate(-45deg); -o-transform: rotate(-45deg); transform: rotate(-45deg); } }
</style>
</head>
<body>
<div id="a">
<span id="d"></span>
<span id="b">
<span id="c"></span>
<span id="U_2e"></span>
</span>
</div>
</body>
</html>

вот анимация, надо высчитать правильный угол а не взятый примерно 45градусов и точное время вместо 1.79сек.
просто дайте формулы для этих расчётов.

Malleys 13.03.2019 19:00

Цитата:

Сообщение от Блондинка
просто дайте формулы для этих расчётов

Цитата:

Сообщение от Блондинка
просто дайте формулы для этих расчётов

Если вам формулы «дадут», а не «просто дадут», то это какое-то другое значение будет для вас иметь?

Цитата:

Сообщение от Блондинка
дайте формулы

Рассмотрите внимательно пост №2

Цитата:

Сообщение от Блондинка
надо высчитать правильный угол

Это математический маятник, у него крайние значения угла отклонения не меняется со временем. В начале вы написали условия для маятника, среди которых было θ₀ = 90°, значит угол отклонения с противоположной стороны тоже составляет 90°.

Цитата:

Сообщение от Блондинка
надо высчитать... точное время

Также вы указали, что g = 9.8 и l = 1, статья, которую я вам указал, содержит практически всю информацию о математическом маятнике, включая формулу для вычисления периода колебания (вперёд и назад, полное колебание).



Подставим ваши данные, получается T = 2π ⋅ sqrt(1 / 9.8) ≈ 2 (сек.)

В CSS есть функция cubic-bezier(x₁, y₁, x₂, y₂), возможно ли при помощи неё выразить половину периода колебания маятника? Да, возможно! (Я не буду описывать, как это получается, вот рабочий лист с графиками https://www.desmos.com/calculator/qxtb8h7li7)

Математический маятник
<div class="pendulum"></div>
<style>

	.pendulum {
		width: 255px;
		height: 125px;
		background: #cfe6cf;
		border-radius: 15px / 12px;
		border: 1px solid #c0c0c0;
	}

	.pendulum::before {
		content: "";
		display: block;
		width: 0;
		margin: auto;
		border: 15px solid transparent;
		border-top-color: #000080;
		border-bottom-width: 0;
	}

	.pendulum::after {
		content: "";
		display: block;
		margin: auto;
		width: 25px;
		height: 100px;
		background:
			radial-gradient(closest-side circle at 50% 87.5%, #0000ff 90%, transparent),
			linear-gradient(to right, transparent 47%, #999, transparent 53%)
		;
		--mask: radial-gradient(closest-side circle at 45% 84.5%, rgba(0, 0, 0, .3), black 136%);
		-webkit-mask: var(--mask);
		mask: var(--mask);
		transform-origin: 50% 0;
		animation: pendulum 1s alternate infinite cubic-bezier(0.36, 0, 0.646, 1);
	}

	@keyframes pendulum {
		from {
			transform: rotate(90deg);
		}

		to {
			transform: rotate(-90deg);
		}
	}

</style>


Цитата:

Сообщение от Блондинка
надо высчитать... точное время

Оно равно θ(t), где t принимает значения 0, 1/2 * T, T, 3/2 * T, 2 * T, ..., k/2 * T; k ∈ N. Для математического маятника вы получите всегда одинаковые крайние значения, но можно построить маятник, который со временем придёт к состоянию равновесия из-за трения. Пусть функция выражающая количество энергии равна f(t) и представлена при помощи графика (зелёная пунктирная линия, см. рабочий лист). Тогда можно представить маятник с затухающими колебаниями при помощи f(t) ⋅ θ(t).

Цитата:

Сообщение от Блондинка (Сообщение 504711)
То самое, что я не могла найти, всё супер.

Вам только нужно, чтобы анимация запускалась или маятник правильно работал или то и другое?

Цитата:

Сообщение от Блондинка
как обновить див с анимацией по клику по самому диву без всяких кнопок

Так нажать по чему-то подразумевает, что вы попадёте на кнопку! Вы требуете странное, хотите нажать, но кнопку вам не надо! Это как хлопнуть в ладоши без ладошей! (Вы уже это где-то прочитали!) Да, оно работает с мышью, но оно не работает с клавиатуры, оно не работает на некоторых телефонах, оно не работает на Android TV, оно не воспринимается скинридерами как кнопка ... т. е. вы не сможете запустить свою анимацию заново!

Вот переделанный пример из поста №2... (с применением выше написанного)

Маятник с затухающим колебанием, запускается заново при нажатии на него
<button class="pendulum"></button>

<style>

	.pendulum {
		width: 255px;
		background: #cfe6cf;
		border-radius: 15px / 12px;
		border: 1px solid #c0c0c0;
		padding: 0;
		display: block;
	}

	.pendulum::before {
		content: "";
		display: block;
		width: 0;
		margin: auto;
		border: 15px solid transparent;
		border-top-color: #000080;
		border-bottom-width: 0;
	}

	.pendulum::after {
		content: "";
		display: block;
		margin: auto;
		margin-bottom: 8px;
		width: 25px;
		height: 100px;
		background:
				radial-gradient(closest-side circle at 50% 87.5%, #0000ff 90%, transparent),
				linear-gradient(to right, transparent 47%, #999, transparent 53%)
	;
		--mask: radial-gradient(closest-side circle at 45% 84.5%, rgba(0, 0, 0, .3), black 136%);
		-webkit-mask: var(--mask);
		mask: var(--mask);
		transform: rotate(var(--θ));
		transform-origin: 50% 0;
	}

</style>

<script>{
	const pendulumElement = document.querySelector(".pendulum");
	var startTime;

	function setNewStartTime() {
		startTime = Date.now() / 1000
	}

	setNewStartTime();

	(function loop() {
		const t = Date.now() / 1000 - startTime;
		const θ = 0.5 * Math.PI * Math.cos(Math.sqrt(9.8) * t);
		const f = Math.exp(-.25 / Math.PI * t * t);
		pendulumElement.style.setProperty("--θ", `${f * θ}rad`);
		requestAnimationFrame(loop);
	})();

	pendulumElement.addEventListener("click", setNewStartTime);
}</script>


Вы просите одно, а ожидаете другое. Формулируйте свои вопросы более точно, указывайте все подробности. Указывайте, что вы делали, что именно у вас не получается, и пусть это будет в одной теме!

UPD
Цитата:

Сообщение от Блондинка
Так?

Вы спрашиваете так, как будто это у меня что-то не получается, а вы якобы нашли решение, и вопрошаете, действительно ли мне такое подходит!

рони 13.03.2019 19:21

Malleys,
почему
Цитата:

Сообщение от Malleys
pendulumElement.style.setProperty("--θ",

а не сразу pendulumElement.style.setProperty("transform",

Malleys 13.03.2019 19:35

Цитата:

Сообщение от рони (Сообщение 504739)
Malleys,
почему
а не сразу pendulumElement.style.setProperty("transform",

Так требуется, чтобы только маятник крутился, а не подставка с маятником!

Если я применю transform к .pendulum, то повернётся подставка, поэтому я придумал своё собственное свойство --θ, которое наследуется, и поэтому доступно в .pendulum::after, где я его могу применить в объявлении transform: rotate(var(--θ)); (обратите внимание, маятник представлен при помощи псевдо-элемента)

рони 13.03.2019 19:43

Malleys,
спасибо, я упустил что там ::after, а для него нет отдельного style.

Блондинка 13.03.2019 21:14

Malleys, пока я не могу посмотреть примеры, из-за браузера, надо скопировать на "сайт" и добавить префиксы, я хотела сама все высчитать, типа зная время и угол можно высчитать вторую анимацию с задержкой, хотела сначала высчитать сколько шагов анимации надо высчитав углы для шагов 0,20,40,60,80 100%, если результат не понравится добавить шаги 10,30,50,70,90%, если опять не понравится добавить еще промежуточные шаги по 5% и тд, это для одного колебания, для второго колебания (-45град 30 град образно) добавить вторую анимацию где начальный угол не 90гр а взят из результата расчётов первой анимации, также высчитать шаги для второй анимации, потом для третьей и так до полного затухания

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

Malleys 14.03.2019 01:17

Цитата:

Сообщение от Блондинка
добавить префиксы

Вам не нужно добавлять префиксы, для этого можно использовать ⚡препроцессоры⚡, например autoprefixer https://github.com/postcss/autoprefixer или специальный скрипт, который добавит только необходимые браузеру префиксы, например, prefixfreehttps://leaverou.github.io/prefixfree/

Или вы любитель адского ☣CSS☣ с префиксами?

Цитата:

Сообщение от Блондинка
хотела сама все высчитать

Посмотрите в сторону препроцессоров, например, SASS, чтобы у вас не получился адски не управляемый ☣CSS☣. (Хотя с помощью скрипта вы тоже можете генерировать CSS в данном случае)

Блондинка 14.03.2019 09:41

Цитата:

Сообщение от Malleys
Вы просите одно, а ожидаете другое. Формулируйте свои вопросы более точно, указывайте все подробности.

я расчитывала что мне просто дадут формулы как высчитать время и угол отклонения в другую сторону при затухающих колебаниях, с подробными пояснениями этих формул

Цитата:

Сообщение от Malleys
Оно равно θ(t), где t принимает значения 0, 1/2 * T, T, 3/2 * T, 2 * T, ..., k/2 * T; k ∈ N.

с подробными пояснениями что значат буквы в этих формулах.

Цитата:

Сообщение от Malleys (Сообщение 504756)
Если вы хотели добавить префиксы, то вам ещё нужно добавить -webkit-border-radius и -moz-border-radius.
...............

исправила
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Математический маятник</title>
<style>
#mathematics_pendulum { width: 930px; height: 500px;  background: -webkit-linear-gradient(top, #ade6ad, #e6e6cc); background: -moz-linear-gradient(top, #ade6ad, #e6e6cc); background: -o-linear-gradient(top, #ade6ad, #e6e6cc); background: linear-gradient(to top, #ade6ad, #e6e6cc); -webkit-border-radius: 50px/35px; border-radius: 50px/35px; border: 1px solid #c0c0c0; position: absolute; }
#still_point { width: 1px; height: 1px; background: transparent; border-top: 45px solid #000080; border-left: 45px solid transparent; border-right: 45px solid transparent; border-bottom: 45px solid transparent; position: absolute; left: 420px; }
#pendulum {  width: 75px; height: 400px; display: inline-block; position: absolute; left: 428px; top: 45px; -webkit-transform-origin: 50% 0; -ms-transform-origin: 50% 0; transform-origin: 50% 0; }
#mathematics_pendulum.animation_demo #pendulum { -webkit-animation: pendulum-1 1.79s linear 0s 1 normal forwards; animation: pendulum-1 1.79s linear 0s 1 normal forwards; }
#pendulum_rod { width: 3px; height: 325px; background: #999999; border-radius: 2px; position: absolute; left: 36px; }
#point_pendulum { width: 75px; height: 75px; display: inline-block; -webkit-border-radius: 50%; border-radius: 50%; background: -webkit-radial-gradient(60% 40%, circle, #bfbfff, #00f); background: -o-radial-gradient(60% 40%, circle, #bfbfff, #00f); background: radial-gradient(circle at 60% 40%, #bfbfff, #00f); position: absolute; top: 325px; }
@-webkit-keyframes pendulum-1 { 0% { -webkit-transform: rotate(90deg); transform: rotate(90deg); } 100% { -webkit-transform: rotate(-45deg); transform: rotate(-45deg); } } @keyframes pendulum-1 { 0% { -webkit-transform: rotate(90deg); transform: rotate(90deg); } 100% { -webkit-transform: rotate(-45deg); transform: rotate(-45deg); } }
</style>
</head>
</head>
<body>
<div id="mathematics_pendulum" class="animation_demo">
<span id="still_point"></span>
<span id="pendulum">
<span id="pendulum_rod"></span>
<span id="point_pendulum"></span>
</span>
</div>
<script>
var a = document.querySelector("#mathematics_pendulum"); a.addEventListener("click", function() { a.classList.remove("animation_demo"); document.documentElement.clientWidth; a.classList.add("animation_demo"); });
</script>
</body>
</html>


Цитата:

Сообщение от Malleys
Вы просите одно, а ожидаете другое. Формулируйте свои вопросы более точно, указывайте все подробности.

Сейчас надеюсь что помогут вставить скрипт маятника с затухающими колебаниями в код представленный выше в этом посте, но со всеми необходимыми префиксами...
<script>{
	const pendulumElement = document.querySelector(".pendulum");
	var startTime;

	function setNewStartTime() {
		startTime = Date.now() / 1000
	}

	setNewStartTime();

	(function loop() {
		const t = Date.now() / 1000 - startTime;
		const θ = 0.5 * Math.PI * Math.cos(Math.sqrt(9.8) * t);
		const f = Math.exp(-.25 / Math.PI * t * t);
		pendulumElement.style.setProperty("--θ", `${f * θ}rad`);
		requestAnimationFrame(loop);
	})();

	pendulumElement.addEventListener("click", setNewStartTime);
}</script>


Часовой пояс GMT +3, время: 16:32.