08.11.2023, 08:59
|
Аспирант
|
|
Регистрация: 09.12.2021
Сообщений: 95
|
|
Очередь анимации в цикличном requestAnimationFrame
Подскажите, как можно реализовать очередь для анимации если используется цикличный requestAnimationFrame?
function animate() {
render();
requestAnimationFrame(animate);
}
function render() {
// код для анимации каких ни будь элементов
}
animate()
|
|
08.11.2023, 09:23
|
|
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,742
|
|
Во-первых в функции animate должна быть проверка на то, что анимация должна остановиться. Т.е. вызывать requestAnimationFrame больше не нужно, иначе получится бесконечный цикл.
Во-вторых у функции animate есть параметр - время. Его надо использовать, что бы узнавать время от начала анимации или от предыдущего вызова animate, что бы рассчитывать какие произвести изменения.
Условная схема такая
let tbeg;
let tlast;
function animate(t) {
tbeg ??= t;
tlast ?? = t
const dtbeg = t - tbeg; // прошло от начала анимации
const dtlast = t - tlast; // прошло от прошлой анимации
render(); // расчет и внесение изменений с учетом dtbeg и/или dtlast
tlast = t;
if (какое то условие окончания) return; // Завершить анимацию?
requestAnimationFrame(animate);
}
function render() {
// код для анимации каких ни будь элементов
}
animate(performance.now())
Примеры можно посмотреть тут
https://developer.mozilla.org/en-US/...AnimationFrame
Последний раз редактировалось voraa, 08.11.2023 в 09:36.
|
|
08.11.2023, 11:32
|
Аспирант
|
|
Регистрация: 09.12.2021
Сообщений: 95
|
|
Сообщение от voraa
|
Во-первых в функции animate должна быть проверка на то, что анимация должна остановиться. Т.е. вызывать requestAnimationFrame больше не нужно, иначе получится бесконечный цикл.
Во-вторых у функции animate есть параметр - время. Его надо использовать, что бы узнавать время от начала анимации или от предыдущего вызова animate, что бы рассчитывать какие произвести изменения.
Условная схема такая
let tbeg;
let tlast;
function animate(t) {
tbeg ??= t;
tlast ?? = t
const dtbeg = t - tbeg; // прошло от начала анимации
const dtlast = t - tlast; // прошло от прошлой анимации
render(); // расчет и внесение изменений с учетом dtbeg и/или dtlast
tlast = t;
if (какое то условие окончания) return; // Завершить анимацию?
requestAnimationFrame(animate);
}
function render() {
// код для анимации каких ни будь элементов
}
animate(performance.now())
Примеры можно посмотреть тут
https://developer.mozilla.org/en-US/...AnimationFrame
|
Во первых, в Three.js анимация не останавливается, цикл отрисовки идёт бесконечно (возможно за исключением тех моментов когда окно сайта не активно). Во вторых, а как сделать то очередь из функций для анимации в таком цикле? Если к примеру, нужно чтоб после завершения одной анимации, начиналась другая. Разумеется не останавливая цикла и не создавая новый.
|
|
08.11.2023, 11:44
|
|
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,742
|
|
Если вы используете Three.js, то и пользуйтесь тем, что он дает.
Цикл отрисовки вообще не останавливается. Каждые 1/60 сек (при частоте экрана 60гц) происходит перерисовка экрана с учетом тех изменений, которые были внесены (если браузер не занят орбаботкой длинной задачи).
requestAnimationFrame просто дает возможность внести изменения перед перерисовкой с учетом времени.
Он представляет базовый уровень, на основе которого можно сделать что угодно, но это именно надо делать самому.
Вызовов requestAnimationFrame может быть много (много циклов). И когда наступает время перерисовки страницы, вызываются все функции, зарегистрированные к этому моменту.
Последний раз редактировалось voraa, 08.11.2023 в 11:49.
|
|
08.11.2023, 11:59
|
Аспирант
|
|
Регистрация: 09.12.2021
Сообщений: 95
|
|
Сообщение от voraa
|
Если вы используете Three.js, то и пользуйтесь тем, что он дает.
Цикл отрисовки вообще не останавливается. Каждые 1/60 сек (при частоте экрана 60гц) происходит перерисовка экрана с учетом тех изменений, которые были внесены (если браузер не занят орбаботкой длинной задачи).
requestAnimationFrame просто дает возможность внести изменения перед перерисовкой с учетом времени.
Он представляет базовый уровень, на основе которого можно сделать что угодно, но это именно надо делать самому.
Вызовов requestAnimationFrame может быть много (много циклов). И когда наступает время перерисовки страницы, вызываются все функции, зарегистрированные к этому моменту.
|
Но увеличение количества циклов сильно снижают производительность. Даже тот же Three.js, писался на нативном js. Вот мне и интересно, как можно реализовать очередь анимаций в постоянном цикле.
|
|
08.11.2023, 12:04
|
|
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,742
|
|
Сообщение от Raadsert
|
Но увеличение количества циклов сильно снижают производительность.
|
Ничего они сильно не снижают. Просто перед перерисовкой будут вызываться несколько простых функций, каждая отвечающая за свое изменение анимации, вместо одной сложной, которая делает все изменения.
Зачем постоянный цикл? Если нет изменений, то и вызывать ничего не надо. Когда есть какие то изменения, то для них запускается цикл requestAnimationFrame
Сообщение от Raadsert
|
Даже тот же Three.js, писался на нативном js
|
А на чем еще можно?
Последний раз редактировалось voraa, 08.11.2023 в 12:22.
|
|
08.11.2023, 15:45
|
Аспирант
|
|
Регистрация: 09.12.2021
Сообщений: 95
|
|
Сообщение от voraa
|
Ничего они сильно не снижают. Просто перед перерисовкой будут вызываться несколько простых функций, каждая отвечающая за свое изменение анимации, вместо одной сложной, которая делает все изменения.
Зачем постоянный цикл? Если нет изменений, то и вызывать ничего не надо. Когда есть какие то изменения, то для них запускается цикл requestAnimationFrame
А на чем еще можно?
|
Хорошо, тогда давайте будем отталкиваться от Three.js. Не знаете как можно сделать очередь анимаций для Three.js?
|
|
09.11.2023, 18:36
|
|
Профессор
|
|
Регистрация: 07.03.2011
Сообщений: 1,134
|
|
>>Хорошо, тогда давайте будем отталкиваться от Three.js. Не знаете как можно сделать очередь анимаций для Three.js?
Так же как и всегда запускать следующую анимацию после окончания предыдущей и так в порядке очереди.
Возможно у тебя возникли сложности с определением события "конец анимации"?.
Как пример простого вызова последовательных анимаций мой пост 10ти летней давности =).
https://javascript.ru/forum/misc/496...tml#post326928
|
|
10.11.2023, 09:32
|
|
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,742
|
|
Немного упростил и осовременил (с Promise и async/await)
<div id="moved" style="position: absolute;width:30px;height: 30px;background: red;"></div>
<br>
<input type="button" onclick="but1()" value="кнопка 1"> <br>
<script type="text/javascript">
function but1 (){
const element = document.getElementById("moved");
animateMove( element , 800 , 100 , 1500)
.then ( () => animateMove( element , -750 , 10 , 200) )
.then ( () => animateMove( element , 150 , -60 , 1000) )
.then ( () => {
element.style.background = ("#" + ( Math.random() * (999-100)+100 )).substr(0,4) ;
element.style.top = "30px";
element.style.left = "100px";
})
}
/* С async/await
async function but1 (){
const element = document.getElementById("moved");
await animateMove( element , 800 , 100 , 1500);
await animateMove( element , -750 , 10 , 200);
await animateMove( element , 150 , -60 , 1000);
element.style.background = ("#" + ( Math.random() * (999-100)+100 )).substr(0,4) ;
element.style.top = "30px";
element.style.left = "100px";
}
*/
function animateMove ( element , x , y , time = 1000){
const statrX = element.offsetLeft;
const startY = element.offsetTop;
const startTime = performance.now();
return new Promise ( (resolve) => {
const animate = function (timenow){
const EA = (timenow - startTime) / time;
if (EA > 1) {
resolve();
} else {
element.style.left = startX + (x * EA) + "px";
element.style.top = startY + (y * EA) + "px";
requestAnimationFrame(animate );
}
};
animate(startTime);
})
}
</script>
Последний раз редактировалось voraa, 10.11.2023 в 10:24.
|
|
10.11.2023, 14:34
|
Аспирант
|
|
Регистрация: 09.12.2021
Сообщений: 95
|
|
Я имею ввиду несколько другое понятие очереди. Например этот же код (я его немного исправил), если несколько раз нажимать на кнопку - анимация будет воспроизводится по новой. А вот каким образом сделать так, чтоб каждое нажатие на кнопку ставило запуск новой функции анимации в некую очередь, и анимация воспроизводилась одна после другой?
1 нажатие на кнопку => animate()
2 нажатие на кнопку => animate() animate()
3 нажатие на кнопку => animate(), animate(), animate()
(при условии что анимация вызванная первым нажатием ещё не завершилась)
<div id="moved" style="position: absolute;width:30px;height: 30px;background: red; pointer-events: none;"></div>
<br>
<input type="button" onclick="but1()" value="кнопка 1"> <br>
<script type="text/javascript">
function but1 (){
const element = document.getElementById("moved");
animateMove( element , 500 , 100 , 1500)
}
/* С async/await
async function but1 (){
const element = document.getElementById("moved");
await animateMove( element , 800 , 100 , 1500);
await animateMove( element , -750 , 10 , 200);
await animateMove( element , 150 , -60 , 1000);
element.style.background = ("#" + ( Math.random() * (999-100)+100 )).substr(0,4) ;
element.style.top = "30px";
element.style.left = "100px";
}
*/
function animateMove ( element , x , y , time = 1000){
const startX = element.offsetLeft;
const startY = element.offsetTop;
const startTime = performance.now();
return new Promise ( (resolve) => {
const animate = function (timenow){
const EA = (timenow - startTime) / time;
if (EA > 1) {
resolve();
} else {
element.style.translate = `${startX + (x * EA)}px ${startY + (y * EA)}px`;
requestAnimationFrame(animate);
}
};
animate(startTime);
})
}
</script>
Последний раз редактировалось Raadsert, 10.11.2023 в 14:38.
|
|
|
|