2010-07-27 9 views
10

El estándar SVG permite utilizar y referir archivos SVG externos.Acceder a un objeto DOM definido en un archivo SVG externo

Tengo un archivo circle.svg que define un objeto circular con id "the_circle". Desde el archivo SVG principal, puedo incluir este círculo y animarlo, usando SVG linking.

También me gustaría acceder al mismo objeto circular a través de javascript, ¿cómo puedo hacer esto? ¿Cuál es el equivalente en Javascript de xlink:href="url(#the_image)#the_circle"?

Usando document.getElementById('the_image') Solo puedo acceder a SVGImageElement pero no a los objetos definidos dentro del SVG incluido.

<?xml version="1.0" standalone="no"?> 
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 
<svg width="100%" height="100%" version="1.1" 
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" > 

    <image 
    id="the_image" 
    x="0" y="0" width="100%" height="100%" 
    xlink:href="circle.svg" /> 

    <animateTransform  
    xlink:href="url(#the_image)#the_circle" 

    attributeName="transform" attributeType="XML" 
    type="translate" 
    from="0" to="25" 
    dur="1s" repeatCount="indefinite" 
    additive="replace" fill="freeze" /> 
</svg> 
+0

publicado la misma cuestión en SVG-desarrolladores http://tech.groups.yahoo.com/group/svg-developers/message/63940 – rodrigob

Respuesta

13

Parece que la forma "correcta" de hacer esto sería usar un elemento "uso" de SVG, en lugar de una imagen. La razón de esto es que la interfaz DOM del elemento de uso de SVG especifica una propiedad "InstanceRoot", lo que le permite obtener la raíz de la "instancia de árbol" correspondiente a ese elemento de uso: http://www.w3.org/TR/SVG/struct.html#InterfaceSVGUseElement

Así, acabaría a una solución que se ve algo como lo siguiente: circle.svg:

<?xml version="1.0" standalone="no"?> 
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 
<svg width="4in" height="4in" id="the_svg" 
    viewBox="0 0 4 4" version="1.1" 
    xmlns="http://www.w3.org/2000/svg"> 
    <circle r="1" fill="blue" stroke="none" id="the_circle"/> 
</svg> 

documento que utiliza el nodo raíz de SVG circle.svg:

<?xml version="1.0" standalone="no"?> 
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 
<svg width="100%" height="100%" id="foo" 
    version="1.1" 
    xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"> 

    <use xlink:href="circle.svg#the_svg"/> 
</svg> 

Lamentablemente, sin embargo, mientras que Firefox es compatible con u del elemento de uso con documentos externos, actualmente hay un error en Webkit que no permite esto: https://bugs.webkit.org/show_bug.cgi?id=12499

Además, Firefox no parece implementar la propiedad instanciaRojo para elementos de uso.

Por lo tanto, parece que tendrá que evitar las limitaciones de las implementaciones actuales de SVG. La forma en que recomendaría hacer esto es usar XMLHttpRequest para descargar el documento al que desea vincular e importar el DOM del documento descargado en el DOM de su documento de host. El siguiente código implementa esto, y funciona en Firefox, Opera y Cromo:

<?xml version="1.0" standalone="no"?> 
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 
<svg width="100%" height="100%" id="foo" 
    version="1.1" 
    xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"> 

    <script> 
    function fetchXML (url, callback) { 
     var xhr = new XMLHttpRequest(); 
     xhr.open('GET', url, true); 
     xhr.onreadystatechange = function (evt) { 
     //Do not explicitly handle errors, those should be 
     //visible via console output in the browser. 
     if (xhr.readyState === 4) { 
      callback(xhr.responseXML); 
     } 
     }; 
     xhr.send(null); 
    }; 

    //fetch the document 
    fetchXML("http://localhost:8082/tmp/circle.svg",function(newSVGDoc){ 
     //import it into the current DOM 
     var n = document.importNode(newSVGDoc.documentElement,true); 
     document.documentElement.appendChild(n); 

     var circle = document.getElementById("the_circle"); //now you have the circle 
    }) 
    </script> 
</svg> 
+0

gracias por la respuesta! – rodrigob

+0

XHR ... brillante. – Duke

+0

¡Esto es exactamente lo que estaba buscando!Otros intentos de recuperar el SVG a través de XHR y anexarlo al DOM no tuvieron éxito. ¡Gracias! –

1

Para complementar @ excelente solución de eco-flujo con el código de jQuery/CoffeeScript:

$.get '/assets/hexagon.svg', (svgFileData)-> 
    svgTag = svgFileData.documentElement 
    $('body').append(svgTag) 
    circle = $('#the_circle') 
+0

No olvide importar el nodo utilizando document.importNode. Puede quejarse si no lo haces. – jbeard4

11

Puede acceder a la necesaria elemento un poco más fácil:

document.getElementById('the_image').contentDocument.getElementById('the_circle') 

Ver this image de referencia (tomada en dev.opera.com) enter image description here

+0

Bien, pero ¿cuál es el truco? ¿Supongo que esto solo funciona en SVG incluidos desde el mismo dominio? – joeytwiddle

+0

¿y qué? En general, desea manipular su archivo, no uno de otro sitio. –

+0

Lo tomaré como un sí; Solo es bueno ser claro. Estoy de acuerdo en que el mismo dominio es a menudo el caso, haciendo que las otras respuestas sean excesivas a menos que realmente se necesite una solución general. – joeytwiddle

Cuestiones relacionadas