Tela HTML5 vs. SVG vs. div

476

Qual é a melhor abordagem para criar elementos em tempo real e poder movê-los? Por exemplo, digamos que eu queira criar um retângulo, círculo e polígono, selecione esses objetos e mova-os.

Entendo que o HTML5 fornece três elementos que podem tornar isso possível: svg , canvas e div . Pelo 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 com um cabeçalho, rodapé, widget e conteúdo de texto. O widget na primeira página seria criado inteiramente com o canvaselemento, a segunda inteiramente com o svgelemento e a terceira com o divelemento simples , HTML e CSS.

verdy
fonte
13
Você pode achar isso interessante: Pensamentos sobre quando usar o Canvas e o SVG .
Robertc
1
Para aqueles que não conhecem esta tecnologia, este vídeo aborda o SVG e o Canvas e outros detalhes sobre como isso se integra no html5.
Paulo Bueno
12
Resposta curta: O Canvas é para o MS Paint e o SVG para o MS Powerpoint. Canvas é raster, SVG é vetorial.
GetFree
2
Caro leitor: faça todas as comparações e declarações aqui com um pouco de sal e verifique a data das postagens e comentários. Os tempos mudaram e mudarão. O desempenho relativo e até as opções que você possui mudarão. Por exemplo, a maioria das respostas foi escrita quando não havia WebGL, o que definitivamente é uma alternativa - ele também estará desatualizado em alguns anos, mas a partir de hoje pode ser muito relevante.
Sebastian
@Sebastian, o que você recomendaria hoje? se for fornecido um tamanho base (por exemplo, 1280x800) e se você estiver disposto a dimensionar elementos manualmente no código ou usar porcentagens o tempo todo, há uma vantagem do SVG em usar DIVs?
Crashalot 6/01/19

Respostas:

563

A resposta curta:

O SVG seria mais fácil para você, uma vez que a seleção e a movimentação já estão integradas. Os objetos SVG são objetos DOM, portanto, eles têm manipuladores de "clique" etc.

Os DIVs são bons, mas são desajeitados e têm um desempenho terrível carregando em grandes números.

O Canvas tem o melhor desempenho, mas você deve implementar todos os conceitos de estado gerenciado (seleção de objetos 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 (digamos, com uma cor e espessura da linha), desenha essa coisa e o Canvas não tem conhecimento dela: ela não sabe onde está ou o que acabou de desenhar, é apenas pixels. Se você deseja desenhar retângulos e fazer com que eles se movam ou sejam selecionáveis, é necessário codificar tudo isso do zero, incluindo o código para lembrar que você os desenhou.

O SVG, por outro lado, deve manter referências a cada objeto que ele renderiza. Todo elemento SVG / VML que você cria é um elemento real no DOM. Por padrão, isso permite que você acompanhe muito melhor os elementos criados e facilita o tratamento de coisas como eventos de mouse por padrão, mas fica mais lento quando há um grande número de objetos.

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

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

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

Corri vários números em desenho feito em HTML DIV versus desenho em tela. Eu poderia fazer uma publicação enorme sobre os benefícios de cada um, mas apresentarei alguns dos resultados relevantes dos meus testes a serem considerados para sua aplicação específica:

Criei páginas de teste Canvas e HTML DIV, ambas com "nós" móveis. Os nós do Canvas eram objetos que eu criei e acompanhei em Javascript. Nós HTML eram Divs móveis.

Adicionei 100.000 nós a cada um dos meus dois testes. Eles tiveram um desempenho bem diferente:

A guia de teste HTML demorou uma eternidade para carregar (com tempo ligeiramente inferior a 5 minutos, o Chrome pediu para matar a página pela primeira vez). O gerenciador de tarefas do Chrome diz que essa guia ocupa 168 MB. Leva 12-13% do tempo de CPU quando estou olhando, 0% quando não estou olhando.

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

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

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

Conclusão:

  • O SVG provavelmente é melhor para aplicativos e aplicativos com poucos itens (menos de 1000? Depende mesmo)
  • O Canvas é melhor para milhares de objetos e manipulação cuidadosa, mas é necessário muito mais código (ou biblioteca) para tirá-lo do papel.
  • Divs HTML são desajeitadas e não escalam, é possível fazer um círculo apenas com cantos arredondados, criar formas complexas, mas envolve centenas de minúsculas divs minúsculas com largura de pixel. Loucura segue.
Simon Sarris
fonte
4
O bolo biblioteca é outro exemplo de fazer objetos móveis e animações com objetos em uma tela
SiggyF
Errado: P div pode escalar se o navegador estiver usando o mecanismo CSS acelerado hw, a arte css é diferente e, além de Canvas e SVG serem a escolha certa aqui, CSS art / div art é justamente quando você não precisa exagerar apenas uma pequena sobreposição: P
ShrekOverflow 6/12/12
Com relação aos DIVs, se você deseja criar círculos / formas especiais e não mudar sua imagem / sprite no curso devido, basta criar um PNG e usá-lo como background-image... Embora você possa fazer coisas semelhantes no SVG / Canvas
luiges90
4
E se você estiver criando um jogo de mapa interativo? : p
Anthony
Isso foi criado usando DIVs (não aninhadas) e transformações em CSS 3D, então eu diria que as DIVs não são lentas: youtube.com/watch?v=fzBC20B5dsk
Erik Kaplun
39

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

O que descobri foi que, no meu Mac, para imagens muito grandes, o SVG é superior. Eu tenho uma Retina do MacBook Pro 2013 de 13 "e funciona muito bem com o violino abaixo. A imagem tem 6000x6000 pixels e 1000 objetos. Uma construção semelhante na tela era impossível de animar para mim quando o usuário estava arrastando objetos pelo diagrama.

Em monitores modernos, você também deve considerar diferentes resoluções, e aqui o SVG oferece tudo isso de graça.

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

Tela cheia: 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 1000 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);
knut
fonte
2
Também optamos pelo SVG, depois de tentar desesperadamente fazer o Canvas trabalhar para nós. Temos um diagrama muito grande e o SVG foi de longe o mais eficiente, além do dimensionamento automático nas telas de retina ser um bônus enorme.
Fijjit
knut e @Fijjit você considerou usar DIVs em vez de SVG? se um tamanho de base (por exemplo, 1280x800) não fosse possível escalar DIVs manualmente, para que fiquem tão nítidos quanto SVG? Obrigado pela ajuda!
Crashalot 6/01/19
24

