В основе проблемы лежит тот факт, что вы получаете идентификатор только первого кадра анимации (строка var aniLoop = (...)
), и это то, что вы пытаетесь отменить, за исключением того, что каждый вызов requestAnimationFrame
имеет другой идентификатор, поэтому вы 'должен сохранить возвращаемое значение последнего вызова и вместо этого отменить его:
HTMLElement.prototype.animate = function(properties,duration) {
"use strict";
var aniLoop,
prop,
last = 0,
fps = 60;
for (prop in properties) {
function ani(time) {
aniLoop = requestAnimationFrame(ani);
if ((time - last) > fps) {
last = time;
console.log(time);
if (time >= (duration * 1000)) {
cancelAnimationFrame(aniLoop);
}
}
}
aniLoop = requestAnimationFrame(ani);
}
};
Однако есть несколько других проблем с вашим кодом, которые также необходимо решить, иначе ваша функция довольно основательно взорвется:
:1 Объявление функции в цикле
Я бы рекомендовал прочитать о различиях между функциями объявление и выражение, чтобы получить лучшую картину, но проблема здесь в том, что вы выполняете объявление функции в цикле, что считается неопределенным поведением (некоторые движки заменят функции, некоторые нет, некоторые взорвут ). Учитывая, что анимациям задана только одна продолжительность и, следовательно, они, вероятно, синхронизированы, было бы лучше перебирать свойства для анимации внутри одной функции анимации, например так:
HTMLElement.prototype.animate = function(properties,duration) {
"use strict";
var aniLoop,
last = 0,
fps = 60;
function ani(time) {
var prop;
aniLoop = requestAnimationFrame(ani);
if ((time - last) > fps) {
last = time;
for (prop in properties) {
console.log(prop + ': ' + time);
}
if (time >= (duration * 1000)) {
cancelAnimationFrame(aniLoop);
}
}
}
aniLoop = requestAnimationFrame(ani);
}
:2 Отметка времени анимации
В настоящее время ваша функция анимации, вероятно, все равно не будет выполнять более одного кадра - если вы посмотрите на requestAnimationFrame documentation на MDN, вы заметите, что обратный вызов, переданный requestAnimationFrame
, получает метку времени, т. е. значение в миллисекундах с начала эпохи UNIX (1 января 1970 г.) — поэтому условие time >= (duration * 1000)
всегда будет правдой. Вместо этого зарегистрируйте время начала, когда вы запускаете анимацию, и сравните с ней отметку времени в обратном вызове, например:
HTMLElement.prototype.animate = function(properties,duration) {
"use strict";
var aniLoop,
start,
last = 0,
fps = 60;
function ani(time) {
var prop,
progress;
aniLoop = requestAnimationFrame(ani);
if ((time - last) > fps) {
last = time;
progress = time - start;
for (prop in properties) {
console.log(prop + ': ' + progress + ' out of ' + (duration * 1000));
}
// This is where we get a difference between current and starting time
if (progress >= (duration * 1000)) {
cancelAnimationFrame(aniLoop);
}
}
}
start = Date.now();
aniLoop = requestAnimationFrame(ani);
}
:3 Дросселирование анимации
Это не так важно, но все же стоит рассмотреть — requestAnimationFrame
предназначен для автоматического дросселирования и регулирования браузером, поэтому вам не нужно применять свои собственные условия относительно того, должна ли запускаться анимация (она не будет превышать 60 кадров в секунду). во всяком случае, так как это потолок спецификации). Вместо этого он должен просто работать с разницей текущего времени со временем начала, чтобы убедиться, что ваша анимация все еще заканчивается в правильном месте, даже если по какой-то причине в анимации есть задержка:
HTMLElement.prototype.animate = function(properties,duration) {
"use strict";
var aniLoop,
start;
function ani(time) {
var prop,
progress;
aniLoop = requestAnimationFrame(ani);
progress = time - start;
for (prop in properties) {
console.log(prop + ': ' + progress + ' out of ' + (duration * 1000));
}
// This is where we get a difference between current and starting time
if (progress >= (duration * 1000)) {
cancelAnimationFrame(aniLoop);
}
}
start = Date.now();
aniLoop = requestAnimationFrame(ani);
}
person
D1SoveR
schedule
19.08.2014