HTML5 Canvas vs SVG vs div

476

Quelle est la meilleure approche pour créer des éléments à la volée et pouvoir les déplacer? Par exemple, disons que je veux créer un rectangle, un cercle et un polygone, puis sélectionner ces objets et les déplacer.

Je comprends que HTML5 fournit trois éléments qui peuvent rendre cela possible: svg , canvas et div . Pour ce que je veux faire, lequel de ces éléments offrira les meilleures performances?

Pour comparer ces approches, je pensais créer trois pages Web visuellement identiques qui contiennent chacune un en-tête, un pied de page, un widget et un contenu textuel. Le widget de la première page serait entièrement créé avec l' canvasélément, le second entièrement avec l' svgélément et le troisième avec l' divélément simple , HTML et CSS.

verdy
la source
13
Vous pourriez trouver cela intéressant: Réflexions sur le moment d'utiliser Canvas et SVG .
robertc
1
Pour ceux d'entre vous qui débutent dans cette technologie, cette vidéo couvre à la fois SVG et Canvas et d'autres détails sur la façon dont cela s'intègre sur html5.
Paulo Bueno
12
Réponse courte: Canvas est à MS Paint comme SVG à MS Powerpoint. La toile est raster, le SVG est vectoriel.
GetFree
2
Cher lecteur: prenez toutes les comparaisons et déclarations ici avec un grain de sel et regardez la date des articles et des commentaires. Les temps ont changé et vont changer. Les performances relatives et même les options dont vous disposez changeront. Par exemple, la plupart des réponses étaient écrites alors qu'il n'y avait pas de WebGL, ce qui est certainement une alternative - il sera également dépassé dans quelques années, mais à ce jour, il peut être très pertinent.
Sebastian
@Sebastian, que recommanderiez-vous aujourd'hui? si on lui donne une taille de base (par exemple, 1280x800) et si vous êtes prêt à mettre à l'échelle des éléments manuellement dans le code ou à utiliser des pourcentages tout le temps, y a-t-il un avantage de SVG à utiliser des DIV?
Crashalot

Réponses:

563

La réponse courte:

SVG serait plus facile pour vous, car la sélection et le déplacement sont déjà intégrés. Les objets SVG sont des objets DOM, donc ils ont des gestionnaires de "clic", etc.

Les DIVs sont corrects mais maladroits et ont un chargement de performance horrible en grand nombre.

Canvas a les meilleures performances de haut en bas, mais vous devez implémenter vous-même tous les concepts d'état géré (sélection d'objet, etc.) ou utiliser une bibliothèque.


La réponse longue:

HTML5 Canvas est simplement une surface de dessin pour une bitmap. Vous configurez pour dessiner (disons avec une couleur et une épaisseur de ligne), dessinez cette chose, puis le canevas n'a aucune connaissance de cette chose: il ne sait pas où il se trouve ni ce que vous venez de dessiner, c'est juste des pixels. Si vous voulez dessiner des rectangles et les faire se déplacer ou être sélectionnables, vous devez coder tout cela à partir de zéro, y compris le code pour vous rappeler que vous les avez dessinés.

SVG d'autre part doit maintenir des références à chaque objet qu'il rend. Chaque élément SVG / VML que vous créez est un véritable élément dans le DOM. Par défaut, cela vous permet de garder une bien meilleure trace des éléments que vous créez et facilite le traitement des choses comme les événements de souris par défaut, mais cela ralentit considérablement lorsqu'il y a un grand nombre d'objets

Ces références DOM SVG signifient qu'une partie du jeu de jambes avec les choses que vous dessinez est faite pour vous. Et SVG est plus rapide lors du rendu de très gros objets, mais plus lent lors du rendu de nombreux objets.

Un jeu serait probablement plus rapide dans Canvas. Un énorme programme de carte serait probablement plus rapide en SVG. Si vous souhaitez utiliser Canvas, j'ai quelques tutoriels pour installer et exécuter des objets mobiles ici .

