Плавная анимация холста

Я пытаюсь научиться создавать плавные анимации JavaScript с использованием холста HTML5. Почему-то анимация не плавная, а какая-то "забрызгиваемая".

Вы можете увидеть структуру, которую я построил на этот jsFiddle, который на данный момент использует только свойства Webkit.

Другой разработчик смог создать ту же концепцию, используя исходный код WebView, основанный на Ext.js. В учебных целях я хотел избежать использования каких-либо библиотек, чтобы лучше понять JavaScript. С концепцией WebViews можно ознакомиться по адресу этот jsFiddle, который показывает гораздо более плавную анимацию.

Я читал и пробовал всевозможные сценарии: от извлечения вызовов update из requestAnimationFrame в свой собственный цикл до перевода контекста в позицию отрисовки, отрисовки в контекст заднего буфера и копирования его в окно просмотра. Следующий код представляет мои лучшие усилия до сих пор.

Есть предложения по улучшению производительности, чтобы объект двигался плавно без дополнительных затрат на внешнюю библиотеку?

Заранее спасибо.

var app;
var now = then = delta = 0;
var viewport = document.createElement( 'canvas' );
var viewportContext = viewport.getContext( '2d' );

function App( )
{
    this.circle = {
        position : viewport.width / 2,
        radius : 10
    };
}

App.prototype.initialize = function( )
{
    app = this;
    document.body.appendChild( viewport );
    viewport.width = 320;
    viewport.height = 200;

    webkitRequestAnimationFrame( app.render, viewport );
};

App.prototype.render = function( )
{
    now = performance.webkitNow( );
    delta = ( now - then ) / 1000.0;
    then = now;

    app.update( delta );
    viewportContext.clearRect( 0, 0, viewport.width, viewport.height );
    app.draw( viewportContext );

    webkitRequestAnimationFrame( app.render, viewport );
};

App.prototype.draw = function( context )
{
    context.fillStyle = "white";
    context.beginPath( );
    context.arc( this.circle.position | 0, viewport.height / 2 | 0, this.circle.radius | 0, 0, Math.PI * 2, true );
    context.closePath( );
    context.fill( );
};

App.prototype.update = function( deltaTime )
{
    this.circle.position += viewport.width / 5 * deltaTime;

    if( this.circle.position >= viewport.width )
    {
        this.circle.position = 0;
    }
};

window.onload = function( )
{
    new App( ).initialize( );
};​

person Jeff Jenkins    schedule 25.09.2012    source источник
comment
Работает гладко для меня. При этом вы можете профилировать свое приложение, посетив инструменты разработчика F12 и проверив параметры профилирования — это покажет вам, какие части вашего приложения потребляют больше всего ресурсов и времени.   -  person Sampson    schedule 25.09.2012
comment
Я не вижу существенной разницы в плавности вашей демонстрации по сравнению с вашей демонстрацией WebViews. Я использую Chrome 21.0.1180.89 м.   -  person Seth Flowers    schedule 25.09.2012
comment
Хммм...любая разница есть разница, и для моей демки она не очень заметна, но она есть. Я использую ту же версию Chrome, и я безрезультатно пытался понять профили кучи и временную шкалу памяти в инструментах разработчика. Тот факт, что я не могу добиться такого же уровня точности, как в демо-версии WebViews, сводит меня с ума.   -  person Jeff Jenkins    schedule 25.09.2012
comment
Кроме того, на этой странице содержится масса информации по этому вопросу.   -  person Shmiddty    schedule 25.09.2012
comment
Обратите внимание на улучшенную гладкость: jsfiddle.net/3TAVu/1 Не имеет смысла, но я считаю, что это связано с размером холста.   -  person Shmiddty    schedule 25.09.2012
comment
@Shmiddty, это странно, но, похоже, это влияет на производительность. Кажется, единственный раз, когда он прыгает вперед, это когда происходит сборка мусора, что также не имеет смысла, учитывая, что не должно создаваться никакого мусора. Опять же, в настоящее время я не совсем понимаю GC в JavaScript.   -  person Jeff Jenkins    schedule 26.09.2012
comment
@MrSlayer Холст отслеживает изменения своего состояния (например, fillStyle/и т. д.), так что это может быть мусор, который необходимо собрать.   -  person Shmiddty    schedule 26.09.2012
comment
Это тоже имело бы смысл. Большое спасибо за понимание. Если вы предпочитаете создать ответ из своих комментариев, я с радостью приму его.   -  person Jeff Jenkins    schedule 26.09.2012


Ответы (2)


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

Кроме того, по какой-то причине производительность увеличивается на более «среднем» холсте. Я не совсем уверен, почему это так, но я думаю, что это связано с оптимизацией браузера.

Вы можете отметить некоторый прирост производительности с помощью нескольких небольших настроек здесь: http://jsfiddle.net/3TAVu/1/< /а>

В частности, я удалил лишнее назначение fillStyle здесь:

App.prototype.draw = function( context )
{
    context.beginPath( );
    context.arc( this.circle.position | 0, viewport.height / 2 | 0, this.circle.radius | 0, 0, Math.PI * 2, true );
    context.closePath( );
    context.fill( );
};

Я также изменил метод рендеринга, очистив только соответствующую часть холста, а не весь:

App.prototype.render = function( )
{
    now = performance.webkitNow( );
    delta = ( now - then ) / 1000.0;
    then = now;

    var cX = app.circle ? (app.circle.position - app.circle.radius) : 0;
    var cY = Math.round(viewport.height/2) - app.circle.radius;
    var w = app.circle ? app.circle.radius * 2 : 0;

    viewportContext.clearRect(cX - 1, cY - 1, w + 2, w + 2);

    app.update( delta );
    app.draw( viewportContext );

    webkitRequestAnimationFrame( app.render, viewport );
};
person Shmiddty    schedule 25.09.2012
comment
Спасибо за вашу помощь, @Shmiddty. Я думаю, что у меня достаточно, чтобы перейти отсюда и продолжить работу с фреймворком. Скорее всего, мне придется добавить обратно полную очистку холста, учитывая, что сцены, как правило, будут более интересными, чем мяч, движущийся по горизонтали. Также спасибо за ссылку на документы. Я уже прочитал большую часть этого материала, но мне, возможно, придется просмотреть еще раз, так как я немного перегружен информацией. - person Jeff Jenkins; 26.09.2012
comment
Конечно вещь. Обычно я нахожу это занятие очень забавным. - person Shmiddty; 26.09.2012

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

person Sujit Y. Kulkarni    schedule 06.06.2013