Lorsque vous passez une chaîne de balisage dans $
, elle est analysée en HTML en utilisant la innerHTML
propriété du navigateur sur un <div>
(ou un autre conteneur approprié pour des cas spéciaux comme <tr>
). innerHTML
ne peut pas analyser SVG ou tout autre contenu non HTML, et même s'il le pouvait, il ne pourrait pas dire qu'il <circle>
é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’existe pas non plus deinnerSVG
propriété ou d'autre moyen (*) pour analyser le contenu dans un SVGElement. Pour cette raison, vous devez utiliser des méthodes de style DOM. jQuery ne vous donne pas un accès facile aux méthodes d'espaces de noms nécessaires pour créer des éléments SVG. Vraiment, jQuery n'est pas du tout conçu pour être utilisé avec SVG et de nombreuses opérations peuvent échouer.
HTML5 promet de vous permettre d'utiliser <svg>
sans l' xmlns
intérieur d'un text/html
document HTML ( ) simple à l'avenir. Mais il ne s'agit que d'un piratage de l'analyseur (**), le contenu SVG sera toujours des SVGElements dans l'espace de noms SVG, et non des HTMLElements, vous ne pourrez donc pas l'utiliser innerHTML
même s'ils ressemblent à une partie d'un document HTML.
Cependant, pour les navigateurs d'aujourd'hui, vous devez utiliser X HTML (correctement servi en tant que 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 les <
symboles à l'intérieur de votre bloc de script (ou les enfermer dans une section CDATA) et inclure la xmlns
déclaration XHTML . exemple:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head>
</head><body>
<svg id="s" xmlns="http://www.w3.org/2000/svg"/>
<script type="text/javascript">
function makeSVG(tag, attrs) {
var el= document.createElementNS('http://www.w3.org/2000/svg', tag);
for (var k in attrs)
el.setAttribute(k, attrs[k]);
return el;
}
var circle= makeSVG('circle', {cx: 100, cy: 50, r:40, stroke: 'black', 'stroke-width': 2, fill: 'red'});
document.getElementById('s').appendChild(circle);
circle.onmousedown= function() {
alert('hello');
};
</script>
</body></html>
*: bien, il y a parseWithContext de DOM Level 3 LS , mais le support du navigateur est très pauvre. Modifier pour ajouter: cependant, même si vous ne pouvez pas injecter de balisage dans un SVGElement, vous pouvez injecter un nouveau SVGElement dans un HTMLElement à l'aide innerHTML
, puis le transférer vers la cible souhaitée. Ce sera probablement un peu plus lent cependant:
<script type="text/javascript"><![CDATA[
function parseSVG(s) {
var div= document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
div.innerHTML= '<svg xmlns="http://www.w3.org/2000/svg">'+s+'</svg>';
var frag= document.createDocumentFragment();
while (div.firstChild.firstChild)
frag.appendChild(div.firstChild.firstChild);
return frag;
}
document.getElementById('s').appendChild(parseSVG(
'<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" onmousedown="alert(\'hello\');"/>'
));
]]></script>
**: Je déteste la façon dont les auteurs de HTML5 semblent avoir peur du XML et sont déterminés à déchaîner les fonctionnalités basées sur XML dans le désordre cruel qu'est le HTML. XHTML a résolu ces problèmes il y a des années.
RMB
>edit as html
sur la balise html et appuyez sur Entrée, tout s'affiche (mais tous les écouteurs d'événement disparaissent). Après avoir lu cette réponse, j'ai changé mes appels createElement en createElementNS et maintenant tout fonctionne!d3.select('body').append('svg').attr('width','100%');
$.parseXML
.La réponse acceptée montre de manière trop compliquée. Comme Forresto le prétend dans sa réponse , " il semble les ajouter dans l'explorateur DOM, mais pas à l'écran " et la raison en est les différents espaces de noms pour html et svg.
La solution de contournement la plus simple consiste à "actualiser" l'ensemble du svg. Après avoir ajouté un cercle (ou d'autres éléments), utilisez ceci:
Cela fait l'affaire. Le cercle est à l'écran.
Ou si vous le souhaitez, utilisez un conteneur div:
Et enveloppez votre svg à l'intérieur du conteneur div:
L'exemple fonctionnel:
http://jsbin.com/ejifab/1/edit
Les avantages de cette technique:
$('svg').prepend('<defs><marker></marker><mask></mask></defs>');
comme vous le faites dans jQuery.$("#cont").html($("#cont").html());
leurs attributs, vous pouvez les modifier à l'aide de jQuery.ÉDITER:
La technique ci-dessus fonctionne uniquement avec SVG "codé en dur" ou manipulé par DOM (= document.createElementNS etc.). Si Raphael est utilisé pour créer des éléments, (selon mes tests) la liaison entre les objets Raphael et SVG DOM est rompue si elle
$("#cont").html($("#cont").html());
est utilisée. La solution de contournement est de ne pas utiliser$("#cont").html($("#cont").html());
du tout et 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 ajouter un élément de filtre au document Raphael, le mannequin pourrait être quelque chose comme
<svg id="dummy" style="display:none"><defs><filter><!-- Filter definitons --></filter></defs></svg>
. La représentation textuelle est d'abord convertie en DOM à l'aide de la méthode $ ("body"). Append () de jQuery. Et lorsque l'élément (filtre) est dans DOM, il peut être interrogé à l'aide des méthodes jQuery standard et ajouté au document SVG principal créé par Raphael.Pourquoi ce mannequin est nécessaire? Pourquoi ne pas ajouter un élément de filtre strictement au document créé par Raphael? Si vous l'essayez en utilisant par exemple.
$("svg").append("<circle ... />")
, il est créé en tant qu'élément html et rien n'est à l'écran comme décrit dans les réponses. Mais si l'ensemble du document SVG est ajouté, le navigateur gère automatiquement la conversion de l'espace de noms de tous les éléments du document SVG.Un exemple éclaire la technique:
La démonstration complète de cette technique est disponible ici: http://jsbin.com/ilinan/1/edit .
(Je n'ai (encore) aucune idée, pourquoi
$("#cont").html($("#cont").html());
ne fonctionne pas lors de l'utilisation de Raphaël. Ce serait un hack très court.)la source
$("#cont").html($("#cont").html());
fonctionnait très bien dans Chrome, mais ne fonctionnait pas dans IE 11 pour moi.Le D3 de plus en plus populaire bibliothèque gère très bien les bizarreries de l'ajout / manipulation de svg. Vous voudrez peut-être envisager de l'utiliser contrairement aux hacks jQuery mentionnés ici.
HTML
Javascript
la source
JQuery ne peut pas ajouter d'éléments
<svg>
(il semble les ajouter dans l'explorateur DOM, mais pas à l'écran).Une solution consiste à ajouter un
<svg>
avec tous les éléments dont vous avez besoin à la page, puis à modifier les attributs des éléments à l'aide.attr()
.http://jsfiddle.net/8FBjb/1/
la source
<circle>
ou d'autres éléments individuellement à l'aide de méthodes DOM complexes et lentes (par exemple,createDocumentFragment()
oucreateElementNS()
), ajoutez tout le document svg dans le conteneur. Au lieu de $ ('body'), il peut aussi s'agir de $ ('div'). Et après cela, le document svg est sur DOM et peut être interrogé de manière familière en utilisant par exemple. $ ('c'). attr ('fill', 'red').Je n'ai vu personne mentionner cette méthode mais
document.createElementNS()
est utile dans ce cas.Vous pouvez créer les éléments en utilisant vanilla Javascript comme nœuds DOM normaux avec l'espace de nom correct, puis les jQuery-ify à partir de là. Ainsi:
Le seul inconvénient est que vous devez créer chaque élément SVG avec le bon espace de noms individuellement, sinon cela ne fonctionnera pas.
la source
J'ai trouvé un moyen simple qui fonctionne avec tous les navigateurs que j'ai (Chrome 49, Edge 25, Firefox 44, IE11, Safari 5 [Win], Safari 8 (MacOS)):
la source
Je peux voir un cercle dans Firefox, faisant 2 choses:
1) Renommer un fichier de html en xhtml
2) Changez le script en
la source
Basé sur la réponse de @ chris-dolphin mais en utilisant la fonction d'assistance:
la source
$svg.append($s('<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>'));
Si la chaîne que vous devez ajouter est SVG et que vous ajoutez l'espace de noms approprié, vous pouvez analyser la chaîne en XML et l'ajouter au parent.
la source
La réponse acceptée par Bobince est une solution courte et portable. Si vous devez non seulement ajouter SVG mais aussi le manipuler, vous pouvez essayer la bibliothèque JavaScript "Pablo" (je l'ai écrite). Cela semblera familier aux utilisateurs de jQuery.
Votre exemple de code ressemblerait alors à:
Vous pouvez également créer des éléments SVG à la volée, sans spécifier de balisage:
la source
Je dirais qu'il serait préférable d'utiliser ajax et de charger l'élément svg à partir d'une autre page.
Où href est l'emplacement de la page avec le svg. De cette façon, vous pouvez éviter tout effet nerveux qui pourrait se produire en remplaçant le contenu html. N'oubliez pas non plus de déballer le svg après son chargement:
la source
Cela fonctionne pour moi aujourd'hui avec FF 57:
Fait du:
la source
$(this).clone()
clone un élément SVG (et ce sont des enfants s'il en avait). Regardez au-delà de l'utilisation detext()
. Je prends une seule cuillère à café qui contenait "Votre nouveau" et je me retrouve avec deux cuillères à café, une avec "Votre" dedans (noir) et une avec "Nouveau dedans" (bleu avec ligne). Jeez, en baisse de 0 voix à -1 :-(la source
Une manière beaucoup plus simple consiste à simplement générer votre SVG dans une chaîne, à créer un élément HTML wrapper et à insérer la chaîne svg dans l'élément HTML à l'aide de
$("#wrapperElement").html(svgString)
. Cela fonctionne très bien dans Chrome et Firefox.la source