Доступ к объекту DOM, определенному во внешнем файле SVG

Стандарт SVG позволяет использовать и передавать внешние SVG файлы.

У меня есть файл circle.svg, который определяет объект окружности с id "the_circle". Из основного файла SVG я могу включить этот круг и оживить его, используя привязку SVG.

Я также хотел бы получить доступ к одному объекту круга через javascript, как я могу это сделать? Что такое javascript-эквивалент xlink:href="url(#the_image)#the_circle"?

Использование document.getElementById('the_image') Я могу получить доступ только к SVGImageElement, но не к объектам, указанным внутри включенного 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%" 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>

Ответ 1

Похоже, что "правильный" способ сделать это будет фактически использовать элемент "Использовать" SVG, а не изображение. Причиной этого является то, что интерфейс DOM элемента использования SVG указывает свойство "instanceRoot", которое позволяет вам получить корень "дерева экземпляров", соответствующего этому используемому элементу: http://www.w3.org/TR/SVG/struct.html#InterfaceSVGUseElement

Итак, вы получите решение, которое выглядит примерно так: 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>

Документ, в котором используется корень svg node для 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>

К сожалению, хотя Firefox поддерживает использование элемента use с внешними документами, в настоящее время в Webkit есть ошибка, которая не позволяет этого: https://bugs.webkit.org/show_bug.cgi?id=12499

Кроме того, Firefox, похоже, не реализует свойство instanceRoot для использования элементов.

Итак, кажется, вам, возможно, придется обойти ограничения существующих реализаций SVG. То, как я рекомендовал бы это сделать, - использовать XMLHttpRequest для загрузки документа, к которому вы хотите связать, и импортировать DOM загруженного документа в документ DOM хоста. Следующий код реализует это и работает в Firefox, Opera и Chromium:

<?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>

Ответ 2

Вы можете легко получить доступ к нужному элементу:

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

Смотрите это изображение для справки (взято dev.opera.com) enter image description here

Ответ 3

В дополнение к отличному решению @echo-flow с кодом в jQuery/Coffeescript:

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