Анимация временной шкалы JavaScript (проблемы точности setTimeout) - PullRequest
1 голос
/ 19 августа 2011

Я начал писать простой класс анимации в JS, который использует возможности анимации Zepto.js, но добавляет к нему возможность, подобную временной шкале.

Сама шкала времени представляет собой простой массив, который выполняет встроенные в него функции при вызове функции play ():

play : function(callback){

        for(var i=0; i<Animator.timeline.buffer.length; i++){

            Animator.timeline.buffer[i].animation();

        }

        if(callback){
            callback();
        }

    }

setTimeout идет прямо в анимации:

alpha : function(parameters, callback, delay){

    var target = parameters.target;
    var duration = parameters.duration;
    var easing = parameters.easing;
    var value = parameters.value;

    if(delay){
        setTimeout(function(){run();},delay*1000);
    } else {
        run();
    }

    function run(){
        $(target).anim({opacity:value},duration,easing);
        if(callback){
            callback();
        }
    }


}

Таким образом, по сути, временная шкала просто запускает функции setTimeout-ed, которые помещаются в ее буферный массив.

Этот подход работает (почти) как и предполагалось с анимациями WebKit, но я столкнулся с несколькими проблемами при выполнении последовательностей изображений (анимации с использованием setInterval, которые изменяют src изображения). Поскольку таймеры JS не гарантируют выполнение в назначенное время, иногда анимации запускаются с опозданием, вероятно из-за встроенного в них setInterval.

Есть идеи, как это решить? Я знаю, что встраивание всех анимаций как обратных вызовов друг в друга решило бы большую часть проблем, но я действительно не знаю, как это сделать из цикла временной шкалы. Кроме того, это быстро станет нечитаемым беспорядком обратных вызовов, если я вызову все функции прямым способом (без использования временной шкалы).

Для справки: функция последовательности моего класса аниматоров:

sequence : function(parameters, callback, delay){

    var target = parameters.target;
    var path = parameters.path;
    var baseName = parameters.baseName;
    var digits = parameters.digits;
    var extension = parameters.extension;
    var frames = parameters.frames;
    var loop = parameters.loop;

    if(parameters.interval){
        var _interval = parameters.interval
    } else {
        var _interval = 15;
    }


    var currentFrame = 0;
    var imageUrl = '';

    var fileName = baseName;

    for(var i=0; i<=digits; i++){
        fileName+='0';
    }

    if(delay){
        setTimeout(function(){runSequence();},delay*1000);
    } else {
        runSequence();
    }

    function runSequence(){

        var interval = setInterval(function(){

        if(currentFrame >= frames){
            currentFrame = 0;
            if(!loop) {
                clearInterval(interval);
                if(callback){
                    callback();
                }
            }
        } else {
            imageUrl = path+fileName.substring(0, fileName.length-currentFrame.toString().length)+currentFrame+"."+extension;
            $(target).attr('src',imageUrl);
            currentFrame++;
        }

    },_interval);

    }

}

Также пример анимации, созданной с помощью этого класса:

Animator.timeline.append(function(){
                Animator.alpha({'target':'#logo', 'value':1, 'duration':1, 'easing':'ease-out' });
            });

            Animator.timeline.append(function(){
                 Animator.sequence({'target':'#sequence', 'path':'images/sequences/index/', 'baseName':'nr1_', 'digits':3, 'extension':'png', 'frames':50},'',1.5);
            });

            Animator.timeline.append(function(){
                Animator.scale({'target':'#text', 'width':.5, 'height':.15, 'duration':1, 'easing':'ease-in-out'},'',3.2);
            });

             Animator.timeline.append(function(){
                Animator.alpha({'target':'#link', 'value':1, 'duration':1,'easing':'ease-out'},'',4.7);
            });

            Animator.timeline.play();

В качестве дополнительной заметки я намеревался создать нечто похожее на GreenSock в AS3, если это поможет.

Спасибо.

1 Ответ

1 голос
/ 01 сентября 2011

Точный setInterval можно смоделировать, компенсируя время, затрачиваемое на выполнение каждой итерации, может быть, эта суть, которую я написал, может вам помочь:

...