Cuadros / gráficos interactivos rápidos y receptivos: SVG, Canvas, ¿otros?

114

Estoy tratando de elegir la tecnología correcta para usar para actualizar un proyecto que básicamente muestra miles de puntos en un gráfico ampliable y panorámico. La implementación actual, que utiliza Protovis, tiene un rendimiento inferior. Compruébalo aquí:

http://www.planethunters.org/classify

Hay alrededor de 2000 puntos cuando se aleja completamente. Intente usar las manijas en la parte inferior para acercar un poco y arrástrelo para desplazarse. Verá que está bastante entrecortado y el uso de la CPU probablemente aumenta al 100% en un núcleo, a menos que tenga una computadora realmente rápida. Cada cambio en el área de enfoque requiere un rediseño de protovis, que es bastante lento y es peor con más puntos dibujados.

Me gustaría hacer algunas actualizaciones en la interfaz, así como cambiar la tecnología de visualización subyacente para que sea más receptiva con la animación y la interacción. En el siguiente artículo, parece que la elección es entre otra biblioteca basada en SVG o una basada en lienzo:

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

d3.js , que surgió de Protovis, está basado en SVG y se supone que es mejor para renderizar animaciones . Sin embargo, tengo dudas sobre cuánto mejor y cuál es su límite de rendimiento. Por esa razón, también estoy considerando una revisión más completa usando una biblioteca basada en lienzo como KineticJS . Sin embargo, antes de llegar demasiado lejos en el uso de un enfoque u otro, me gustaría escuchar a alguien que haya hecho una aplicación web similar con esta cantidad de datos y obtener su opinión.

Lo más importante es el rendimiento, con un enfoque secundario en la facilidad de agregar otras funciones de interacción y programar la animación. Probablemente no habrá más de 2000 puntos a la vez, con esas pequeñas barras de error en cada uno. El acercamiento, el alejamiento y la panorámica deben ser suaves. Si las bibliotecas SVG más recientes son decentes en esto, entonces tal vez la facilidad de uso de d3 supere la configuración aumentada para KineticJS, etc. Pero si hay una gran ventaja de rendimiento al usar un lienzo, especialmente para personas con computadoras más lentas, entonces Definitivamente preferiría ir por ese camino.

Ejemplo de aplicación creada por NYTimes que usa SVG, pero que aún se anima aceptablemente sin problemas: http://www.nytimes.com/interactive/2012/05/17/business/dealbook/how-the-facebook-offering-compares.html . Si puedo obtener ese rendimiento y no tener que escribir mi propio código de dibujo de lienzo, probablemente optaría por SVG.

Me di cuenta de que algunos usuarios han utilizado un híbrido de manipulación de d3.js combinado con la representación de lienzo . Sin embargo, no puedo encontrar mucha documentación sobre esto en línea o ponerme en contacto con el OP de esa publicación. Si alguien tiene alguna experiencia en este tipo de implementación de DOM-to-Canvas ( demostración , código ), también me gustaría saber de usted. Parece ser un buen híbrido de poder manipular datos y tener un control personalizado sobre cómo renderizarlos (y por lo tanto, el rendimiento), pero me pregunto si tener que cargar todo en el DOM seguirá ralentizando las cosas.

Sé que existen algunas preguntas que son similares a esta, pero ninguna de ellas hace exactamente lo mismo. Gracias por tu ayuda.

Seguimiento : la implementación que terminé usando está en https://github.com/zooniverse/LightCurves

Andrew Mao
fuente
"Lo más importante es el rendimiento, con un enfoque secundario en la facilidad para agregar otras interacciones" +1 para lienzo
philipp
La pregunta es, ¿SVG es suficiente en la mayoría de los navegadores para 2k puntos + otros elementos del gráfico? Si es así, y la lentitud se debe solo a debilidades en protovis, prefiero seguir con SVG.
Andrew Mao
1
Mike Bostock ya dio una buena respuesta. Para obtener información adicional, puede consultar estos dos recursos: stackoverflow.com/questions/5882716/html5-canvas-vs-svg-vs-div/… blogs.msdn.com/b/ie/archive/2011/04/22 /…
Ümit
8
Seguimiento: Implementé esto con un enfoque híbrido de SVG / lienzo, donde el SVG se encarga de los ejes y las líneas de cuadrícula y el lienzo puede representar los puntos extremadamente rápido. ¡Es súper rápido!
Andrew Mao

Respuestas:

183

Afortunadamente, dibujar 2000 círculos es un ejemplo bastante fácil de probar. Así que aquí hay cuatro posibles implementaciones, dos de Canvas y SVG:

