Gráficos / gráficos interativos rápidos e responsivos: SVG, Canvas, outros?

114

Estou tentando escolher a tecnologia certa para usar na atualização de um projeto que basicamente renderiza milhares de pontos em um gráfico com zoom e panorâmica. A implementação atual, usando Protovis, tem baixo desempenho. Confira aqui:

http://www.planethunters.org/classify

Existem cerca de 2.000 pontos quando totalmente reduzido. Tente usar as alças na parte inferior para aumentar um pouco o zoom e arraste para se movimentar. Você verá que é bastante instável e o uso da CPU provavelmente sobe até 100% em um núcleo, a menos que você tenha um computador muito rápido. Cada mudança na área de foco chama um redesenho para protovis que é muito lento e é pior com mais pontos desenhados.

Eu gostaria de fazer algumas atualizações na interface, bem como alterar a tecnologia de visualização subjacente para ser mais responsiva com animação e interação. No artigo a seguir, parece que a escolha é entre outra biblioteca baseada em SVG ou baseada em canvas:

http://www.sitepoint.com/how-to-choose-between-canvas-and-svg/

d3.js , que cresceu a partir do Protovis, é baseado em SVG e supostamente é melhor para renderizar animações . No entanto, tenho dúvidas sobre o quanto melhor e qual é seu teto de desempenho. Por esse motivo, também estou considerando uma revisão mais completa usando uma biblioteca baseada em tela como o KineticJS . No entanto, antes de ir muito longe no uso de uma abordagem ou outra, gostaria de ouvir alguém que fez um aplicativo da web semelhante com tantos dados e obter sua opinião.

O mais importante é o desempenho, com foco secundário na facilidade de adicionar outros recursos de interação e programar a animação. Provavelmente não haverá mais de 2.000 pontos de uma vez, com aquelas pequenas barras de erro em cada um. Aumentar, diminuir e girar ao redor precisam ser suaves. Se as bibliotecas SVG mais recentes são decentes nisso, talvez a facilidade de usar d3 supere a configuração aumentada para KineticJS, etc. Mas se houver uma grande vantagem de desempenho em usar um canvas, especialmente para pessoas com computadores mais lentos, então eu definitivamente preferiria seguir esse caminho.

Exemplo de aplicativo feito pelo NYTimes que usa SVG, mas ainda apresenta animação sem problemas: http://www.nytimes.com/interactive/2012/05/17/business/dealbook/how-the-facebook-offering-compares.html . Se eu conseguir esse desempenho e não precisar escrever meu próprio código de desenho de tela, provavelmente optaria pelo SVG.

Percebi que alguns usuários usaram um híbrido de manipulação de d3.js combinado com renderização de tela . Porém, não consigo encontrar muita documentação sobre isso online ou entre em contato com o OP desse post. Se alguém tiver alguma experiência com esse tipo de implementação DOM-to-Canvas ( demo , código ), gostaria de ouvir de você também. Parece ser um bom híbrido de capacidade de manipular dados e ter controle personalizado sobre como renderizá-los (e, portanto, o desempenho), mas estou me perguntando se ter que carregar tudo no DOM ainda vai desacelerar as coisas.

Eu sei que existem algumas perguntas semelhantes a esta, mas nenhuma delas pergunta exatamente a mesma coisa. Obrigado pela ajuda.

Acompanhamento : a implementação que acabei usando está em https://github.com/zooniverse/LightCurves

Andrew Mao
fonte
"O mais importante é o desempenho, com um foco secundário na facilidade de adicionar outra interação" +1 para canvas
philipp
A questão é: o SVG é suficiente na maioria dos navegadores para 2k pontos + outros elementos do gráfico? Se assim for, e a lentidão se deve apenas a fraquezas no protovis, prefiro ficar com o SVG.
Andrew Mao,
1
Mike Bostock já deu uma boa resposta. Para obter mais informações, você pode verificar estes dois recursos: stackoverflow.com/questions/5882716/html5-canvas-vs-svg-vs-div/… blogs.msdn.com/b/ie/archive/2011/04/22 /…
Ümit
8
Acompanhamento: implementei isso com uma abordagem híbrida de SVG / canvas, em que o SVG cuida dos eixos e linhas de grade e a tela pode renderizar os pontos muito rapidamente. É super rápido!
Andrew Mao

Respostas:

183

Felizmente, desenhar 2.000 círculos é um exemplo muito fácil de testar. Portanto, aqui estão quatro implementações possíveis, duas de cada Canvas e SVG:

