HTML5 Canvas vs. SVG vs. div

476

¿Cuál es el mejor enfoque para crear elementos sobre la marcha y poder moverlos? Por ejemplo, supongamos que quiero crear un rectángulo, círculo y polígono y luego seleccionar esos objetos y moverlos.

Entiendo que HTML5 proporciona tres elementos que pueden hacer esto posible: svg , canvas y div . Para lo que quiero hacer, ¿cuál de esos elementos proporcionará el mejor rendimiento?

Para comparar estos enfoques, estaba pensando en crear tres páginas web visualmente idénticas que tengan un encabezado, pie de página, widget y contenido de texto. El widget en la primera página se crearía completamente con el canvaselemento, el segundo completamente con el svgelemento y el tercero con el divelemento plano , HTML y CSS.

verdy
fuente
13
Puede que le resulte interesante: Reflexiones sobre cuándo usar Canvas y SVG .
robertc
1
Para aquellos de ustedes que son nuevos en esta tecnología, este video cubre tanto SVG como Canvas y otros detalles sobre cómo se integra en html5.
Paulo Bueno
12
Respuesta corta: Canvas es para MS Paint como SVG para MS Powerpoint. Canvas es raster, SVG es vectorial.
GetFree
2
Estimado lector: tome todas las comparaciones y declaraciones aquí con un grano de sal y mire la fecha de las publicaciones y comentarios. Los tiempos han cambiado y cambiarán. El rendimiento relativo e incluso las opciones que tiene cambiarán. Por ejemplo, la mayoría de las respuestas se escribieron cuando no había WebGL, lo que definitivamente es una alternativa: también estará desactualizado en unos años, pero a partir de hoy puede ser muy relevante.
Sebastian
@Sebastian, ¿cuál recomendarías hoy? si se le da un tamaño base (por ejemplo, 1280x800) y si está dispuesto a escalar elementos manualmente en código o usar porcentajes todo el tiempo, ¿hay alguna ventaja de SVG para usar DIV?
Crashalot

Respuestas:

563

La respuesta corta:

SVG sería más fácil para usted, ya que la selección y el desplazamiento ya están integrados. Los objetos SVG son objetos DOM, por lo que tienen controladores de "clic", etc.

Los DIV están bien pero son torpes y tienen una carga de rendimiento horrible en grandes cantidades.

Canvas tiene el mejor rendimiento sin dudas, pero debe implementar todos los conceptos de estado administrado (selección de objetos, etc.) usted mismo o usar una biblioteca.


La respuesta larga:

HTML5 Canvas es simplemente una superficie de dibujo para un mapa de bits. Se configura para dibujar (digamos con un color y grosor de línea), dibuja esa cosa, y luego el lienzo no tiene conocimiento de esa cosa: no sabe dónde está o qué es lo que acaba de dibujar, es solo píxeles Si desea dibujar rectángulos y hacer que se muevan o sean seleccionables, debe codificar todo desde cero, incluido el código para recordar que los dibujó.

SVG, por otro lado, debe mantener referencias a cada objeto que representa. Cada elemento SVG / VML que cree es un elemento real en el DOM. De forma predeterminada, esto le permite realizar un seguimiento mucho mejor de los elementos que crea y facilita el manejo de cosas como los eventos del mouse de manera predeterminada, pero se ralentiza significativamente cuando hay una gran cantidad de objetos

Esas referencias SVG DOM significan que parte del trabajo de pies para lidiar con las cosas que dibujas se hace por ti. Y SVG es más rápido cuando se procesan objetos realmente grandes , pero más lento cuando se procesan muchos objetos.

Un juego probablemente sería más rápido en Canvas. Un gran programa de mapas probablemente sería más rápido en SVG. Si desea utilizar Canvas, tengo algunos tutoriales sobre cómo poner en marcha objetos móviles y ejecutarlos aquí .

Canvas sería mejor para cosas más rápidas y manipulación de mapas de bits pesados ​​(como la animación), pero tomará más código si desea mucha interactividad.

He corrido un montón de números en un dibujo hecho con HTML DIV versus un dibujo hecho en Canvas. Podría hacer una gran publicación sobre los beneficios de cada uno, pero daré algunos de los resultados relevantes de mis pruebas para considerar para su aplicación específica:

