Cuando pasa una cadena de marcado $
, se analiza como HTML utilizando la innerHTML
propiedad del navegador en un <div>
(u otro contenedor adecuado para casos especiales como <tr>
). innerHTML
no puede analizar SVG u otro contenido que no sea HTML, e incluso si pudiera no podría decir que <circle>
se suponía que estaba en el espacio de nombres SVG.
innerHTML
no está disponible en SVGElement: es una propiedad de HTMLElement únicamente. Tampoco hay actualmente uninnerSVG
propiedad u otra forma (*) para analizar el contenido en un elemento SVGE. Por esta razón, debe usar métodos de estilo DOM. jQuery no le brinda fácil acceso a los métodos de espacios de nombres necesarios para crear elementos SVG. Realmente jQuery no está diseñado para usarse con SVG y muchas operaciones pueden fallar.
HTML5 promete permitirte usar <svg>
sin un documento xmlns
HTML ( text/html
) plano en el futuro. Pero esto es solo un truco del analizador sintáctico (**), el contenido SVG seguirá siendo SVGElements en el espacio de nombres SVG y no HTMLElements, por lo que no podrá usarlo innerHTML
aunque parezca parte de un documento HTML.
Sin embargo, para los navegadores de hoy debe usar X HTML (servido correctamente como application/xhtml+xml
; guardar con la extensión de archivo .xhtml para pruebas locales) para que SVG funcione. (De todos modos, tiene sentido; SVG es un estándar basado en XML). Esto significa que tendría que escapar de los <
símbolos dentro de su bloque de script (o encerrarlo en una sección CDATA) e incluir la xmlns
declaración XHTML . ejemplo:
<!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>
*: bueno, hay parseWithContext de DOM Level 3 LS , pero el soporte del navegador es muy pobre. Editar para agregar: sin embargo, aunque no puede inyectar marcado en un elemento SVGE, puede inyectar un nuevo elemento SVGE en un elemento HTMLE usando innerHTML
, luego transferirlo al objetivo deseado. Sin embargo, es probable que sea un poco más lento:
<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>
**: Odio la forma en que los autores de HTML5 parecen tener miedo de XML y están decididos a calzar las características basadas en XML en el desorden que es HTML. XHTML resolvió estos problemas hace años.
RMB
>edit as html
en la etiqueta html y presiono enter, se muestra todo (pero todos los oyentes de eventos desaparecen). Después de leer esta respuesta, cambié mis llamadas createElement a createElementNS y ahora todo funciona.d3.select('body').append('svg').attr('width','100%');
$.parseXML
.La respuesta aceptada muestra una forma demasiado complicada. Como Forresto afirma en su respuesta , " parece agregarlos en el explorador DOM, pero no en la pantalla " y la razón de esto son los diferentes espacios de nombres para html y svg.
La solución más fácil es "actualizar" todo el svg. Después de agregar un círculo (u otros elementos), use esto:
Esto hace el truco. El círculo está en la pantalla.
O si lo desea, use un contenedor div:
Y envuelva su svg dentro del contenedor div:
El ejemplo funcional:
http://jsbin.com/ejifab/1/edit
Las ventajas de esta técnica:
$('svg').prepend('<defs><marker></marker><mask></mask></defs>');
como haces en jQuery.$("#cont").html($("#cont").html());
sus atributos, se pueden editar con jQuery.EDITAR:
La técnica anterior funciona solo con SVG "codificado" o DOM manipulado (= document.createElementNS, etc.). Si se usa Raphael para crear elementos, (de acuerdo con mis pruebas) la conexión entre los objetos Raphael y SVG DOM se rompe si
$("#cont").html($("#cont").html());
se usa. La solución a esto es no usar$("#cont").html($("#cont").html());
en absoluto y en lugar de usar un documento SVG ficticio.Este SVG ficticio es primero una representación textual del documento SVG y contiene solo los elementos necesarios. Si queremos, por ejemplo. para agregar un elemento de filtro al documento de Raphael, el ficticio podría ser algo así
<svg id="dummy" style="display:none"><defs><filter><!-- Filter definitons --></filter></defs></svg>
. La representación textual se convierte primero a DOM utilizando el método $ ("body"). Append () de jQuery. Y cuando el elemento (filtro) está en DOM, puede consultarse utilizando métodos jQuery estándar y adjuntarse al documento SVG principal creado por Raphael.¿Por qué se necesita este muñeco? ¿Por qué no agregar un elemento de filtro estrictamente al documento creado por Raphael? Si lo intentas usando eg.
$("svg").append("<circle ... />")
, se crea como elemento html y no hay nada en la pantalla como se describe en las respuestas. Pero si se agrega todo el documento SVG, entonces el navegador maneja automáticamente la conversión del espacio de nombres de todos los elementos en el documento SVG.Un ejemplo ilustra la técnica:
La demostración de trabajo completa de esta técnica está aquí: http://jsbin.com/ilinan/1/edit .
(Todavía no tengo idea, por qué
$("#cont").html($("#cont").html());
no funciona cuando se usa Raphael. Sería un truco muy corto).fuente
$("#cont").html($("#cont").html());
funcionó muy bien en Chrome, pero no funcionó en IE 11 para mí.La biblioteca D3 cada vez más popular maneja las rarezas de agregar / manipular svg muy bien. Es posible que desee considerar su uso en lugar de los hacks jQuery mencionados aquí.
HTML
Javascript
fuente
JQuery no puede agregar elementos a
<svg>
(parece agregarlos en el explorador DOM, pero no en la pantalla).Una solución alternativa es agregar un archivo
<svg>
con todos los elementos que necesita a la página, y luego modificar los atributos de los elementos usando.attr()
.http://jsfiddle.net/8FBjb/1/
fuente
<circle>
u otros elementos individualmente utilizando métodos DOM complejos y lentos (por ejemplo,createDocumentFragment()
ocreateElementNS()
), agregue todo el documento svg al contenedor. En lugar de $ ('cuerpo') puede ser, por supuesto, también $ ('div'). Y después de eso, el documento svg está en DOM y se puede consultar de manera familiar usando, por ejemplo, $ ('c'). attr ('relleno', 'rojo').No he visto a nadie mencionar este método, pero
document.createElementNS()
es útil en este caso.Puede crear los elementos usando Javascript vainilla como nodos DOM normales con el espacio de nombres correcto y luego jQuery-ify desde allí. Al igual que:
El único inconveniente es que debe crear cada elemento SVG con el espacio de nombres correcto individualmente o no funcionará.
fuente
Encontré una manera fácil que funciona con todos los navegadores que tengo (Chrome 49, Edge 25, Firefox 44, IE11, Safari 5 [Win], Safari 8 (MacOS)):
fuente
Puedo ver el círculo en Firefox, haciendo 2 cosas:
1) Cambiar el nombre del archivo de html a xhtml
2) Cambiar script a
fuente
Basado en la respuesta de @ chris-dolphin pero usando la función de ayuda:
fuente
$svg.append($s('<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>'));
Si la cadena que necesita agregar es SVG y agrega el espacio de nombres adecuado, puede analizar la cadena como XML y agregarla al padre.
fuente
La respuesta aceptada por Bobince es una solución breve y portátil. Si necesita no solo agregar SVG sino también manipularlo, puede probar la biblioteca de JavaScript "Pablo" (lo escribí). Se sentirá familiar para los usuarios de jQuery.
Su código de ejemplo se vería así:
También puede crear elementos SVG sobre la marcha, sin especificar el marcado:
fuente
Sugeriría que podría ser mejor usar ajax y cargar el elemento svg desde otra página.
Donde href es la ubicación de la página con el svg. De esta forma, puede evitar cualquier efecto nervioso que pueda ocurrir al reemplazar el contenido html. Además, no olvides desenvolver el svg después de cargarlo:
fuente
Esto funciona para mí hoy con FF 57:
Hace:
fuente
$(this).clone()
está clonando un elemento SVG (y son hijos si tuviera alguno). Mira más allá del uso detext()
. Estoy tomando una sola tspan que tenía "Your New" en ella, y terminé con dos tspans, una con "Your" en ella (negro) y otra con "New in it" (azul con línea). Dios, de 0 votos a -1 :-(fuente
Una forma mucho más simple es generar su SVG en una cadena, crear un elemento HTML envoltorio e insertar la cadena svg en el elemento HTML usando
$("#wrapperElement").html(svgString)
. Esto funciona bien en Chrome y Firefox.fuente