Как правильно ссылаться на внешний файл SVG в SVG? - PullRequest
20 голосов
/ 27 августа 2011

Здравствуйте, я работаю над картой svg / js, которая состоит из множества маленьких графиков svg (Городские районы). Я помещаю каждую графику в отдельный файл, чтобы мой основной файл SVG по-прежнему можно было поддерживать и не раздутым.

Как правильно сослаться на внешний файл SVG от другого SVG?

Ожидаемый результат: Откройте 1.svg в браузере и увидите синий прямоугольник. Как это должно работать: w3c: использовать элемент

Так вот что я попробовал: 1.svg:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet href="style.css" type="text/css"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-       20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"    width="1000" height="1000">
<use xlink:href="another.svg#rectangle"/>
</svg>

another.svg:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-       20010904/DTD/svg10.dtd">
<svg id="rectangle" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"    width="1000" height="1000">
<rect class="blue" x="558.5" y="570" width="5" height="5" />
</svg>

style.css

.blue { fill: blue; }

Результат:

  • Firefox: синий прямоугольник (именно то, что я хотел)
  • Хром: Ничего
  • Опера: Черный прямоугольник

Примечание: я пробовал это с элементом изображения, но он не работал с таблицами стилей, т.е. я получил черный прямоугольник, а не синий.

Важно: Если вы хотите сослаться на другой SVG , а хотите, чтобы ссылочный SVG был частью формальной структуры документа, вы можете использовать AJAX сделать это.

https://bugs.webkit.org/show_bug.cgi?id=12499

Ответы [ 4 ]

9 голосов
/ 29 августа 2011

Из определения в спецификации SVG, что вы связаны с :

Селекторы CSS2 не могут быть применены к (концептуально) клонированному дереву DOM, поскольку его содержимое не является частьюформальная структура документа.

Это означает, что ваш селектор в 1.svg не применяется к клонированному дереву DOM.

Так почему бы просто не ссылаться на таблицу стилей из another.svgвместо?Это должно работать во всех браузерах, а также с <use> и <image>.

Другой вариант - стилизовать элемент <use> в основном документе svg (1.svg), так как стиль каскадируетсяоттуда тоже клонированное дерево.

8 голосов
/ 03 мая 2018

Это отвечает на исходный вопрос, но пытается ответить на вопрос ссылки на внешние SVG-файлы в SVG также в более широком смысле.

Отсутствие поддержки SVG

Шесть лет спустя Chrome и Safari по-прежнему не допускают ссылки / загрузки внешних файлов SVG .

Именно поэтому <use xlink:href="another.svg#rectangle" class="blue"/> работает в Firefox, но не в браузерах WebKit.

Все в одном файле

Если проект может себе это позволить, просто поместите все файлы SVG в один родительский файл HTML или SVG. Таким образом, он будет работать во всех трех браузерах:

Но тогда, это не действительно внешнее, само собой разумеется!

Чтобы извлечь выгоду из кэширования и избежать повторения, мы хотели бы сохранить воспроизводимый SVG-контент во внешнем файле.

Обход: вставьте внешний файл SVG с помощью JavaScript

Храните стили и определения в одном файле SVG, сохраняйте геометрию SVG в каком-то другом файле и просто загружайте первое из второго с помощью JavaScript.

В чистом SVG и чистом JavaScript

Определите, что мы хотели бы использовать. styles-and-defs.svg

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <style type="text/css" >
    <![CDATA[

    .blue { fill: blue; }

    ]]>
    </style>

    <defs>
        <rect id="rectangle" class="blue" width="50" height="50" />
    </defs>
</svg>

Используйте геометрию, созданную выше, и загрузите ее определение. parent.svg