Hice páginas de prueba Canvas y HTML DIV, ambas tenían "nodos" móviles. Los nodos de lienzo eran objetos que creé y seguí en Javascript. Los nodos HTML eran Divs móviles.

Agregué 100,000 nodos a cada una de mis dos pruebas. Se desempeñaron de manera bastante diferente:

La pestaña de prueba de HTML tardó una eternidad en cargarse (cronometrado en poco menos de 5 minutos, Chrome le pidió que matara la página la primera vez). El administrador de tareas de Chrome dice que esa pestaña está ocupando 168MB. Toma 12-13% de tiempo de CPU cuando lo estoy mirando, 0% cuando no estoy mirando.

La pestaña Lienzo se cargó en un segundo y ocupa 30 MB. También ocupa el 13% del tiempo de CPU todo el tiempo, independientemente de si uno lo está mirando o no. (Edición 2013: en su mayoría lo han solucionado)

Arrastrar en la página HTML es más suave, lo que se espera del diseño, ya que la configuración actual es volver a dibujar TODO cada 30 milisegundos en la prueba de Canvas. Hay muchas optimizaciones para Canvas para esto. (la invalidación del lienzo es la más fácil, también las regiones de recorte, el rediseño selectivo, etc., solo depende de cuánto desee implementar)

No hay duda de que podría hacer que Canvas sea más rápido en la manipulación de objetos como los divs en esa simple prueba, y por supuesto mucho más rápido en el tiempo de carga. El dibujo / carga es más rápido en Canvas y también tiene mucho más espacio para optimizaciones (es decir, excluir cosas que están fuera de la pantalla es muy fácil).

Conclusión:

  • SVG es probablemente mejor para aplicaciones y aplicaciones con pocos elementos (¿menos de 1000? Depende realmente)
  • Canvas es mejor para miles de objetos y una manipulación cuidadosa, pero se necesita mucho más código (o una biblioteca) para despegarlo.
  • Los Divs HTML son torpes y no se escalan, hacer un círculo solo es posible con esquinas redondeadas, hacer formas complejas es posible pero involucra cientos de pequeños y diminutos divisiones de píxeles. La locura se produce.
Simon Sarris
fuente
44
La biblioteca Cake es otro ejemplo de hacer objetos movibles y animaciones con objetos en un lienzo
SiggyF
Incorrecto: P div puede escalar si el navegador está usando un motor CSS acelerado hw, css art es diferente y además de Canvas y SVG son la opción correcta aquí, CSS art / div art es justo cuando no necesita sobrepasar solo una pequeña superposición: P
ShrekOverflow
Con respecto a los DIV, si desea hacer círculos / formas especiales y no va a cambiar su imagen / sprite a su debido tiempo, simplemente puede crear un PNG y usarlo como background-image... Aunque puede hacer cosas similares en SVG / Canvas
luiges90
44
¿Qué pasa si estás creando un juego de mapas interactivo? : p
Anthony
Esto fue creado usando DIV (no anidados) y transformaciones CSS 3D, por lo que diría que los DIV no son lentos en absoluto: youtube.com/watch?v=fzBC20B5dsk
Erik Kaplun
39

Para agregar a esto, he estado haciendo una aplicación de diagrama, e inicialmente comencé con lienzo. El diagrama consta de muchos nodos, y pueden hacerse bastante grandes. El usuario puede arrastrar elementos en el diagrama.

Lo que encontré fue que en mi Mac, para imágenes muy grandes, SVG es superior. Tengo una Retina MacBook Pro 2013 de 13 ", y ejecuta bastante bien el violín de abajo. La imagen es de 6000x6000 píxeles y tiene 1000 objetos. Una construcción similar en el lienzo era imposible de animar para mí cuando el usuario arrastraba objetos en el diagrama.

En las pantallas modernas también debe tener en cuenta diferentes resoluciones, y aquí SVG le ofrece todo esto de forma gratuita.

Violín: http://jsfiddle.net/knutsi/PUcr8/16/

Pantalla completa: 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
fuente
2
También nos decidimos por SVG, después de intentar desesperadamente hacer que Canvas trabaje para nosotros. Tenemos un diagrama muy grande y SVG fue, con mucho, el más eficiente, además, el autoescalado en las pantallas de retina es una gran ventaja.
Fijjit
knut y @Fijjit ¿consideró usar DIV en lugar de SVG? si se le da un tamaño base (por ejemplo, 1280x800), ¿no podría escalar manualmente los DIV para que se vean tan nítidos como SVG? ¡gracias por tu ayuda!
Crashalot
24

