jquery’s append ne fonctionne pas avec l’élément svg?

En supposant ceci:

    $(document).ready(function(){ $("svg").append(''); });       

Pourquoi je ne vois rien?

Lorsque vous transmettez une chaîne de balisage dans $ , elle est analysée en HTML en utilisant la propriété innerHTML du navigateur sur un

(ou tout autre conteneur approprié pour des cas particuliers comme

). innerHTML ne peut pas parsingr SVG ou tout autre contenu non HTML, et même s’il le pouvait, il ne pourrait pas dire que était censé se trouver dans l’espace de noms SVG.

innerHTML n’est pas disponible sur SVGElement: c’est une propriété de HTMLElement uniquement. Il n’y a pas non plus actuellement de propriété innerSVG ou autre moyen (*) d’parsingr le contenu dans un SVGElement. Pour cette raison, vous devez utiliser des méthodes de style DOM. jQuery ne vous permet pas d’accéder facilement aux méthodes de noms de fichiers nécessaires pour créer des éléments SVG. En réalité, jQuery n’est pas conçu pour être utilisé avec SVG et de nombreuses opérations peuvent échouer.

HTML5 promet de vous permettre d’utiliser sans xmlns dans un document HTML ( text/html ) ordinaire à l’avenir. Mais ce n’est qu’un hack parsingur (**), le contenu SVG sera toujours SVGElements dans l’espace de nommage SVG, et non HTMLElements, vous ne pourrez donc pas utiliser innerHTML même s’il ressemble à un document HTML.

Cependant, pour les navigateurs actuels, vous devez utiliser X HTML (correctement utilisé comme application/xhtml+xml ; enregistrer avec l’extension de fichier .xhtml pour les tests locaux) pour que SVG fonctionne. (Cela a du sens de toute façon; SVG est une norme correctement basée sur XML.) Cela signifie que vous devez échapper aux symboles < intérieur de votre bloc de script (ou inclure une section CDATA) et inclure la déclaration XHTML xmlns . Exemple:

       

*: bien, il y a parseWithContext de DOM Level 3 LS, mais la prise en charge du navigateur est très mauvaise. Modifier pour append: cependant, même si vous ne pouvez pas injecter de balisage dans un SVGElement, vous pouvez injecter un nouveau SVGElement dans un HTMLElement en utilisant innerHTML, puis le transférer sur la cible souhaitée. Ce sera probablement un peu plus lent si:

  

**: Je déteste la façon dont les auteurs de HTML5 semblent avoir peur de XML et sont déterminés à intégrer des fonctionnalités basées sur XML dans le fouillis de code HTML. XHTML a résolu ces problèmes il y a des années.

La réponse acceptée montre une manière trop compliquée. Comme le prétend Forresto dans sa réponse , ” il semble les append dans l’explorateur DOM, mais pas à l’écran “, ce qui s’explique par la différence entre les espaces de noms pour html et svg.

La solution la plus simple consiste à “rafraîchir” tout le svg. Après avoir ajouté un cercle (ou d’autres éléments), utilisez ceci:

 $("body").html($("body").html()); 

Cela fait l’affaire. Le cercle est à l’écran.

Ou si vous voulez, utilisez un div div:

 $("#cont").html($("#cont").html()); 

Et enveloppez votre svg à l’intérieur du conteneur div:

 

L’exemple fonctionnel:
http://jsbin.com/ejifab/1/edit

Les avantages de cette technique:

  • vous pouvez éditer les svg existants (qui sont déjà dans DOM), par exemple. créé en utilisant Raphael ou comme dans votre exemple “codé en dur” sans script.
  • Vous pouvez append des structures d’éléments complexes sous forme de chaînes, par exemple. $('svg').prepend(''); comme vous le faites dans jQuery.
  • après les éléments sont ajoutés et rendus visibles à l’écran en utilisant $("#cont").html($("#cont").html()); leurs atsortingbuts peuvent être édités en utilisant jQuery.

