web-dev-qa-db-fra.com

HTML5 Canvas vs SVG vs div

Quelle est la meilleure approche pour créer des éléments à la volée et pouvoir les déplacer? Par exemple, supposons que je souhaite 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 pouvant rendre cela possible: svg , canvas et div . Pour ce que je veux faire, lequel de ces éléments fournira la meilleure performance?

Pour comparer ces approches, je pensais créer trois pages Web visuellement identiques, chacune contenant 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’élément canvas, le deuxième entièrement avec l’élément svg et le troisième avec l’élément plain div, HTML et CSS.

442
verdy

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, ils ont donc des gestionnaires "de clic", etc.

Les DIV sont correctes mais maladroites et ont des performances de charge épouvantables à grands nombres.

Canvas offre les meilleures performances, 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 un bitmap. Vous êtes prêt à dessiner (dites avec une couleur et une épaisseur de trait), 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 déplacer ou les sélectionner, vous devez tout coder à partir de zéro, , y compris le code pour vous rappeler que vous les a dessinés.

En revanche, SVG doit conserver des références à chaque objet rendu. Chaque élément SVG/VML que vous créez est un élément réel du DOM. Par défaut, cela vous permet de garder un meilleur suivi des éléments que vous créez et facilite par défaut le traitement des événements tels que les événements de souris, 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 travail pour traiter les choses que vous dessinez est faite pour vous. Et SVG est plus rapide lors du rendu d'objets très volumineux , mais plus lent lors du rendu de nombreux objets .

Un jeu serait probablement plus rapide dans Canvas. Un vaste programme de cartes serait probablement plus rapide en SVG. Si vous voulez utiliser Canvas, j'ai quelques tutoriels sur la mise en place d'objets mobiles ici .