<svg version="1.1"
    baseProfile="full"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    width="420" height="120">

    <use xlink:href="#rectangle" x="10" y="10" />

    <script><![CDATA[

        /** When the document is ready, this self-executing function will be run. **/
        (function() {

            var ajax = new XMLHttpRequest();
            ajax.open("GET", "styles-and-defs.svg", true);
            ajax.send();

            /**
             * Append the external SVG to this very SVG.
             *
             * Notice the use of an SVG selector on the document derived from the AJAX result.
             *  This is because the full document cannot be included directly into the SVG.
             *  Trying to include to do so would result in:
             *      `HierarchyRequestError: Node cannot be inserted at the specified point in the hierarchy` in Firefox;
             *      `Nodes of type '#document' may not be inserted inside nodes of type 'svg'.` in Chrome.
             */
            ajax.onload = function(e) {
                var parser = new DOMParser();
                var ajaxdoc = parser.parseFromString( ajax.responseText, "image/svg+xml" );
                document.getElementsByTagName('svg')[0].appendChild( ajaxdoc.getElementsByTagName('svg')[0] );
            }

        })();   /* END (anonymous function) */

    ]]></script>
</svg>

Это отвечает ОП.

В HTML

Тот же базовый подход, что и в чистом SVG:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
        Load external SVG (HTML)
    </title>
    <meta name="author" content="Fabien Snauwaert">
</head>

<body>

    <svg version="1.1"
    baseProfile="full"
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    width="420" height="120">
        <use xlink:href="#rectangle" x="10" y="10"  />
    </svg>

<script>

    /** When the document is ready, this self-executing function will be run. **/
    (function() {

        var ajax = new XMLHttpRequest();
        ajax.open("GET", "styles-and-defs.svg", true);
        ajax.send();

        /**
         * Append the external SVG to this very SVG.
         *
         * Notice the use of an SVG selector on the document derived from the AJAX result.
         *  This is because the full cannot be included directly into the SVG.
         *  Trying to include to do so would result in:
         *      `HierarchyRequestError: Node cannot be inserted at the specified point in the hierarchy` in Firefox;
         *      `Nodes of type '#document' may not be inserted inside nodes of type 'svg'.` in Chrome.
         */
        ajax.onload = function(e) {
            var parser = new DOMParser();
            var ajaxdoc = parser.parseFromString( ajax.responseText, "image/svg+xml" );
            document.getElementsByTagName('body')[0].appendChild( ajaxdoc.getElementsByTagName('svg')[0] );
        }

    })();   /* END (anonymous function) */

</script>

</body>
</html>

Конечно, вы можете использовать jQuery (или почему бы не отличный D3.js ) для загрузки файла.

Примечания

  • Не забывайте использовать <defs>. Я считаю, что это хорошо, когда у вас есть внешний SVG, вы можете держать все аккуратно и организованно. (А без этого мы бы отображали контент дважды.)
  • Я избавился от style.css и просто поместил CSS внутри файла styles-and-defs.
  • Если в версии HTML вы наблюдаете разрыв между родительским SVG и границами окна, то это потому, что «невидимый» SVG (со стилями и определением), как и любой другой SVG, является элементом inline , Чтобы избавиться от этого пробела, просто установите style="display: block;" на этом SVG.
  • Скачать все примеры можно здесь .

SVG великолепен, но может показаться слишком мало поддерживаемым, хотя и допускает некоторые замечательные вещи. Я надеюсь, что это поможет некоторым людям там.

Проверено нормально на OS X 10.12.6 в:

  • Firefox 59.0.2
  • Chrome 66.0.3359.139
  • Safari 11.0.1
3 голосов
/ 29 августа 2011

Попробуйте сделать так:

Площадь:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"    width="1000" height="1000">
    <rect x="558.5" y="570" width="5" height="5" id="rectangle" />
</svg>

Используйте это:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet href="style.css" type="text/css"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"    width="1000" height="1000">
    <use xlink:href="another.svg#rectangle" class="blue"/>
</svg>
0 голосов
/ 28 августа 2011
Элемент

<svg> не имеет атрибута xlink:href, если необходимо добавить внешнее изображение, используйте элемент <image>.

...