MODIFIER:

La technique ci-dessus fonctionne avec “hard coded” ou DOM manipulé (= document.createElementNS etc.) SVG uniquement. Si Raphael est utilisé pour créer des éléments (selon mes tests), la liaison entre les objects Raphael et SVG DOM est rompue si $("#cont").html($("#cont").html()); est utilisé. La solution à ce problème n’est pas d’utiliser $("#cont").html($("#cont").html()); du tout et au lieu d’utiliser un document SVG factice.

Ce SVG factice est d’abord une représentation textuelle du document SVG et ne contient que les éléments nécessaires. Si nous voulons par exemple pour append un élément de filtre au document de Raphael, le mannequin pourrait être quelque chose comme . La représentation textuelle est d’abord convertie en DOM en utilisant la méthode $ (“body”). Append () de jQuery. Et lorsque l’élément (filter) est dans DOM, il peut être interrogé en utilisant les méthodes standard de jQuery et ajouté au document SVG principal créé par Raphael.

Pourquoi ce mannequin est-il nécessaire? Pourquoi ne pas append un élément de filtre ssortingctement au document créé par Raphael? Si vous l’essayez en utilisant par exemple $("svg").append("") , il est créé en tant qu’élément html et rien n’est à l’écran comme décrit dans les réponses. Mais si tout le document SVG est ajouté, le navigateur gère automatiquement la conversion de tous les éléments du document SVG.

Un exemple éclaire la technique:

 // Add Raphael SVG document to container element var p = Raphael("cont", 200, 200); // Add id for easy access $(p.canvas).attr("id","p"); // Textual representation of element(s) to be added var f = ''; // Create dummy svg with filter definition $("body").append(''); // Append filter definition to Raphael created svg $("#p defs").append($("#dummy filter")); // Remove dummy $("#dummy").remove(); // Now we can create Raphael objects and add filters to them: var r = p.rect(10,10,100,100); $(r.node).attr("filter","url(#myfilter)"); 

La démo complète de cette technique est ici: http://jsbin.com/ilinan/1/edit .

(Je n’ai (encore) aucune idée, pourquoi $("#cont").html($("#cont").html()); ne fonctionne pas avec Raphael. Ce serait très court.)

La bibliothèque D3, de plus en plus populaire, gère les bizarreries d’ajout / manipulation de svg très bien. Vous voudrez peut-être envisager de l’utiliser contrairement aux hacks de jQuery mentionnés ici.

HTML

  

Javascript

 var circle = d3.select("svg").append("circle") .attr("r", "10") .attr("style", "fill:white;stroke:black;stroke-width:5"); 

JQuery ne peut pas append d’éléments à (il semble bien les append dans l’explorateur DOM, mais pas à l’écran).

Une solution consiste à append un à tous les éléments dont vous avez besoin sur la page, puis à modifier les atsortingbuts des éléments à l’aide de .attr() .

 $('body') .append($('')) .mousemove( function (e) { $("#c").attr({ cx: e.pageX, cy: e.pageY }); }); 

http://jsfiddle.net/8FBjb/1/

Je n’ai pas vu quelqu’un mentionner cette méthode, mais document.createElementNS() est utile dans ce cas.

Vous pouvez créer les éléments en utilisant le Javascript de vanille comme des noeuds DOM normaux avec le bon espace de noms, puis jQuery-ify à partir de là. Ainsi:

 var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'), circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); var $circle = $(circle).attr({ //All your atsortingbutes }); $(svg).append($circle); 

Le seul inconvénient est que vous devez créer chaque élément SVG avec le bon espace de noms individuellement ou cela ne fonctionnera pas.

Je peux voir le cercle dans Firefox, en faisant 2 choses:

1) Renommer le fichier de html à xhtml

2) Changer le script en

  

