HTML5 Canvas vs. SVG vs. div

Qual é a melhor abordagem para criar elementos na hora e ser capaz de movê-los? Por exemplo, digamos que eu queira criar um retângulo, um círculo e um polígono e, em seguida, selecioná-los e movê-los.

Eu entendo que o HTML5 fornece três elementos que podem tornar isso possível: svg , canvas e div . Para o que eu quero fazer, qual desses elementos fornecerá o melhor desempenho?

Para comparar essas abordagens, eu estava pensando em criar três páginas da web visualmente idênticas, cada uma delas contendo um conteúdo de header, rodapé, widget e texto. O widget na primeira página seria criado inteiramente com o elemento canvas , o segundo inteiramente com o elemento svg e o terceiro com o elemento div simples, HTML e CSS.

A resposta curta:

O SVG seria mais fácil para você, já que a seleção e a movimentação já estão incorporadas. Objetos SVG são objects DOM, portanto, eles têm manipuladores de “clique”, etc.

DIVs estão bem, mas desajeitados e têm um desempenho horrível carregando em grandes números.

O Canvas tem o melhor desempenho, mas você precisa implementar todos os conceitos de estado gerenciado (seleção de objects, etc) ou usar uma biblioteca.


A resposta longa:

O HTML5 Canvas é simplesmente uma superfície de desenho para um mapa de bits. Você configura para desenhar (Diga com uma espessura de cor e linha), desenhe essa coisa, e então o Canvas não tem conhecimento disso: ele não sabe onde está ou o que você acabou de desenhar, é apenas pixels. Se você quiser desenhar retângulos e fazer com que eles se movam ou sejam selecionáveis, você terá que codificar tudo isso desde o início, incluindo o código para lembrar que você os desenhou.

Por outro lado, o SVG deve manter referências a cada object renderizado. Todo elemento SVG / VML que você cria é um elemento real no DOM. Por padrão, isso permite que você mantenha um controle muito melhor dos elementos que você cria e faz com que lidar com coisas como events de mouse seja mais fácil por padrão, mas diminui significativamente quando há um grande número de objects

Essas referências DOM do SVG significam que parte do trabalho de lidar com as coisas que você desenha é feito para você. E o SVG é mais rápido ao renderizar objects realmente grandes , mas mais lento ao renderizar muitos objects.

Um jogo provavelmente seria mais rápido no Canvas. Um enorme programa de mapas provavelmente seria mais rápido no SVG. Se você quiser usar o Canvas, eu tenho alguns tutoriais sobre como colocar objects móveis em funcionamento aqui .

O Canvas seria melhor para coisas mais rápidas e manipulação pesada de bitmap (como animação), mas tomará mais código se você quiser muita interatividade.

Eu corri um monte de números em desenho HTML feito por DIV versus desenho em canvas. Eu poderia fazer um post enorme sobre os benefícios de cada um, mas vou dar alguns dos resultados relevantes dos meus testes para considerar para sua aplicação específica:

Eu fiz as páginas de teste Canvas e HTML DIV, ambas tinham “nós” móveis. Os nós de canvas eram objects que criei e mantive em JavaScript. Os nós HTML eram divs móveis.

Eu adicionei 100.000 nós para cada um dos meus dois testes. Eles tiveram um desempenho bem diferente:

A guia de teste de HTML levou uma eternidade para carregar (cronometrada em pouco menos de 5 minutos, chrome pediu para matar a página pela primeira vez). O gerenciador de tarefas do Chrome diz que essa guia está ocupando 168MB. Demora 12-13% do tempo de CPU quando estou olhando para ele, 0% quando não estou olhando.

A guia Canvas carregada em um segundo e ocupa 30MB. Ele também ocupa 13% do tempo da CPU o tempo todo, independentemente de estar ou não olhando para ele. (Edição de 2013: Eles basicamente corrigiram isso)

Arrastar a página HTML é mais suave, o que é esperado pelo design, já que a configuração atual é redesenhar TUDO a cada 30 milissegundos no teste da canvas. Existem muitas otimizações para o Canvas para isso. (invalidação de canvas sendo a mais fácil, também regiões de recorte, redesenho seletivo, etc. depende do quanto você deseja implementar)

Não há dúvida de que você poderia fazer com que o Canvas seja mais rápido na manipulação de objects que os divs nesse teste simples e, claro, muito mais rápido no tempo de carregamento. O desenho / carregamento é mais rápido no Canvas e tem muito mais espaço para otimizações também (ou seja, excluir objects que estão fora da canvas é muito fácil).