Esses exemplos usam o comportamento de zoom da D3 para implementar zoom e panorâmica. Além de os círculos serem renderizados em Canvas ou SVG, a outra grande diferença é se você usa zoom geométrico ou semântico .

O zoom geométrico significa que você aplica uma única transformação a toda a janela de visualização: quando você aumenta o zoom, os círculos ficam maiores. O zoom semântico em contraste significa que você aplica transformações a cada círculo individualmente: quando você aumenta o zoom, os círculos permanecem do mesmo tamanho, mas se espalham. Planethunters.org atualmente usa zoom semântico, mas pode ser útil considerar outros casos.

O zoom geométrico simplifica a implementação: você aplica uma tradução e escala uma vez e, em seguida, todos os círculos são renderizados novamente. A implementação de SVG é particularmente simples, atualizando um único atributo "transform". O desempenho de ambos os exemplos de zoom geométrico parece mais do que adequado. Para zoom semântico, você notará que D3 é significativamente mais rápido do que Protovis. Isso ocorre porque está fazendo muito menos trabalho para cada evento de zoom. (A versão Protovis tem que recalcular todos os atributos em todos os elementos.) O zoom semântico baseado em Canvas é um pouco mais rápido que o SVG, mas o zoom semântico SVG ainda parece responsivo.

No entanto, não há fórmula mágica para desempenho, e essas quatro abordagens possíveis não cobrem todo o espaço de possibilidades. Por exemplo, você pode combinar zoom geométrico e semântico, usando a abordagem geométrica para panorâmica (atualizando o atributo "transformar") e apenas redesenhando círculos individuais durante o zoom. Você provavelmente poderia até mesmo combinar uma ou mais dessas técnicas com transformações CSS3 para adicionar alguma aceleração de hardware (como no exemplo de empacotamento de borda hierárquica ), embora isso possa ser complicado de implementar e pode introduzir artefatos visuais.

Ainda assim, minha preferência pessoal é manter o máximo possível em SVG e usar o Canvas apenas para o "loop interno" quando a renderização for o gargalo . O SVG tem tantas conveniências para desenvolvimento - como CSS, data-joins e o inspetor de elemento - que muitas vezes é uma otimização prematura começar com o Canvas. Combinar Canvas com SVG, como na visualização de IPO do Facebook que você vinculou, é uma maneira flexível de manter a maioria dessas conveniências e, ao mesmo tempo, obter o melhor desempenho. Também usei essa técnica em Cubism.js , onde o caso especial de visualização de série temporal se adapta bem ao cache de bitmap.

Como mostram esses exemplos, você pode usar D3 com Canvas, embora partes do D3 sejam específicas para SVG. Veja também este gráfico de força dirigida e este exemplo de detecção de colisão .

mbostock
fonte
Uau, essa foi uma resposta incrível, e do próprio mestre da visualização! Acho que teria que ficar com o zoom semântico e, no meu computador, o renderizador baseado em tela é muito mais rápido do que a versão SVG ao aplicar panorâmica / zoom (pode ter a ver com a implementação do navegador?). O que você disse sobre o uso de SVG com canvas como loop interno é exatamente o que eu queria confirmar, e os exemplos de código são apenas um ótimo bônus. Muito obrigado!
Andrew Mao,
Pensei em experimentar os exemplos de zoom semântico em diferentes navegadores: Chrome, ambos muito rápidos, não consigo ver a diferença; IE: SVG ligeiramente mais lento; Firefox (último comentário): SVG é muito lento em comparação com o canvas. Acho que isso também complica um pouco a decisão, mas torna a renderização do canvas uma escolha segura. Mais uma pergunta: o uso do KineticJS em vez do canvas afetará diretamente o desempenho de maneira significativa?
Andrew Mao
1
Andrew, um pouco tarde, mas aqui está minha experiência com o FF: Está se atualizando. Eu costumava executar as transições FF 15 e D3 SVG rapidamente começaram a ficar lentas. Mas cada nova versão ficava substancialmente mais rápida. Agora estou no FF 18 beta e é rápido em comparação com 17. Não tenho certeza se é tão bom quanto o cromo.
user2503795
@AndrewMao Oi Andrew, Eu me deparo com uma situação em que parece que a renderização é o gargalo. Preciso aplicar panorâmica e zoom em alguns pontos e cerca de 6.000 caminhos de curvas. stackoverflow.com/questions/17907769/svg-path-rendering-speed/… Mas eu não entendo muito Bostock quando ele disse "mantenha o máximo possível em SVG e use Canvas apenas para o" loop interno "" que eu tenho olhei para os quatro exemplos embora. Você poderia me lançar alguma luz?
kakacii
@kakacii a transformação é igualmente lenta em todos os navegadores? Se sim, eu diria que você está usando o código errado ou atingiu os limites de renderização do navegador. Se você pudesse postar algum código, talvez eu possa ajudar. mbostock estava se referindo ao uso de SVG para simplicidade de manipulação e canvas apenas quando necessário, pois é mais complicado de codificar. No entanto, bibliotecas como KineticJS simplificaram isso até certo ponto.
Andrew Mao
8

