Отметка времени, передаваемая обратному вызову requestAnimationFrame
, представляет собой DOMHighResTimestamp, аналогичную отметке, возвращаемой performance.now()
.
Эта временная метка указывает количество миллисекунд, прошедших с начала времени жизни текущего документа (ну, может быть немного сложнее ), когда началось выполнение обратных вызовов.
Таким образом, даже если не выполняется цикл requestAnimationFrame , эта временная метка действительно увеличивается, как и Date.now()
.
В вашем коде вы, вероятно, захотите сохранить только время, прошедшее с последнего кадра. Для этого вы можете просто сохранить timestamp
в глобальной переменной, а затем в обратном вызове сделать
var elapsed = timestamp - last_frame;
last_frame = timestamp;
И не забудьте также позаботиться о случае возобновления, где timestamp
будет неопределенным, а elapsed
должно быть сброшено.
Теперь я хотел бы отметить, что ваше описание проблемы может также указывать на совершенно другую проблему: у вас может быть одновременно запущено более одного цикла.
Поскольку вы используете одну переменную animation
для хранения frame_id (используется для cancelAnimationFrame), если вы вызовете rotateCamera
, когда цикл уже запущен, первые frame_ids будут потеряны, а их цикл rAF действительно продолжить.
let common_id = 0; // OP's `animation` variable
let first_id = 0;
let second_id = 0;
function loop1(timestamp) {
common_id = first_id = requestAnimationFrame(loop1);
log_1.textContent = "loop 1: " + timestamp;
}
function loop2(timestamp) {
common_id = second_id = requestAnimationFrame(loop2);
log_2.textContent = "loop 2: " + timestamp;
}
btn.onclick = e => {
console.log("first loop's id", first_id);
console.log("second loop's id", second_id);
console.log('clearing common_id', common_id);
cancelAnimationFrame(common_id);
}
loop1();
loop2();
Я думаю, что это возможно в вашем коде, поскольку input[name='camerarotation-selection']
может меняться несколько раз, когда input[name='selection']
не был изменен или даже если input[name='camerarotation-selection']
может быть несколькими элементами.
Чтобы избежать этого, вы можете сохранить переменную семафора, позволяющую вам знать, работает цикл или нет, и запускать его только тогда, когда он не работает.
Или вы могли бы полностью избавиться от cancelAnimationFrame
, используя только один семафор и выйдя из него в начале обратного вызова rAF:
let stopped = true;
function loop(timestamp) {
if (stopped) return; // exit early
requestAnimationFrame(loop);
log.textContent = timestamp;
}
// you can click it several times
btn_start.onclick = e => {
if (stopped === true) { // only if not running yet
stopped = false;
requestAnimationFrame(loop);
}
}
btn_stop.onclick = e => {
stopped = true; // deal only with the semaphore
};
btn_switch.onclick = e => {
stopped = !stopped;
if (stopped === false) { // we were paused
// start again
requestAnimationFrame(loop);
}
}