Поддерживает ли HTML5/Canvas двойную буферизацию?

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

Ответ 1

Следующая полезная ссылка, помимо показа примеров и преимуществ использования двойной буферизации, показывает несколько других советов по производительности для использования элемента холста html5. Он включает ссылки на тесты jsPerf, которые объединяют результаты тестирования в браузерах в базу данных браузера. Это гарантирует, что рекомендации по производительности будут проверены.

http://www.html5rocks.com/en/tutorials/canvas/performance/

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

// canvas element in DOM
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');

// buffer canvas
var canvas2 = document.createElement('canvas');
canvas2.width = 150;
canvas2.height = 150;
var context2 = canvas2.getContext('2d');

// create something on the canvas
context2.beginPath();
context2.moveTo(10,10);
context2.lineTo(10,30);
context2.stroke();

//render the buffered canvas onto the original canvas element
context1.drawImage(canvas2, 0, 0);

Ответ 2

Очень простой метод состоит в том, чтобы иметь два элемента canvas в одном и том же месте экрана и устанавливать видимость для буфера, который вам нужно показать. Нарисуйте скрытые и флип, когда закончите.

Некоторые коды:

CSS

canvas { border: 2px solid #000; position:absolute; top:0;left:0; 
visibility: hidden; }

Переключение в JS:

Buffers[1-DrawingBuffer].style.visibility='hidden';
Buffers[DrawingBuffer].style.visibility='visible';

DrawingBuffer=1-DrawingBuffer;

В этом коде массив "Буферы []" содержит оба холст-объекта. Поэтому, когда вы хотите начать рисовать, вам все равно нужно получить контекст:

var context = Buffers[DrawingBuffer].getContext('2d');

Ответ 3

Браузеры, которые я тестировал, обрабатывают эту буферизацию для вас, не перерисовывая полотно до тех пор, пока код, который рисует ваш кадр, не завершится. См. Также список рассылки WHATWG: http://www.mail-archive.com/[email protected]/msg19969.html

Ответ 4

Вы всегда можете сделать var canvas2 = document.createElement("canvas"); и не добавлять его в DOM вообще.

Просто говорю, так как вы, ребята, так одержимы display:none; это просто кажется мне более чистым и более точно имитирует идею двойного буферизации, чем просто неудобно невидимое полотно.

Ответ 5

Более двух лет спустя:

Нет необходимости "вручную" выполнять двойную буферизацию. Г-н Гири писал об этом в своей книге "HTML5 Canvas" .

Чтобы эффективно уменьшить использование мерцания requestAnimationFrame()!

Ответ 6

Для неверующих, здесь какой-то мерцающий код. Обратите внимание, что я явно очищаю, чтобы стереть предыдущий круг.

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

function draw_ball(ball) {
    ctx.clearRect(0, 0, 400, 400);
    ctx.fillStyle = "#FF0000";
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, 30, 0, Math.PI * 2, true);
    ctx.closePath();
    ctx.fill();
}

var deltat = 1;
var ball = {};
ball.y = 0;
ball.x = 200;
ball.vy = 0;
ball.vx = 10;
ball.ay = 9.8;
ball.ax = 0.1;

function compute_position() {
    if (ball.y > 370 && ball.vy > 0) {
        ball.vy = -ball.vy * 84 / 86;
    }
    if (ball.x < 30) {
        ball.vx = -ball.vx;
        ball.ax = -ball.ax;
    } else if (ball.x > 370) {
        ball.vx = -ball.vx;
        ball.ax = -ball.ax;
    }
    ball.ax = ball.ax / 2;
    ball.vx = ball.vx * 185 / 186;
    ball.y = ball.y + ball.vy * deltat + ball.ay * deltat * deltat / 2
    ball.x = ball.x + ball.vx * deltat + ball.ax * deltat * deltat / 2
    ball.vy = ball.vy + ball.ay * deltat
    ball.vx = ball.vx + ball.ax * deltat
    draw_ball(ball);
}

setInterval(compute_position, 40);
<!DOCTYPE html>
<html>
<head><title>Basketball</title></head>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
</body></html>

Ответ 7

Джош спросил (некоторое время назад) о том, как браузер знает "когда процесс рисования заканчивается", чтобы избежать мерцания. Я бы сразу прокомментировал его сообщение, но мой представитель не достаточно высок. И это только мое мнение. У меня нет фактов, чтобы поддержать это, но я чувствую себя довольно уверенно в этом, и может быть полезно другим, читающим это в будущем.

Я предполагаю, что браузер не "знает", когда вы закончите рисовать. Но, как и большинство javascript, пока ваш код работает без отказа от управления браузером, браузер по существу заблокирован и не сможет/не сможет обновить/отреагировать на свой пользовательский интерфейс. Я предполагаю, что если вы очистите холст и нарисуете весь свой кадр без отказа от управления браузером, он не нарисует ваш холст, пока вы не закончите.