Conclusão:

  • O SVG provavelmente é melhor para aplicativos e aplicativos com poucos itens (menos de 1000? Depende mesmo)
  • Canvas é melhor para milhares de objects e manipulação cuidadosa, mas muito mais código (ou biblioteca) é necessário para tirá-lo do chão.
  • As Divs HTML são desajeitadas e não escalonam, fazendo com que um círculo só seja possível com cantos arredondados, fazendo com que formas complexas sejam possíveis, mas envolvendo centenas de minúsculos divs de tamanho de pixel. A loucura segue.

Para adicionar a isso, eu tenho feito um aplicativo de diagrama e, inicialmente, comecei com canvas. O diagrama consiste em muitos nós e eles podem ficar bastante grandes. O usuário pode arrastar elementos no diagrama ao redor.

O que eu descobri foi que no meu Mac, para imagens muito grandes, o SVG é superior. Eu tenho um MacBook Pro 2013 13 “Retina, e corre o violino abaixo muito bem. A imagem é 6000×6000 pixels, e tem 1000 objects. Uma construção semelhante na canvas era impossível para animar para mim quando o usuário estava arrastando objects ao redor do diagrama.

Nos monitores modernos, você também precisa considerar diferentes resoluções, e aqui o SVG oferece tudo isso gratuitamente.

Violino: http://jsfiddle.net/knutsi/PUcr8/16/

Fullscreen: http://jsfiddle.net/knutsi/PUcr8/16/embedded/result/

 var wiggle_factor = 0.0; nodes = []; // create svg: var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute('style', 'border: 1px solid black'); svg.setAttribute('width', '6000'); svg.setAttribute('height', '6000'); svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink"); document.body.appendChild(svg); function makeNode(wiggle) { var node = document.createElementNS("http://www.w3.org/2000/svg", "g"); var node_x = (Math.random() * 6000); var node_y = (Math.random() * 6000); node.setAttribute("transform", "translate(" + node_x + ", " + node_y +")"); // circle: var circ = document.createElementNS("http://www.w3.org/2000/svg", "circle"); circ.setAttribute( "id","cir") circ.setAttribute( "cx", 0 + "px") circ.setAttribute( "cy", 0 + "px") circ.setAttribute( "r","100px"); circ.setAttribute('fill', 'red'); circ.setAttribute('pointer-events', 'inherit') // text: var text = document.createElementNS("http://www.w3.org/2000/svg", "text"); text.textContent = "This is a test! ÅÆØ"; node.appendChild(circ); node.appendChild(text); node.x = node_x; node.y = node_y; if(wiggle) nodes.push(node) return node; } // populate with 100 nodes: for(var i = 0; i < 1000; i++) { var node = makeNode(true); svg.appendChild(node); } // make one mapped to mouse: var bnode = makeNode(false); svg.appendChild(bnode); document.body.onmousemove=function(event){ bnode.setAttribute("transform","translate(" + (event.clientX + window.pageXOffset) + ", " + (event.clientY + window.pageYOffset) +")"); }; setInterval(function() { wiggle_factor += 1/60; nodes.forEach(function(node) { node.setAttribute("transform", "translate(" + (Math.sin(wiggle_factor) * 200 + node.x) + ", " + (Math.sin(wiggle_factor) * 200 + node.y) + ")"); }) },1000/60); 

Eu concordo com as conclusões de Simon Sarris:

Eu comparei algumas visualizações em Protovis (SVG) a Processingjs (Canvas), que exibem> 2000 pontos e processamentojs é muito mais rápido do que protovis.

Manipular events com SVG é, claro, muito mais fácil porque você pode anexá-los aos objects. No Canvas você tem que fazer isso manualmente (verifique a posição do mouse, etc), mas para uma interação simples, não deve ser difícil.

Há também a biblioteca dojo.gfx do kit de ferramentas do dojo. Ele fornece uma camada de abstração e você pode especificar o renderizador (SVG, Canvas, Silverlight). Isso também pode ser uma opção viável, embora eu não saiba quanta sobrecarga a camada de abstração adicional adiciona, mas facilita o código de interações e animações e é independente de renderizador.

Aqui estão alguns benchmarks interessantes:

Conhecer as diferenças entre o SVG e o Canvas seria útil para selecionar o caminho certo.

Tela de pintura

  • Resolução dependente
  • Não há suporte para manipuladores de events
  • Capacidades de renderização de texto insatisfatórias
  • Você pode salvar a imagem resultante como .png ou .jpg
  • Adequado para jogos intensivos em charts