J’ai trouvé un moyen simple qui fonctionne avec tous les navigateurs que je possède (Chrome 49, Edge 25, Firefox 44, IE11, Safari 5 [Win], Safari 8 (MacOS)):

 // Clean svg content (if you want to update the svg's objects) // Note : .html('') doesn't works for svg in some browsers $('#svgObject').empty(); // add some objects $('#svgObject').append(''); $('#svgObject').append(''); // Magic happens here: refresh DOM (you must refresh svg's parent for Edge/IE and Safari) $('#svgContainer').html($('#svgContainer').html()); 
 .svgStyle { fill:cornflowerblue; fill-opacity:0.2; stroke-width:2; stroke-dasharray:5,5; stroke:black; } 
  
It works if two shapes (one square and one circle) are displayed above.

Basé sur la réponse de @chris-dolphin mais utilisant la fonction assistant:

 // Creates svg element, returned as jQuery object function $s(elem) { return $(document.createElementNS('http://www.w3.org/2000/svg', elem)); } var $svg = $s("svg"); var $circle = $s("circle").attr({...}); $svg.append($circle); 

Si la chaîne à append est SVG et que vous ajoutez le bon espace de noms, vous pouvez parsingr la chaîne en XML et l’append au parent.

 var xml = jQuery.parseXML(''); $("svg").append(xml.documentElement)) 

La réponse acceptée par Bobince est une solution courte et portable. Si vous devez non seulement append SVG mais aussi le manipuler, vous pouvez essayer la bibliothèque JavaScript “Pablo” (je l’ai écrite). Il sera familier aux utilisateurs de jQuery.

Votre exemple de code ressemblerait alors à:

 $(document).ready(function(){ Pablo("svg").append(''); }); 

Vous pouvez également créer des éléments SVG à la volée, sans spécifier de balisage:

 var circle = Pablo.circle({ cx:100, cy:50, r:40 }).appendTo('svg'); 

Je suggérerais qu’il serait préférable d’utiliser ajax et de charger l’élément svg à partir d’une autre page.

 $('.container').load(href + ' .svg_element'); 

Où href est l’emplacement de la page avec le svg. De cette façon, vous pouvez éviter les effets de choc liés au remplacement du contenu HTML. De plus, n’oubliez pas de déballer le svg après son chargement:

 $('.svg_element').unwrap(); 
  var svg; // if you have variable declared and not assigned value. // then you make a mistake by appending elements to that before creating element svg.appendChild(document.createElement("g")); // at some point you assign to svg svg = document.createElementNS('http://www.w3.org/2000/svg', "svg") // then you put it in DOM document.getElementById("myDiv").appendChild(svg) // it wont render unless you manually change myDiv DOM with DevTools // to fix assign before you append var svg = createElement("svg", [ ["version", "1.2"], ["xmlns:xlink", "http://www.w3.org/1999/xlink"], ["aria-labelledby", "title"], ["role", "img"], ["class", "graph"] ]); function createElement(tag, atsortingbuteArr) { // .createElementNS NS is must! Does not draw without let elem = document.createElementNS('http://www.w3.org/2000/svg', tag); atsortingbuteArr.forEach(element => elem.setAtsortingbute(element[0], element[1])); return elem; } // extra:  for example requires atsortingbutes to render. Check if missing. 

Cela fonctionne pour moi aujourd’hui avec FF 57:

 function () { // JQuery, today, doesn't play well with adding SVG elements - sortingcks required $(selector_to_node_in_svg_doc).parent().prepend($(this).clone().text("Your")); $(selector_to_node_in_svg_doc).text("New").attr("x", "340").text("New") .attr('stroke', 'blue').attr("style", "text-decoration: line-through"); } 

Fait du:

cette image SVG vue dans Firefox 57

Une méthode beaucoup plus simple consiste à générer votre SVG dans une chaîne, à créer un élément HTML d’encapsulation et à insérer la chaîne svg dans l’élément HTML à l’aide de $("#wrapperElement").html(svgSsortingng) . Cela fonctionne très bien dans Chrome et Firefox.