Estos ejemplos utilizan el comportamiento de zoom de D3 para implementar el zoom y la panorámica. Aparte de si los círculos se representan en Canvas o SVG, la otra gran distinción es si utiliza zoom geométrico o semántico .

El zoom geométrico significa que aplica una sola transformación a toda la ventana gráfica: cuando hace zoom, los círculos se agrandan. El zoom semántico en contraste significa que aplica transformaciones a cada círculo individualmente: cuando hace zoom, los círculos permanecen del mismo tamaño pero se extienden. Planethunters.org utiliza actualmente el zoom semántico, pero podría ser útil considerar otros casos.

El zoom geométrico simplifica la implementación: aplica una traducción y escala una vez, y luego todos los círculos se vuelven a renderizar. La implementación de SVG es particularmente simple, actualizando un único atributo de "transformación". El rendimiento de ambos ejemplos de zoom geométrico se siente más que adecuado. Para el zoom semántico, notará que D3 es significativamente más rápido que Protovis. Esto se debe a que hace mucho menos trabajo para cada evento de zoom. (La versión de Protovis tiene que recalcular todos los atributos de todos los elementos). El zoom semántico basado en Canvas es un poco más rápido que SVG, pero el zoom semántico SVG todavía se siente receptivo.

Sin embargo, no existe una fórmula mágica para el desempeño, y estos cuatro enfoques posibles no comienzan a cubrir todo el espacio de posibilidades. Por ejemplo, puede combinar el acercamiento geométrico y semántico, utilizando el enfoque geométrico para la panorámica (actualizando el atributo "transformar") y solo redibujando círculos individuales mientras hace zoom. Probablemente incluso podría combinar una o más de estas técnicas con transformaciones CSS3 para agregar algo de aceleración de hardware (como en el ejemplo de agrupación de bordes jerárquicos ), aunque eso puede ser complicado de implementar y puede introducir artefactos visuales.

Aún así, mi preferencia personal es mantener tanto en SVG como sea posible, y usar Canvas solo para el "bucle interno" cuando la renderización es el cuello de botella . SVG tiene tantas comodidades para el desarrollo, como CSS, combinaciones de datos y el inspector de elementos, que a menudo es una optimización prematura comenzar con Canvas. Combinar Canvas con SVG, como en la visualización de IPO de Facebook que vinculó, es una forma flexible de retener la mayoría de estas comodidades sin dejar de obtener el mejor rendimiento. También utilicé esta técnica en Cubism.js , donde el caso especial de visualización de series de tiempo se presta bien al almacenamiento en caché de mapas de bits.

Como muestran estos ejemplos, puede usar D3 con Canvas, aunque partes de D3 son específicas de SVG. Vea también este gráfico de fuerza dirigida y este ejemplo de detección de colisiones .

mbostock
fuente
Vaya, esa fue una respuesta increíble, ¡y del mismo maestro de la visualización! Creo que tendría que seguir con el zoom semántico, y en mi computadora, el renderizador basado en lienzo es mucho más rápido que la versión SVG cuando se hace una panorámica / zoom (¿podría tener que ver con la implementación del navegador?). Lo que dijiste sobre el uso de SVG con lienzo como bucle interno es exactamente lo que estaba buscando para confirmar, y los ejemplos de código son solo una buena ventaja. ¡Muchas gracias!
Andrew Mao
Acabo de pensar en probar los ejemplos de zoom semántico en diferentes navegadores: Chrome, ambos bastante rápidos, no puedo notar la diferencia; IE: SVG un poco más lento; Firefox (último comentario): SVG es muy lento en comparación con el lienzo. Supongo que eso también complica un poco la decisión, pero hace que la representación de lienzo sea una elección segura. Una pregunta más: ¿El uso de KineticJS en lugar de lienzo afectará directamente el rendimiento de manera significativa?
Andrew Mao
1
Andrew, un poco tarde, pero esta es mi experiencia con FF: se está poniendo al día. Solía ​​ejecutar transiciones FF 15 y D3 SVG que rápidamente comenzaron a volverse lentas. Pero cada nueva versión se volvió sustancialmente más rápida. Ahora estoy en FF 18 beta y es rápido en comparación con el 17. Sin embargo, no estoy seguro de si es tan suave como el cromo.
user2503795
@AndrewMao Hola Andrew, Me encuentro con una situación en la que parece que el renderizado es el cuello de botella. Necesito desplazar y hacer zoom en algunos puntos y alrededor de 6000 curvas. stackoverflow.com/questions/17907769/svg-path-rendering-speed/… Pero no entiendo muy bien a Bostock cuando dijo "mantenga tanto en SVG como sea posible, y use Canvas solo para el" bucle interno "" Tengo Sin embargo, miré los cuatro ejemplos ... ¿Podrías arrojarme algo de luz?
kakacii
@kakacii, ¿la transformación es igualmente lenta en todos los navegadores? Si es así, diría que está usando el código incorrecto o ha alcanzado los límites de la representación del navegador. Si pudiera publicar algún código, podría ayudarlo. mbostock se refería al uso de SVG para simplificar la manipulación y el lienzo solo cuando sea necesario, ya que es más complicado de codificar. Sin embargo, las bibliotecas como KineticJS lo han simplificado hasta cierto punto.
Andrew Mao
8