Conhecer as diferenças entre SVG e Canvas seria útil na seleção da correta.

Tela de pintura

SVG

  • Resolução independente
  • Suporte para manipuladores de eventos
  • 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 em jogos
Leo os quatro
fonte
8
por que as pessoas dizem que o Canvas depende da resolução? Eu entendo que, uma vez que o bitmap tenha sido renderizado, ele não aumenta muito. mas você pode redesenhar as alterações no tamanho da resolução. Então, como essa resolução não é independente?
Alex Bollbach
@AlexBollbach - O Canvas depende da resolução, porque você precisa levar em consideração (depender) da resolução para obter bons resultados. Com o SVG, você não se importa com a resolução. Boa sorte em obter linhas não irregulares em uma impressora 2400DPI e uma renderização baseada em Canvas. Não há problema com SVG.
Sebastian
18

Eu concordo com as conclusões de Simon Sarris:

Comparei algumas visualizações no Protovis (SVG) com o Processingjs (Canvas), que exibe> 2000 pontos e o processingjs é muito mais rápido que o protovis.

A manipulação de eventos com SVG é obviamente muito mais fácil, porque você pode anexá-los aos objetos. No Canvas, você deve fazer isso manualmente (verificar 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 dojo. Ele fornece uma camada de abstração e você pode especificar o renderizador (SVG, Canvas, Silverlight). Essa também pode ser uma opção viável, embora eu não saiba quanto sobrecarga a camada de abstração adicional acrescenta, mas facilita a codificação de interações e animações e é independente do renderizador.

Aqui estão alguns benchmarks interessantes:

Ümit
fonte
17

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

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

Existem muitas gravações de tela no Youtube e em outros lugares, coisas 2D / 3D de alto desempenho em execução no navegador, sendo tudo um elemento DOM no qual você pode inspecionar o elemento , a 60FPS (misturado ao WebGL para determinados efeitos, mas não para o parte principal da renderização).

Erik Kaplun
fonte
14

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

Ao longo dos anos, o desempenho do SVG melhorou bastante e agora há transições e animações CSS aceleradas por hardware para o SVG que não dependem do desempenho do JavaScript. É claro que o desempenho do JavaScript também melhorou e, com ele, o desempenho do Canvas, mas não tanto quanto o SVG. Também existe 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 Simon usou acima: É melhor do que o Canvas e o SVG . Isso não significa que deve ser a tecnologia preferida, já que é uma fera para se trabalhar e é apenas mais rápida em casos de uso muito específicos.

IMHO para a maioria dos casos de uso atualmente, 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 muito simples ao mesmo tempo (por elemento), para que o Canvas e, mais ainda, o WebGL realmente brilhem.

Em esta resposta a uma pergunta semelhante eu estou fornecendo mais detalhes, porque eu acho que a combinação de todas as três tecnologias, por vezes, é a melhor opção que você tem.

Sebastian
fonte
Usuários Unix devem tomar nota de que a aceleração de hardware está desativado por padrão no Firefox e cromo, ainda é verdade em meados de 2019.
NVRM
@NVRM - trata-se de aceleração de hardware de CSS e SVG, não de decodificação de vídeo. AFAIK o antigo tem estado disponível há anos: Verificação de saída de chrome: // gpu
Sebastian
layers.acceleration.force-enabledno Firefox não é sobre decodificação de vídeo. É um fato bem conhecido. Quando concluído, o loop usando requestAnimationFrame é outro nível, permitindo muito mais repainas. Não é sobre vídeo.
NVRM 01/08/19
@NVRM - você pode fornecer links para erros de FF e Chromium para esses problemas de GPU no Linux, por favor? Observe também que, por "aceleração por hardware", eu não estava me referindo apenas à aceleração da GPU, mas também à composição e animações multithread, como por exemplo, carregar spinners que continuam girando enquanto nenhum JavaScript está em execução ou enquanto o JS está sendo executado. Isso é impossível no Canvas e, em relação ao "JavaScript" puro, é realmente algum tipo de aceleração de hardware (multiencadeamento) que está definitivamente disponível no Chrome e FF em todas as plataformas. Obrigado!
Sebastian
1
Para resumir a situação atual: Funciona para mim no Chrome e no Chromium. No Linux. Em 2019. Em todas as instâncias, testei sem configuração especial. O Firefox / Mozilla está trabalhando nele para Linux , no entanto, a renderização fora do processo também não é algo novo para o FF e sempre funcionará melhor com SVG, CSS etc. do que com o Canvas.
Sebastian
13

Para seus propósitos, recomendo usar o SVG, já que você obtém eventos DOM, como manipulação de mouse, incluindo arrastar e soltar, incluído, não é necessário implementar seu próprio redesenho nem acompanhar o estado de seus objetos. Use o Canvas quando precisar manipular imagens de bitmap e use uma div regular quando desejar manipular coisas criadas em HTML. Quanto ao desempenho, você verá que os navegadores modernos estão acelerando os três, mas essa tela recebeu a maior atenção até agora. Por outro lado, o quão bem você escreve seu javascript é fundamental para obter o máximo desempenho com o canvas, por isso ainda recomendo usar o SVG.

Gaurav
fonte
1
Na verdade, o uso de HTML simples é o mais eficiente em combinação com imagens CSS.
Raynos 4/11/11
16
@ Raynos: Fonte?
Janus Troelsen
3

Ao pesquisar no Google, encontro uma boa explicação sobre o uso e a compactação de SVG e Canvas em http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html

Espero que ajude:

  • O SVG, como HTML, usa renderização retida : quando queremos desenhar um retângulo na tela, usamos declarativamente um elemento em nosso DOM. O navegador desenhará um retângulo, mas também criará um objeto SVGRectElement na memória que representa o retângulo. Esse objeto é algo que fica por aí para manipularmos - ele é retido. Podemos atribuir diferentes posições e tamanhos a ele ao longo do tempo. Também podemos anexar ouvintes de eventos para torná-los interativos.
  • O Canvas usa renderização imediata : quando desenhamos um retângulo , o navegador renderiza imediatamente um retângulo na tela, mas nunca haverá nenhum "objeto de retângulo" que o represente. Há apenas alguns pixels no buffer da tela. Não podemos mover o retângulo. Só podemos desenhar outro retângulo. Não podemos responder a cliques ou outros eventos no retângulo. Só podemos responder a eventos em toda a tela .

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

Alireza Fattahi
fonte