SVG

  • Resolução independente
  • Suporte para manipuladores de events
  • Mais adequado para aplicativos com grandes áreas de renderização (Google Maps)
  • Renderização lenta se complexa (qualquer coisa que use muito o DOM será lenta)
  • Não é adequado para aplicação no jogo

Apenas meus 2 centavos em relação à opção divs.

Famous / Infamous e SamsaraJS (e possivelmente outros) usam divs não-nesteds absolutamente posicionados (com conteúdo HTML / CSS não-trivial), combinados com matrix2d / matrix3d ​​para posicionamento e transformações 2D / 3D, e atingem 60FPS estáveis ​​em hardware móvel moderado , então eu argumentaria contra os divs sendo uma opção lenta.

Há uma abundância de gravações de canvas no Youtube e em outros lugares, de material 2D / 3D de alto desempenho rodando no navegador com tudo sendo um elemento DOM no qual você pode Inspecionar Elemento , a 60FPS (misturado com WebGL para certos efeitos, mas não para o parte principal da renderização).

Para seus propósitos, recomendo usar SVG, já que você recebe events DOM, como manuseio de mouse, incluindo arrastar e soltar, incluído, não precisa implementar seu próprio redesenho e não precisa acompanhar o estado de seus objects. Use o Canvas quando você precisar manipular imagens de bitmap e usar um div regular quando quiser manipular o material criado em HTML. Quanto ao desempenho, você descobrirá que os navegadores modernos estão acelerando todos os três, mas essa canvas recebeu a maior atenção até o momento. Por outro lado, o quão bem você escreve seu javascript é fundamental para obter o máximo de desempenho com o canvas, então eu ainda recomendo usar o SVG.

Embora ainda haja alguma verdade na maioria das respostas acima, acho que elas merecem uma atualização:

Ao longo dos anos, o desempenho do SVG melhorou muito e agora há transições CSS animadas por hardware e animações para SVG que não dependem do desempenho do JavaScript. Obviamente, o desempenho do JavaScript também melhorou e, com ele, o desempenho do Canvas, mas não tanto quanto o SVG foi aprimorado. Também há um “novo garoto” no bloco que está disponível em quase todos os navegadores hoje e que é o WebGL . Para usar as mesmas palavras que o Simon usou acima: bate as mãos Canvas e SVG . Isso não significa que deva ser a tecnologia de ponta, já que é uma fera para se trabalhar e só é mais rápido em casos de uso muito específicos.

IMHO para a maioria dos casos de uso hoje, o SVG oferece a melhor relação desempenho / usabilidade. As visualizações precisam ser realmente complexas (com relação ao número de elementos) e realmente simples ao mesmo tempo (por elemento) para que o Canvas e ainda mais o WebGL realmente brilhem.

Nesta resposta a uma pergunta semelhante estou fornecendo mais detalhes, porque eu acho que a combinação das três tecnologias às vezes é a melhor opção que você tem.

Enquanto pesquisava, encontrei uma boa explicação sobre o uso e a compactação do SVG e do Canvas em http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html

Espero que ajude:

  • O SVG, como o HTML, usa a renderização retida : quando queremos desenhar um retângulo na canvas, usamos declarativamente um elemento em nosso DOM. O navegador desenhará um retângulo, mas também criará um object SVGRectElement na memory que representa o retângulo. Esse object é algo que fica ao nosso redor para manipular – é mantido. Podemos atribuir diferentes posições e tamanhos a ele ao longo do tempo. Também podemos append ouvintes de events para torná-lo interativo.
  • Canvas usa renderização imediata : Quando desenhamos um retângulo , o navegador imediatamente renderiza um retângulo na canvas, mas nunca haverá qualquer “object retângulo” que o represente. Há apenas um monte de pixels no buffer de canvas. Não podemos mover o retângulo. Nós só podemos desenhar outro retângulo. Não podemos responder a cliques ou outros events no retângulo. Nós só podemos responder a events em toda a canvas .

Portanto, canvas é uma API restritiva de nível mais baixo que o SVG. Mas há um outro lado disso, que é que com a canvas você pode fazer mais com a mesma quantidade de resources. Como o navegador não precisa criar e manter o gráfico de objects na memory de todas as coisas que desenhamos, ele precisa de menos resources de memory e computação para desenhar a mesma cena visual. Se você tem uma visualização muito grande e complexa para desenhar, o Canvas pode ser seu ticket.