O HTML5 / Canvas suporta buffer duplo?

O que eu gostaria de fazer é desenhar meus charts em um buffer e depois copiá-los como estão na canvas para que eu possa fazer animações e evitar tremulações. Mas não consegui encontrar essa opção. Alguém sabe como eu posso fazer isso?

O seguinte link útil, além de mostrar exemplos e vantagens de usar o buffer duplo, mostra várias outras dicas de desempenho para usar o elemento de canvas html5. Inclui links para testes jsPerf, que agregam resultados de teste em navegadores em um database do Browserscope. Isso garante que as dicas de desempenho sejam verificadas.

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

Para sua conveniência, incluí um exemplo mínimo de buffer duplo efetivo, conforme descrito no artigo.

 // 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); 

Um método muito simples é ter dois elementos da canvas na mesma localização da canvas e definir a visibilidade para o buffer que você precisa mostrar. Desenhe no oculto e vire quando terminar.

Algum código:

CSS:

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

Inversão no JS:

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

Nesse código, a matriz ‘Buffers []’ contém os dois objects de canvas. Então, quando você quer começar a desenhar, você ainda precisa obter o contexto:

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

Os navegadores que testei lidam com esse buffer por você, não repintando a canvas até que o código que desenha o quadro seja concluído. Veja também a lista de discussão do WHATWG: http://www.mail-archive.com/whatwg@lists.whatwg.org/msg19969.html

Você sempre pode fazer var canvas2 = document.createElement("canvas"); e não anexá-lo ao DOM.

Apenas dizendo que vocês parecem tão obcecados com a display:none; parece apenas mais limpo para mim e imita a ideia do buffer duplo com mais precisão do que apenas ter uma canvas estranhamente invisível.

Mais de dois anos depois:

Não há necessidade de implementar manualmente o buffer duplo. O Sr. Geary escreveu sobre isso em seu livro “HTML5 Canvas” .

Para reduzir efetivamente o uso de cintilação requestAnimationFrame() !

Para os incrédulos, aqui está um código de cintilação. Note que estou limpando explicitamente para apagar o círculo anterior.

http://coderextreme.net/basketball2.html ( http://jsfiddle.net/GzSWJ/ )

 < !DOCTYPE html>  Basketball   Your browser does not support the canvas element.   

Josh perguntou (há um tempo atrás) sobre como o navegador sabe “quando o processo de desenho termina”, de modo a evitar a cintilação. Eu teria comentado diretamente para o seu post, mas o meu representante não é alto o suficiente. Também esta é apenas a minha opinião. Eu não tenho fatos para sustentar isso, mas me sinto bastante confiante sobre isso e pode ser útil para os outros lerem isso no futuro.

Eu estou supondo que o navegador não “sabe” quando você terminar de desenhar. Mas, assim como a maioria dos javascript, contanto que seu código seja executado sem renunciar ao controle do navegador, o navegador é basicamente bloqueado e não atualiza / não responde à interface do usuário. Eu estou supondo que se você limpar a canvas e desenhar todo o seu quadro sem abrir mão do controle para o navegador, ele não vai realmente desenhar sua canvas até que você esteja pronto.

Se você configurar uma situação em que sua renderização abranja várias chamadas setTimeout / setInterval / requestAnimationFrame, onde você limpa a canvas em uma chamada e desenha elementos em sua canvas nas próximas chamadas, repetindo o ciclo (por exemplo) a cada 5 chamadas, estaria disposto a apostar que você veria flicker, já que a canvas seria atualizada após cada chamada.

Dito isso, não tenho certeza se confiaria nisso. Já estamos no ponto em que o javascript é compilado no código nativo da máquina antes da execução (pelo menos é o que o mecanismo V8 do Chrome faz do que eu entendo). Eu não ficaria surpreso se não demorasse muito para que os navegadores começassem a executar seu javascript em um thread separado da interface do usuário ea sincronizar qualquer access aos elementos da interface do usuário, permitindo que a interface do usuário atualizasse / respondesse durante a execução do javascript que não estava acessando a interface do usuário. Quando / se isso acontecer (e eu entendi que há muitos obstáculos que precisam ser superados, como o início dos manipuladores de events enquanto você ainda está executando outro código), provavelmente veremos o flicker na animação de canvas que não está usando algum tipo de buffer duplo.

Pessoalmente, adoro a ideia de dois elementos da canvas posicionados em cima uns dos outros e alternando o que é mostrado / desenhado em cada quadro. Bastante não intrusivo e, provavelmente, muito fácil de adicionar a um aplicativo existente com algumas linhas de código.

Não há oscilação nos navegadores da web! Eles já usam o buffer dbl para sua renderização. O mecanismo Js fará toda a sua renderização antes de mostrá-la. Além disso, o contexto salva e restaura apenas os dados da matriz transformadora da pilha e tal, não o próprio conteúdo da canvas. Então, você não precisa nem quer dbl buffering!

Em vez de usar a sua própria, você provavelmente obterá a melhor quilometragem usando uma biblioteca existente para criar animações JavaScript limpas e sem oscilações:

Aqui está um dos mais populares: http://processingjs.org

O Opera 9.10 é muito lento e mostra o processo de desenho. Se você quiser ver um navegador não usar o buffer duplo, experimente o Opera 9.10 out.

Algumas pessoas sugeriram que os navegadores são de alguma forma determinantes quando o processo de desenho termina, mas você pode explicar como isso funciona? Eu não notei nenhuma cintilação óbvia no Firefox, Chrome ou IE9, mesmo quando o desenho está lento, então parece que é isso que eles estão fazendo, mas como isso é feito é um mistério para mim. Como o navegador saberia que está atualizando a exibição antes que mais instruções de desenho sejam executadas? Você acha que eles apenas o tempo assim, se um intervalo de mais de 5ms ou mais passa sem executar uma instrução de desenho de canvas, ele assume que pode com segurança trocar buffers?

você precisa de 2 canvas: (observe o z-index e a posição css: absolute)

  Your browser does not support the canvas element.   Your browser does not support the canvas element.  

você pode notar que a primeira canvas é visível e a segunda é escondida a idéia é desenhar no oculto depois disso, vamos esconder o visível e tornar a canvas oculta visível. quando está oculto “limpar a canvas escondida

  

Na maioria das situações, você não precisa fazer isso, o navegador implementa isso para você. Mas nem sempre é útil!

Você ainda tem que implementar isso quando seu desenho é muito complicado. A maior parte da taxa de atualização de canvas é de cerca de 60Hz, ou seja, as atualizações de canvas por 16ms. A taxa de atualização do navegador pode se aproximar desse número. Se sua forma precisar de 100ms para ser concluída, você verá uma forma incompleta. Assim, você pode implementar o buffer duplo nessa situação.

Fiz um teste: Clear a rect, wait for some time, then fill with some color. Se eu definir o tempo para 10 ms, não vou ver piscando. Mas se eu configurá-lo para 20ms, a oscilação acontece.