Le canevas serait préférable pour des choses plus rapides et une manipulation bitmap lourde (comme l'animation), mais prendra plus de code si vous voulez beaucoup d'interactivité.

J'ai exécuté un tas de chiffres sur le dessin HTML DIV par rapport au dessin Canvas. Je pourrais faire un énorme article sur les avantages de chacun, mais je donnerai certains des résultats pertinents de mes tests à considérer pour votre application spécifique:

J'ai fait des pages de test Canvas et HTML DIV, les deux avaient des «nœuds» mobiles. Les nœuds de canevas sont des objets que j'ai créés et dont je garde la trace en Javascript. Les nœuds HTML étaient des Divs mobiles.

J'ai ajouté 100 000 nœuds à chacun de mes deux tests. Ils ont joué assez différemment:

L'onglet de test HTML a pris une éternité à charger (chronométré à un peu moins de 5 minutes, Chrome a demandé de tuer la page la première fois). Le gestionnaire de tâches de Chrome indique que l'onglet occupe 168 Mo. Cela prend 12-13% de temps CPU quand je le regarde, 0% quand je ne le regarde pas.

L'onglet Canvas chargé en une seconde et prend 30 Mo. Cela prend également 13% du temps CPU tout le temps, que l'on le regarde ou non. (Édition 2013: Ils ont principalement corrigé cela)

Faire glisser sur la page HTML est plus fluide, ce qui est attendu par la conception, car la configuration actuelle consiste à tout redessiner toutes les 30 millisecondes dans le test Canvas. Il existe de nombreuses optimisations pour Canvas pour cela. (l'invalidation du canevas étant la plus simple, le découpage des régions, le redessin sélectif, etc. dépend juste de ce que vous avez envie d'implémenter)

Il ne fait aucun doute que Canvas pourrait être plus rapide dans la manipulation d'objets que les divs dans ce test simple, et bien sûr beaucoup plus rapide dans le temps de chargement. Le dessin / chargement est plus rapide dans Canvas et a beaucoup plus de place pour les optimisations (c'est-à-dire qu'il est très facile d'exclure les choses hors écran).

Conclusion:

  • SVG est probablement meilleur pour les applications et les applications avec peu d'éléments (moins de 1000? Cela dépend vraiment)
  • Canvas est meilleur pour des milliers d'objets et une manipulation soigneuse, mais beaucoup plus de code (ou une bibliothèque) est nécessaire pour le faire décoller.
  • Les divs HTML sont maladroits et ne sont pas mis à l'échelle, faire un cercle n'est possible qu'avec des coins arrondis, faire des formes complexes est possible mais implique des centaines de minuscules divs à l'échelle du pixel. La folie s'ensuit.
Simon Sarris
la source
4
La bibliothèque Cake est un autre exemple de création d'objets mobiles et d'animations avec des objets sur une toile
SiggyF
Mauvais: P div peut évoluer si le navigateur utilise le moteur CSS accéléré hw, l'art CSS est différent et en plus de Canvas et SVG sont le bon choix ici, l'art CSS / art div est juste quand vous n'avez pas besoin de surpasser juste une petite superposition: P
ShrekOverflow
Concernant les DIVs, si vous voulez faire des cercles / formes spéciales et ne va pas changer son image / sprite en temps voulu, vous pouvez simplement créer un PNG et l'utiliser comme background-image... Bien que vous puissiez faire des choses similaires dans SVG / Canvas
luiges90
4
Et si vous créez un jeu de cartes interactif? : p
Anthony
Cela a été créé à l'aide de DIVs (non imbriqués) et de transformations CSS 3D, donc je dirais que les DIVs ne sont pas lents du tout: youtube.com/watch?v=fzBC20B5dsk
Erik Kaplun
39

Pour ajouter à cela, j'ai fait une application de diagramme et j'ai d'abord commencé avec canvas. Le diagramme comprend de nombreux nœuds et ils peuvent devenir assez volumineux. L'utilisateur peut faire glisser des éléments dans le diagramme.

Ce que j'ai trouvé, c'est que sur mon Mac, pour les très grandes images, SVG est supérieur. J'ai un MacBook Pro 2013 13 "Retina, et il exécute assez bien le violon ci-dessous. L'image est 6000x6000 pixels, et a 1000 objets. Une construction similaire en toile était impossible à animer pour moi lorsque l'utilisateur faisait glisser des objets dans le diagramme.

Sur les écrans modernes, vous devez également prendre en compte différentes résolutions, et ici SVG vous donne tout cela gratuitement.

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

Plein écran: 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
la source
2
Nous nous sommes également installés sur SVG, après avoir désespérément essayé de faire travailler Canvas pour nous. Nous avons un très grand diagramme et SVG était de loin le plus efficace, plus la mise à l'échelle automatique sur les écrans de la rétine est un énorme bonus.
Fijjit
knut et @Fijjit avez-vous envisagé d'utiliser des DIV au lieu de SVG? si on leur donne une taille de base (par exemple, 1280x800), ne pourriez-vous pas mettre à l'échelle manuellement les DIVs pour qu'ils soient aussi nets que SVG? Merci de votre aide!
Crashalot
24