Если вы настроите ситуацию, когда ваш рендеринг охватывает несколько вызовов setTimeout/setInterval/requestAnimationFrame, где вы очищаете холст в одном вызове и рисуете элементы на вашем холсте в следующих нескольких вызовах, повторяя цикл (например) каждые 5 звонки, я готов поспорить, что вы увидите мерцание, поскольку полотно будет обновляться после каждого вызова.

Тем не менее, я не уверен, что буду этому доверять. Мы уже находимся в точке, когда javascript скомпилирован до собственного машинного кода перед исполнением (по крайней мере, то, что движок Chrome V8 делает из того, что я понимаю). Я бы не удивился, если бы не было слишком много времени, прежде чем браузеры запустили javascript в отдельном потоке из пользовательского интерфейса и синхронизировали любой доступ к элементам пользовательского интерфейса, позволяя пользовательскому интерфейсу обновлять/реагировать во время выполнения javascript, который не имел доступа к пользовательскому интерфейсу. Когда/если это произойдет (и я понимаю, что нужно преодолеть много препятствий, таких как обработчики событий, когда вы еще запускаете другой код), мы, вероятно, увидим мерцание на анимации холста, которые не используются некоторая двойная буферизация.

Лично мне нравится идея двух элементов холста, расположенных поверх друг друга и чередующихся, которые показываются/рисуются на каждом кадре. Довольно неинтрузивный и, вероятно, довольно легко добавляется в существующее приложение с несколькими строками кода.

Ответ 8

В веб-браузерах нет мерцания! Они уже используют dbl-буферизацию для их рендеринга. Js движок сделает весь ваш рендеринг, прежде чем показывать его. Кроме того, контекст сохраняет и восстанавливает только данные матрицы трансформации стека и, таким образом, не сам контент холста. Итак, вам не нужна или нужна буфера dbl!

Ответ 9

Вместо того, чтобы кататься самостоятельно, вы, вероятно, получите лучший пробег, используя существующую библиотеку для создания чистой анимации JavaScript без фликкера:

Здесь популярный: http://processingjs.org

Ответ 10

Opera 9.10 работает очень медленно и показывает процесс рисования. Если вы хотите, чтобы браузер не использовал двойную буферизацию, попробуйте использовать Opera 9.10.

Некоторые люди предположили, что браузеры каким-то образом определяют, когда заканчивается процесс рисования, но можете ли вы объяснить, как это может работать? Я не заметил каких-либо очевидных мерцаний в Firefox, Chrome или IE9, даже когда рисунок медленный, поэтому кажется, что это то, что они делают, но как это делается, для меня загадка. Как браузер когда-либо узнает, что он обновляет дисплей перед тем, как будут выполнены другие инструкции по рисованию? Считаете ли вы, что они просто время это так, если интервал более 5 мс или около того идет без выполнения инструкции рисования холста, он предполагает, что он может безопасно менять буфер?

Ответ 11

вам нужно 2 холста: (обратите внимание на css z-index и position: absolute)

<canvas id="layer1" width="760" height="600" style=" position:absolute; top:0;left:0; 
visibility: visible;  z-index: 0; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<canvas id="layer2" width="760" height="600" style="position:absolute; top:0;left:0; 
visibility: visible;  z-index: 1; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>

вы можете заметить, что первый холст виден, а второй скрывает идею его рисования на скрытом, после чего мы спрячем видимость и сделаем скрытый холст видимым. когда он скрыт "ясный скрытый холст

<script type="text/javascript">
var buff=new Array(2);
buff[0]=document.getElementById("layer1");
buff[1]=document.getElementById("layer2");

ctx[0]=buff[0].getContext("2d");
ctx[1]=buff[1].getContext("2d");
var current=0;
// draw the canvas (ctx[ current ]);
buff[1- current ].style.visibility='hidden';
buff[ current ].style.visibility='visible';
ctx[1-current].clearRect(0,0,760,600);
current =1-current;

Ответ 12

В большинстве ситуаций вам не нужно это делать, браузер реализует это для вас. Но не всегда полезно!

Вам все еще нужно реализовать это, когда ваш рисунок очень сложный. Большая часть скорости обновления экрана составляет около 60 Гц, это означает обновление экрана за 16 мс. Скорость обновления браузера может приближаться к этому числу. Если вам нужна форма 100 мс, вы увидите незавершенную форму. Таким образом, вы можете реализовать двойную буферизацию в этой ситуации.

Я сделал тест: Clear a rect, wait for some time, then fill with some color. Если я установил время до 10 мс, я не увижу мерцание. Но если я установил его на 20 мс, произойдет мерцание.