Creo que en tu caso la decisión entre lona y svg no es como una decisión entre »montar a caballo« o conducir un »Porsche«. Para mí, se parece más a la decisión sobre el color del coche.

Permítanme explicar: suponiendo que, según el marco, las operaciones

  • dibuja una estrella,
  • agrega una estrella y
  • quitar una estrella

tomar tiempo lineal. Entonces, si su decisión del marco fue buena, es un poco más rápido, de lo contrario, un poco más lento.

Si sigues asumiendo que el marco es rápido, entonces se vuelve totalmente obvio que la falta de rendimiento se debe a la gran cantidad de estrellas y manejarlas es algo que ninguno de los marcos puede hacer por ti, al menos no lo sé. sobre esto.

Lo que quiero decir es que la base del problema lleva a un problema básico de geometría computacional, a saber: búsqueda de rango y otro de infografía: nivel de detalle .

Para resolver su problema de rendimiento, necesita implementar un buen preprocesador que sea capaz de encontrar muy rápidamente qué estrellas mostrar y tal vez sea capaz de agrupar estrellas que están muy juntas, dependiendo del zoom. Lo único que mantiene su vista vívida y rápida es mantener el número de estrellas para dibujar lo más bajo posible.

Como dijiste, lo más importante es el rendimiento, de lo que tendería a usar lienzo, porque funciona sin operaciones DOM. También ofrece la oportunidad de utilizar webGL, lo que aumenta mucho el rendimiento gráfico.

Por cierto: ¿ revisaste paper.js ? Utiliza lienzo, pero emula gráficos vectoriales.

PD: En este libro puede encontrar una discusión muy detallada sobre los gráficos en la web, las tecnologías, los pros y los contras del lienzo, SVG y DHTML.

philipp
fuente
7

Recientemente trabajé en un panel de control casi en tiempo real (se actualiza cada 5 segundos) y elegí usar gráficos que se renderizan usando lienzo.

Probamos Highcharts (biblioteca de gráficos JavaScript basada en SVG) y CanvasJS (biblioteca de gráficos JavaScript basada en Canvas). Aunque Highcharts es una API de gráficos fantástica y ofrece muchas más funciones, decidimos usar CanvasJS.

Necesitábamos mostrar al menos 15 minutos de datos por gráfico (con la opción de elegir un rango de máximo dos horas).

Entonces, durante 15 minutos: 900 puntos (puntos de datos por segundo) x2 (gráfico de combinación de líneas y barras) x4 gráficos = 7200 puntos en total.

Con Chrome Profiler, con CanvasJS la memoria nunca superó los 30 MB, mientras que con Highcharts el uso de memoria superó los 600 MB.

Además, con un tiempo de actualización de 5 segundos, el renderizado de CanvasJS fue más receptivo que Highcharts.

Usamos un temporizador (setInterval 5 segundos) para hacer 4 llamadas a la API REST para extraer los datos del servidor back-end que se conectó a Elasticsearch. Cada gráfico actualizado como datos es recibido por JQuery.post ().

Dicho esto, para los informes fuera de línea, optaría por Highcharts ya que su API es más flexible.

También hay gráficos de Zing que afirman usar SVG o Canvas pero no los han mirado.

Canvas debe considerarse cuando el rendimiento es realmente crítico. SVG para flexibilidad. No es que los marcos de lienzo no sean flexibles, pero se necesita mucho más trabajo para que el marco de lienzo obtenga la misma funcionalidad que un marco svg.

user432024
fuente
0

También descubrí que cuando imprimimos en PDF una página con gráficos SVG, el PDF resultante todavía contiene una imagen basada en vectores, mientras que si imprime una página con gráficos Canvas, la imagen en el archivo PDF resultante se rasteriza.

ostrokach
fuente