Connaître les différences entre SVG et Canvas serait utile pour sélectionner le bon.

Toile

SVG

  • Indépendant de la résolution
  • Prise en charge des gestionnaires d'événements
  • Idéal pour les applications avec de grandes zones de rendu (Google Maps)
  • Rendu lent si complexe (tout ce qui utilise beaucoup le DOM sera lent)
  • Ne convient pas pour une application de jeu
Leo The Four
la source
8
pourquoi les gens disent que Canvas dépend de la résolution? Je comprends qu'une fois que le bitmap a été rendu, il ne s'ajuste pas bien. mais vous pouvez redessiner les changements de taille de résolution, alors comment cette résolution n'est-elle pas indépendante?
Alex Bollbach
@AlexBollbach - Canvas dépend de la résolution, car vous devez prendre en compte (dépendre) de la résolution afin d'obtenir de bons résultats. Avec SVG, vous ne vous souciez pas de la résolution. Bonne chance pour obtenir des lignes non irrégulières sur une imprimante 2400 DPI et un rendu basé sur Canvas. Aucun problème avec SVG.
Sebastian
18

Je suis d'accord avec les conclusions de Simon Sarris:

J'ai comparé certaines visualisations dans Protovis (SVG) à Processingjs (Canvas) qui affichent> 2000 points et processingjs est beaucoup plus rapide que protovis.

La gestion des événements avec SVG est bien sûr beaucoup plus simple car vous pouvez les attacher aux objets. Dans Canvas, vous devez le faire manuellement (vérifier la position de la souris, etc.) mais pour une interaction simple, cela ne devrait pas être difficile.

Il y a aussi le dojo.gfx bibliothèque de la boîte à outils dojo. Il fournit une couche d'abstraction et vous pouvez spécifier le rendu (SVG, Canvas, Silverlight). Cela pourrait également être un choix viable même si je ne sais pas combien de temps supplémentaire la couche d'abstraction supplémentaire ajoute, mais cela facilite le codage des interactions et des animations et est indépendant du rendu.

Voici quelques repères intéressants:

Ümit
la source
17

Juste mes 2 cents concernant l'option divs.