Conocer las diferencias entre SVG y Canvas sería útil para seleccionar la correcta.

Lona

SVG

  • Resolución independiente
  • Soporte para controladores de eventos.
  • El más adecuado para aplicaciones con grandes áreas de representación (Google Maps)
  • Representación lenta si es compleja (cualquier cosa que use mucho el DOM será lenta)
  • No es adecuado para la aplicación del juego.
Leo los cuatro
fuente
8
¿Por qué la gente dice que Canvas depende de la resolución? Entiendo que una vez que el mapa de bits se ha procesado, no se escala bien. pero puede volver a dibujar los cambios en el tamaño de la resolución, entonces, ¿cómo no es independiente de esa resolución?
Alex Bollbach
@AlexBollbach: el lienzo depende de la resolución, ya que debe tener en cuenta (depender) de la resolución para obtener buenos resultados. Con SVG no te importa la resolución. Buena suerte al obtener líneas no irregulares en una impresora 2400DPI y un renderizado basado en Canvas. No hay problema con SVG.
Sebastian
18

Estoy de acuerdo con las conclusiones de Simon Sarris:

He comparado alguna visualización en Protovis (SVG) con Processingjs (Canvas) que muestra> 2000 puntos y Processingjs es mucho más rápido que Protovis.

Por supuesto, manejar eventos con SVG es mucho más fácil porque puede adjuntarlos a los objetos. En Canvas, debe hacerlo manualmente (verificar la posición del mouse, etc.) pero para una interacción simple no debería ser difícil.

También está la biblioteca dojo.gfx del kit de herramientas dojo. Proporciona una capa de abstracción y puede especificar el renderizador (SVG, Canvas, Silverlight). Esa también podría ser una opción viable, aunque no sé cuánta sobrecarga agrega la capa de abstracción adicional, pero facilita la codificación de interacciones y animaciones y es independiente del renderizador.

Aquí hay algunos puntos de referencia interesantes:

Ümit
fuente
17

Solo mis 2 centavos con respecto a la opción divs.

Famous / Infamous y SamsaraJS (y posiblemente otros) usan divs no anidados absolutamente posicionados (con contenido HTML / CSS no trivial), combinados con matrix2d / matrix3d ​​para posicionamiento y transformaciones 2D / 3D, y logran un 60FPS estable en hardware móvil moderado , entonces argumentaría en contra de que los divs sean una opción lenta.

Hay muchas grabaciones de pantalla en Youtube y en otros lugares, de material 2D / 3D de alto rendimiento que se ejecuta en el navegador, todo es un elemento DOM en el que puede inspeccionar el elemento , a 60FPS (mezclado con WebGL para ciertos efectos, pero no para el parte principal de la representación).

Erik Kaplun
fuente
14

Si bien todavía hay algo de verdad en la mayoría de las respuestas anteriores, creo que merecen una actualización:

Con los años, el rendimiento de SVG ha mejorado mucho y ahora hay transiciones y animaciones CSS aceleradas por hardware para SVG que no dependen en absoluto del rendimiento de JavaScript. Por supuesto, el rendimiento de JavaScript también ha mejorado y, con él, el rendimiento de Canvas, pero no tanto como SVG. También hay un "nuevo chico" en el bloque que está disponible en casi todos los navegadores hoy y que es WebGL . Para usar las mismas palabras que Simon usó anteriormente: supera a Canvas y SVG . Sin embargo, esto no significa que deba ser la tecnología de acceso, ya que es una bestia con la que trabajar y solo es más rápida en casos de uso muy específicos.

En mi humilde opinión para la mayoría de los casos de uso de hoy, SVG ofrece la mejor relación rendimiento / usabilidad. Las visualizaciones deben ser realmente complejas (con respecto al número de elementos) y realmente simples al mismo tiempo (por elemento) para que Canvas y aún más WebGL realmente brillen.

En esta respuesta a una pregunta similar , proporciono más detalles, por qué creo que la combinación de las tres tecnologías a veces es la mejor opción que tiene.