Canvas serait mieux pour les choses plus rapides et les manipulations de bitmap lourdes (comme l'animation), mais nécessitera plus de code si vous voulez beaucoup d'interactivité.

J'ai passé beaucoup de chiffres sur le dessin HTML créé par DIV par rapport au dessin fait sur Canvas. Je pourrais écrire énormément sur les avantages de chacun, mais je donnerai quelques résultats pertinents de mes tests à prendre en compte pour votre application spécifique:

J'ai créé les pages de test Canvas et HTML DIV, toutes deux comportant des "nœuds" amovibles. Les nœuds de toile sont des objets que j'ai créés et suivis en Javascript. Les nœuds HTML étaient des Div mobiles.

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

Le chargement de l’onglet test HTML a pris une éternité (légèrement inférieur à 5 minutes, chrome invité à supprimer la page la première fois). Le gestionnaire de tâches de Chrome indique que cet onglet occupe 168 Mo. Cela prend 12-13% de temps CPU quand je le regarde, 0% quand je ne regarde pas.

L'onglet Toile chargé en une seconde et occupe 30 Mo. De plus, il occupe tout le temps 13% du temps processeur, qu'on le voie ou non. (édition de 2013: ils ont généralement résolu ce problème)

Le glisser sur la page HTML est plus fluide, comme prévu par la conception, car la configuration actuelle consiste à redessiner TOUT en 30 millisecondes dans le test de Canvas. Canvas dispose de nombreuses optimisations à cet égard. (L’invalidation de la toile étant la plus facile, également les régions de découpage, le redessinage sélectif, etc., cela dépend de la mesure dans laquelle vous avez envie de la mettre en œuvre)

Il ne fait aucun doute que vous pouvez obtenir que Canvas accélère la manipulation des objets en tant que divs dans ce test simple et, bien entendu, beaucoup plus rapidement lors du chargement. Le dessin/chargement est plus rapide dans Canvas et offre beaucoup plus d'espace d'optimisation (par exemple, il est très facile d'exclure des éléments hors écran).

Conclusion:

  • SVG est probablement mieux pour les applications et les applications avec peu d'éléments (moins de 1000? Cela dépend vraiment)
  • Canvas est préférable pour des milliers d'objets et pour une manipulation minutieuse, mais il faut beaucoup plus de code (ou une bibliothèque) pour le faire démarrer.
  • Les divs HTML sont maladroits et n’ont pas d’échelle; créer un cercle n’est possible qu’avec des angles arrondis; créer des formes complexes est possible, mais implique des centaines de minuscules divs de pixel-large. La folie s'ensuit.
535
Simon Sarris

Pour ajouter à cela, j'ai créé une application de diagramme et commencé avec canvas. Le diagramme se compose de plusieurs noeuds et ils peuvent devenir assez gros. 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, le format SVG est supérieur. J'ai un MacBook Pro 2013 13 "Retina, et le violon ci-dessous fonctionne très bien. L'image mesure 6000 x 6000 pixels et 1000 objets. Une construction similaire dans le canevas m'était impossible à animer lorsque l'utilisateur faisait glisser des objets dans le diagramme.

Sur les écrans modernes, vous devez également prendre en compte différentes résolutions. 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);
38
knut

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

Toile

SVG

  • Résolution indépendante
  • Support pour les 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
22
Leo The Four

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

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

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

Il existe également la bibliothèque dojo.gfx du toolkit dojo. Il fournit une couche d'abstraction et vous pouvez spécifier le rendu (SVG, Canvas, Silverlight). C’est peut-être aussi un choix viable, bien que je ne sache pas combien de temps la couche d’abstraction supplémentaire ajoute, mais cela facilite le codage des interactions et des animations et rend le rendu indépendant du rendu.

Voici quelques repères intéressants:

18
Ümit

Juste mes 2 cents en ce qui concerne l'option divs.

Famous/Infamous et SamsaraJS (et éventuellement d’autres) utilisent des divs non imbriqués positionnés de manière absolue (avec un contenu HTML/CSS non trivial), associés à matrix2d/matrix3d ​​pour le positionnement et les transformations 2D/3D, et permettent de réaliser une image stable à 60FPS sur du matériel mobile modéré , donc je dirais que les divs ne sont pas une option lente.

Il existe de nombreux enregistrements d'écran sur Youtube et ailleurs, de contenus 2D/3D hautes performances exécutés dans le navigateur, le tout étant un élément DOM que vous pouvez Inspect Element on, à 60FPS certains effets, mais pas pour la partie principale du rendu).

16
Erik Allik

Bien que la plupart des réponses ci-dessus contiennent encore une part de vérité, 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ération matérielle pour SVG qui ne dépendent pas des performances de JavaScript à tout. Bien sûr, les performances de JavaScript se sont également améliorées et avec celles de Canvas, mais pas autant que SVG. En outre, il existe un "nouvel enfant" sur le bloc qui est disponible dans presque tous les navigateurs actuels et qui est WebGL . Pour utiliser les mêmes mots que Simon a utilisés ci-dessus: It bat haut et fort Canvas et SVG . Cela ne signifie pas pour autant qu'il s'agisse d'une technologie de choix, car c'est une bête avec laquelle travailler et ce n'est que plus rapide dans des cas d'utilisation très spécifiques.

IMHO pour la plupart des cas d'utilisation aujourd'hui, SVG offre le meilleur rapport performances/utilisabilité. Les visualisations doivent être très complexes (en termes de nombre d'éléments) et très simples en même temps (par élément) pour que Canvas et plus encore WebGL brillent vraiment.

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

14
Sebastian

Pour vos besoins, je vous recommande d’utiliser SVG, car vous avez inclus les événements DOM, tels que la manipulation de la souris, y compris le glisser-déposer, vous n’aurez pas à mettre en œuvre votre propre rafraîchissement, ni à suivre l’état de vos objets. Utilisez Canvas lorsque vous devez manipuler des images bitmap et utilisez une div régulière 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 les trois, mais que cette toile a suscité le plus d'attention jusqu'à présent. D'autre part, la qualité de l'écriture de votre javascript est essentielle pour obtenir les meilleures performances possibles avec canvas, je vous recommande donc toujours d'utiliser SVG.

13
Gaurav

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

J'espère que ça aide:

  • SVG, comme HTML, utilise le rendu conservé : Lorsque nous voulons dessiner un rectangle à l'écran, nous utilisons de manière déclarative un élément dans notre DOM. Le navigateur dessine alors un rectangle, mais crée également un objet SVGRectElement ​​en mémoire qui représente le rectangle. Cet objet est quelque chose qui reste à manipuler pour nous - il est conservé. Nous pouvons lui attribuer différentes positions et tailles au fil du temps. Nous pouvons également attacher des auditeurs d'événements pour le rendre interactif.
  • Canvas utilise le rendu immédiat : lorsque nous dessinons un rectangle , le navigateur affiche immédiatement un rectangle à l'écran, mais il n'y a jamais va être un "objet rectangle" qui le représente. Il y a juste un tas de pixels dans le tampon de canevas. Nous ne pouvons pas déplacer le rectangle. Nous pouvons seulement dessiner un autre rectangle. Nous ne pouvons pas répondre aux clics ou autres événements sur le rectangle. Nous ne pouvons répondre aux événements que sur le canevas entier .

Donc, canvas est une API plus restrictive que SVG. Mais il y a un inconvénient à cela: avec canvas, vous pouvez faire plus avec la même quantité de ressources. Comme le navigateur n'a pas à créer ni à gérer le graphe d'objets en mémoire de tout ce que nous avons dessiné, 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.

2
Alireza Fattahi