Fams / Infamous et SamsaraJS (et peut-être d'autres) utilisent des divs non imbriqués absolument positionnés (avec un contenu HTML / CSS non trivial), combinés avec matrix2d / matrix3d ​​pour le positionnement et les transformations 2D / 3D, et atteignent un 60FPS stable sur du matériel mobile modéré , donc je plaiderais contre le fait que les divs soient une option lente.

Il y a beaucoup d'enregistrements d'écran sur Youtube et ailleurs, de trucs 2D / 3D haute performance fonctionnant dans le navigateur avec tout étant un élément DOM sur lequel vous pouvez inspecter l'élément , à 60FPS (mélangé avec WebGL pour certains effets, mais pas pour le partie principale du rendu).

Erik Kaplun
la source
14

Bien qu'il y ait encore du vrai dans la plupart des réponses ci-dessus, je pense qu'elles méritent une mise à jour:

Au fil des ans, les performances de SVG se sont beaucoup améliorées et il existe maintenant des transitions CSS et des animations accélérées par le matériel pour SVG qui ne dépendent pas du tout des performances JavaScript. Bien sûr, les performances JavaScript se sont également améliorées et avec elles, les performances de Canvas, mais pas autant que SVG ont été améliorées. Il y a aussi un "nouveau venu" sur le bloc qui est disponible dans presque tous les navigateurs aujourd'hui et c'est WebGL . Pour utiliser les mêmes mots que Simon a utilisé ci-dessus: Il bat à la fois Canvas et SVG haut la main. Cela ne signifie pas que ce devrait être la technologie de choix, car c'est une bête avec laquelle travailler et elle n'est plus rapide que dans des cas d'utilisation très spécifiques.

À mon humble avis pour la plupart des cas d'utilisation aujourd'hui, SVG offre le meilleur rapport performances / convivialité. Les visualisations doivent être vraiment complexes (par rapport au nombre d'éléments) et vraiment simples à la fois (par élément) pour que Canvas et plus encore WebGL brille vraiment.

Dans cette réponse à une question similaire, je donne plus de détails, pourquoi je pense que la combinaison des trois technologies est parfois la meilleure option que vous avez.

Sébastien
la source
Les utilisateurs d'Unix doivent prendre note que l'accélération matérielle est désactivée par défaut sur Firefox et Chromium, toujours vrai à la mi
2019.
@NVRM - il s'agit de l'accélération matérielle de CSS et SVG, pas du décodage vidéo. AFAIK l'ancien est disponible depuis des années: Vérifier la sortie du chrome: // gpu
Sebastian
layers.acceleration.force-enableddans Firefox ne concerne pas le décodage vidéo. C'est un fait bien connu. Lorsque vous avez terminé les boucles à l'aide de requestAnimationFrame est un autre niveau, permettant ainsi plus de repeints. Pas du tout sur la vidéo.
NVRM
@NVRM - pouvez-vous fournir des liens vers les bogues FF et Chromium pour ces problèmes de GPU sous Linux, s'il vous plaît? Notez également que par "accélération matérielle", je ne faisais pas seulement référence à l'accélération GPU, mais également à la composition et aux animations multithreads, comme par exemple le chargement de filateurs qui continuent de tourner sans JavaScript ou pendant l' exécution de JS. C'est impossible avec Canvas et par rapport au pur "JavaScript" c'est en effet une sorte d'accélération matérielle (multi-threading) qui est définitivement disponible dans Chrome et FF sur toutes les plateformes. Merci!
Sebastian
1
Pour résumer la situation actuelle: Fonctionne pour moi sur Chrome et Chrome. Sous Linux. En 2019. Sur toutes les instances, j'ai testé sans configuration spéciale. Firefox / Mozilla y travaille pour Linux , cependant le rendu hors processus n'est pas quelque chose de nouveau pour FF non plus et fonctionnera toujours mieux avec SVG, CSS, etc. qu'il ne peut avec Canvas.
Sebastian
13

Pour vos besoins, je recommande d'utiliser SVG, car vous obtenez des événements DOM, comme la gestion de la souris, y compris le glisser-déposer, inclus, vous n'avez pas à implémenter votre propre redessin, et vous n'avez pas à suivre l'état de vos objets. Utilisez Canvas lorsque vous devez manipuler des images bitmap et utilisez un div normal lorsque vous souhaitez manipuler des éléments créés en HTML. En ce qui concerne les performances, vous constaterez que les navigateurs modernes accélèrent désormais tous les trois, mais que le canevas a reçu le plus d'attention jusqu'à présent. D'un autre côté, la façon dont vous écrivez votre javascript est essentielle pour obtenir le plus de performances avec le canevas, donc je recommanderais toujours d'utiliser SVG.

Gaurav
la source
1
En fait, l'utilisation de HTML simple est la plus performante en combinaison avec des images CSS.
Raynos
16
@Raynos: Source?
Janus Troelsen
3

Lors de la recherche sur Google, je trouve une bonne explication sur l'utilisation et la compression de SVG et de Canvas sur http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html

J'espère que cela aide:

  • SVG, comme HTML, utilise le rendu retenu : Lorsque nous voulons dessiner un rectangle à l'écran, nous utilisons déclarativement un élément dans notre DOM. Le navigateur dessinera alors un rectangle, mais il créera également un objet SVGRectElement en mémoire qui représente le rectangle. Cet objet est quelque chose qui nous reste à manipuler - il est conservé. Nous pouvons lui attribuer différentes positions et tailles au fil du temps. Nous pouvons également attacher des écouteurs d'événements pour le rendre interactif.
  • Canvas utilise un rendu immédiat : lorsque nous dessinons un rectangle , le navigateur affiche immédiatement un rectangle à l'écran, mais aucun "objet rectangle" ne le représentera. Il y a juste un tas de pixels dans le tampon de toile. Nous ne pouvons pas déplacer le rectangle. Nous ne pouvons que dessiner un autre rectangle. Nous ne pouvons pas répondre aux clics ou autres événements sur le rectangle. Nous ne pouvons répondre qu'aux événements sur l' ensemble du canevas .

Canvas est donc une API de plus bas niveau et plus restrictive que SVG. Mais il y a un revers à cela, c'est qu'avec le canevas, vous pouvez faire plus avec la même quantité de ressources. Parce que le navigateur n'a pas à créer et à maintenir le graphe d'objets en mémoire de toutes les choses que nous avons dessinées, il a besoin de moins de mémoire et de ressources de calcul pour dessiner la même scène visuelle. Si vous avez une visualisation très grande et complexe à dessiner, Canvas peut être votre ticket.

Alireza Fattahi
la source