Penso que, no seu caso, a decisão entre canvas e svg não é como uma decisão entre »andar a Cavalo« ou conduzir um »Porsche«. Para mim é mais como a decisão sobre a cor dos carros.

Deixe-me explicar: Supondo que, com base na estrutura das operações

  • desenhe uma estrela,
  • adicione uma estrela e
  • remover uma estrela

leva tempo linear. Então, se sua decisão do framework foi boa, é um pouco mais rápido, caso contrário, um pouco mais lento.

Se você continuar assumindo que o framework é apenas rápido, então se torna totalmente óbvio que a falta de desempenho é causada pela grande quantidade de estrelas e manipulá-los é algo que nenhum dos frameworks pode fazer por você, pelo menos eu não sei sobre isso.

O que quero dizer é que a base do problema leva a um problema básico de geometria computacional, a saber: range search e outro de computação gráfica: nível de detalhe .

Para resolver seu problema de desempenho, você precisa implementar um bom pré-processador que seja capaz de encontrar rapidamente quais estrelas exibir e talvez seja capaz de agrupar estrelas que estão próximas, dependendo do zoom. A única coisa que mantém sua visão vívida e rápida é manter o menor número de estrelas possível.

Como você afirmou, o mais importante é o desempenho, do que eu tenderia a usar o canvas, porque ele funciona sem operações DOM. Também oferece a oportunidade de usar o webGL, o que aumenta muito o desempenho gráfico.

BTW: você verificou o paper.js ? Ele usa tela, mas emula gráficos vetoriais.

PS: Neste livro você pode encontrar uma discussão muito detalhada sobre gráficos na web, as tecnologias, prós e contras do canvas, SVG e DHTML.

philipp
fonte
7

Recentemente, trabalhei em um painel quase em tempo real (atualização a cada 5 segundos) e optei por usar gráficos que renderizam usando tela.

Tentamos Highcharts (biblioteca de gráficos JavaScript baseada em SVG) e CanvasJS (biblioteca de gráficos JavaScript baseada em canvas). Embora Highcharts seja uma API de gráficos fantástica e ofereça muito mais recursos, decidimos usar o CanvasJS.

Precisávamos exibir pelo menos 15 minutos de dados por gráfico (com opção de escolha de intervalo de no máximo duas horas).

Portanto, por 15 minutos: 900 pontos (pontos de dados por segundo) x2 (gráfico de combinação de linhas e barras) gráficos x4 = total de 7200 pontos.

Usando o cromo profiler, com CanvasJS a memória nunca ultrapassou 30 MB, enquanto com Highcharts o uso de memória excedeu 600 MB.

Também com tempo de atualização de 5 segundos, a renderização do CanvasJS foi mais responsiva do que o Highcharts.

Usamos um cronômetro (setInterval 5 segundos) para fazer 4 chamadas de API REST para puxar os dados do servidor de backend que se conectou ao Elasticsearch. Cada gráfico atualizado como dados é recebido por JQuery.post ().

Dito isso, para relatórios off-line, eu escolheria Highcharts, pois é uma API mais flexível.

Também há gráficos Zing que afirmam usar SVG ou Canvas, mas não os examinou.

O canvas deve ser considerado quando o desempenho é realmente crítico. SVG para flexibilidade. Não que os frameworks canvas não sejam flexíveis, mas é preciso muito mais trabalho para o framework canvas obter a mesma funcionalidade que um framework svg.

user432024
fonte
3

Também pode dar uma olhada em Meteor Charts, que é construído em cima da super-rápida estrutura KineticJS: http://meteorcharts.com/

Eric Rowell
fonte
0

Também descobri que quando imprimimos em PDF uma página com gráficos SVG, o PDF resultante ainda contém uma imagem baseada em vetor, enquanto se você imprimir uma página com gráficos Canvas, a imagem no arquivo PDF resultante é rasterizada.

ostrokach
fonte