Sebastian
fuente
Los usuarios de Unix deben tener en cuenta que la aceleración de hardware está deshabilitada de manera predeterminada tanto en Firefox como en Chromium, lo que sigue siendo cierto a mediados de 2019.
NVRM
@NVRM: se trata de la aceleración de hardware de CSS y SVG, no de la decodificación de video. AFAIK el primero ha estado disponible durante años: Verifique la salida de Chrome: // gpu
Sebastian
layers.acceleration.force-enableden Firefox no se trata de decodificación de video. Es un hecho bien conocido. Cuando finaliza los bucles con requestAnimationFrame, hay otro nivel que permite muchas más repeticiones. No se trata del video en absoluto.
NVRM
@NVRM: ¿puede proporcionar enlaces a errores de FF y Chromium para estos problemas de GPU en Linux, por favor? También tenga en cuenta que por "aceleración por hardware" no solo me refería a la aceleración de GPU, sino también a la composición y animaciones de subprocesos múltiples, como, por ejemplo, cargar hiladores que siguen girando mientras no se ejecuta JavaScript o mientras se ejecuta JS. Esto es imposible con Canvas y en relación con el "JavaScript" puro, de hecho, es algún tipo de aceleración de hardware (multihilo) que definitivamente está disponible en Chrome y FF en todas las plataformas. ¡Gracias!
Sebastian
1
Para resumir la situación actual: funciona para mí en Chrome y Chromium. En Linux En 2019. En todos los casos, probé sin una configuración especial. Firefox / Mozilla está trabajando en ello para Linux , sin embargo, el renderizado fuera de proceso tampoco es algo nuevo para FF y siempre funcionará mejor con SVG, CSS, etc., que con Canvas.
Sebastian
13

Para sus propósitos, le recomiendo usar SVG, ya que obtiene eventos DOM, como el manejo del mouse, que incluye arrastrar y soltar, no tiene que implementar su propio redibujo, y no tiene que realizar un seguimiento del estado de tus objetos Use Canvas cuando tenga que manipular imágenes de mapa de bits y use un div regular cuando quiera manipular cosas creadas en HTML. En cuanto al rendimiento, encontrará que los navegadores modernos ahora están acelerando los tres, pero ese lienzo ha recibido la mayor atención hasta ahora. Por otro lado, qué tan bien escribes tu javascript es crítico para obtener el máximo rendimiento con el lienzo, por lo que aún recomiendo usar SVG.

Gaurav
fuente
1
En realidad, el uso de HTML sin formato es el más eficaz en combinación con imágenes CSS.
Raynos
16
@Raynos: ¿Fuente?
Janus Troelsen
3

Mientras busco en Google, encuentro una buena explicación sobre el uso y la compresión de SVG y Canvas en http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html

Espero eso ayude:

  • SVG, al igual que HTML, utiliza la representación retenida : cuando queremos dibujar un rectángulo en la pantalla, declarativamente usamos un elemento en nuestro DOM. Luego, el navegador dibujará un rectángulo, pero también creará un objeto SVGRectElement en memoria que representa el rectángulo. Este objeto es algo que nos queda para manipular, se conserva. Podemos asignar diferentes posiciones y tamaños a lo largo del tiempo. También podemos adjuntar oyentes de eventos para hacerlo interactivo.
  • Canvas utiliza la representación inmediata : cuando dibujamos un rectángulo , el navegador muestra inmediatamente un rectángulo en la pantalla, pero nunca habrá ningún "objeto rectangular" que lo represente. Solo hay un montón de píxeles en el búfer de lienzo. No podemos mover el rectángulo. Solo podemos dibujar otro rectángulo. No podemos responder a clics u otros eventos en el rectángulo. Solo podemos responder a eventos en todo el lienzo .

Entonces Canvas es una API más restrictiva de bajo nivel que SVG. Pero hay un lado negativo de eso, que es que con el lienzo puedes hacer más con la misma cantidad de recursos. Debido a que el navegador no tiene que crear y mantener el gráfico de objetos en memoria de todas las cosas que hemos dibujado, necesita menos recursos de memoria y cálculo para dibujar la misma escena visual. Si tiene una visualización muy grande y compleja para dibujar, Canvas puede ser su boleto.

Alireza Fattahi
fuente