Osadzić SVG w SVG?

100

Mam dokument SVG i chciałbym dołączyć do niego zewnętrzny obraz svg, czyli coś takiego:

<object data="logo.svgz" width="100" height="100" x="200" y="400"/>

(„obiekt” to tylko przykład - zewnętrzny dokument będzie SVG zamiast xhtml).

Jakieś pomysły? Czy to w ogóle możliwe? A może najlepiej byłoby po prostu włożyć plik xml logo.svg do mojego zewnętrznego dokumentu SVG?

Marcin
źródło

Odpowiedzi:

137

Użyj imageelementu i odnieś się do pliku SVG. Dla zabawy zapisz jako recursion.svg:

<svg width="100%" height="100%" viewBox="-100 -100 200 200" version="1.1"
     xmlns="http://www.w3.org/2000/svg">
  <circle cx="-50" cy="-50" r="30" style="fill:red" />
  <image x="10" y="20" width="80" height="80" href="recursion.svg" />
</svg>
Phrogz
źródło
3
Dzięki, z jakiegoś powodu moje wyszukiwanie w Google po prostu nie działało, dopóki nie opublikowałem tego pytania. Zauważam, że szerokość i wysokość muszą być obecne, aby obraz był renderowany.
Marcin
20
Jedna interesująca obserwacja: najnowsze wersje przeglądarek Firefox, Chrome i Safari pokazują tylko jeden poziom rekurencji (dwie kropki) przy użyciu powyższego. Jeśli jednak zapiszesz powyższe jako „a.svg” i zmienisz obraz na „b.svg”, a następnie zapiszesz go również jako „b.svg” z obrazem odwołującym się do „a.svg”, Firefox pokaże dodatkowe poziomy rekurencji za każdym razem, gdy przeładowujesz naprzemienne pliki . Wydaje się, że buforuje wynik za każdym razem, gdy ładujesz plik, przechodząc o jeden poziom głębiej.
Phrogz,
6
@IanStormTaylor Element SVG sam w sobie nie ma właściwości stylu; raczej elementy wewnątrz elementu SVG mają styl. Jednak podczas korzystania <image>z SVG (lub <img>czy <embed>w HTML), aby odwoływać się do pliku SVG nie mają dostęp do podstawowej DOM. W związku z tym nie, nie można stylizować elementów wewnątrz elementu SVG, do którego odwołuje się plik <image>.
Phrogz
2
@proteneer <image xlink:href="data:image/svg+xml;utf8,&lt;svg …&gt;… &lt;/svg&gt;" />. (Jeśli używasz JavaScript do ustawiania hrefatrybutu, nie musisz <
zmieniać znaczenia
1
xlink:hrefjest przestarzały , teraz powinieneś po prostu użyć href. Czy możesz zaktualizować swoją odpowiedź, aby to uwzględnić?
Kaczor Donald
93

Lub możesz faktycznie osadzić dziecko svg w nadrzędnym pliku svg w ten sposób:

<svg>
    <g>
        <svg>
            ...
        </svg>
    </g>
</svg>

demo:
http://hitokun-s.github.io/old/demo/path-between-two-svg.html

toshi
źródło
@toshi czy masz inny przykład swojej odpowiedzi? próbuję, ale nie potrafię wdrożyć twojej rady. mój „zewnętrzny” SVG ustawia okrąg i gradienty. mój wewnętrzny SVG jest obiektem. samodzielny, wewnętrzny SVG działa zgodnie z oczekiwaniami. ale wewnętrzny SVG nie wyświetla się w mojej implementacji twojej rady. stąd moja prośba o inny przykład.
Jay Grey
+1 za wzmiankę o samodzielnej alternatywie. Jak działa pozycjonowanie / zmiana rozmiaru takiego osadzonego pliku SVG?
bluenote10
41

Warto wspomnieć, że kiedy osadzasz pliki SVG w innym SVG z:

<image x="10" y="20" width="80" height="80" xlink:href="image.svg" />

następnie osadzony SVG przyjmuje prostokąt kształt o określonych wymiarach.

Oznacza to, że jeśli osadzony plik SVG jest okręgiem lub jakimś innym kształtem niż kwadrat, staje się kwadratem z przezroczystością. Dlatego zdarzenia myszy zostają uwięzione w tym osadzonym kwadracie i nie docierają do nadrzędnego pliku SVG. Uważaj na to.

Lepszym podejściem jest użycie wzorca. Aby wypełnić kształt, albo okrąg, kwadrat, albo nawet ścieżka.

<defs>
 <pattern id="pat" x="0" y="0" width="500" height="500" patternUnits="userSpaceOnUse">
   <image x="0" y="0" width="500" height="500" xlink:href="images/mysvg.svg"></image>
 </pattern>
</defs>

Następnie użyj wzoru w ten sposób:

<circle cx="0" cy="0" r="250" fill="url(#pat)"></circle>

Teraz zdarzenia myszy nie utkną w przezroczystych kwadratach obrazu!

oabarca
źródło
Ten wzór wypełnienia jest doskonały, dziękuję. W przypadku mniejszych wstawek lub mniejszych okienek podglądu programiści mogą chcieć zmniejszyć całą szerokość i wysokość w równym stopniu.
Steve Taylor
7

Zauważyłem, że użycie <image>tagu dało niskiej jakości renderowanie osadzonego pliku. Jednak następująca technika zadziałała (aby osadzić plik SVG w pliku SVG - niekoniecznie do renderowania na stronie HTML):

  • Edytuj plik SVG w edytorze tekstu.

  • Znajdź koniec metadanych:

    </metadata>
      <g
       id="layer1"
       inkscape:groupmode="layer"
       inkscape:label="Layer 1">
    
  • Wstaw ten wiersz po tym tagu grupy:

    <use xlink:href="OTHERFILE.svg#layer1" y="0" x="0" />
    
  • W tym przypadku dołączamy INNY PLIK.svg do pliku i całą warstwę 1 (pierwsza i domyślna warstwa).

  • Zapisz to, a następnie otwórz plik w Inkscape.

Ta technika jest przydatna w przypadku standardowego tła lub logo na każdej stronie. Umieszczając go jako pierwszy w pliku, zostanie on wyrenderowany jako pierwszy (a więc na dole). Możesz go również zablokować, dodając ten atrybut:

sodipodi:insensitive="true" 

Innymi słowy:

<use xlink:href="OTHERFILE.svg#layer1" sodipodi:insensitive="true" y="0" x="0" />
Nick Gammon
źródło
@WilliamEntriken Co rozumiesz przez „pliki zewnętrzne”? Metoda, którą opisałem, wykorzystuje zewnętrzny plik, a mianowicie plik z pozostałymi elementami.
Nick Gammon
6

Notatka xlink:hrefzostała wycofana , po prostu użyj hrefzamiast niej, np

<svg viewBox="0 0 512 512">
  <image width="512" height="512" href="external.svg"/>
</svg>

viewBox, widtha heightwartości (w tej odpowiedzi) służą jedynie celom ilustracyjnym, odpowiednio dostosuj układ ( czytaj więcej ).

Od <image> akcji podobnej specyfikacji , co <img>, co oznacza, że nie obsługuje SVG stylizacji, jak wspomniano w odpowiedzi Christiaan użytkownika . Na przykład, jeśli mam następującą linię css, która ustawia kolor kształtu svg na taki sam jak kolor czcionki,

svg {
  fill: currentColor;
}

Powyższy styl nie miałby zastosowania, gdyby <image>został użyty. W tym celu musisz użyć <use>, jak pokazano w odpowiedzi Nicka .

Uwaga id="layer1"i href="OTHERFILE.svg#layer1"wartości w jego odpowiedzi są obowiązkowe .

Oznacza to, że musisz dodać idatrybut do zewnętrznego pliku svg, więc musisz hostować (zmodyfikowany) zewnętrzny plik svg samodzielnie (twoja strona internetowa) lub gdzie indziej. Wynikowy zewnętrzny plik SVG wygląda następująco (zwróć uwagę, gdzie umieściłem id):

<svg id="logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  <path d="..."/>
</svg>

Wartość id może być dowolna, w tym przykładzie używam „logo”.

Aby osadzić ten plik svg,

<svg viewBox="0 0 512 512">
  <use href="edited-external.svg#logo"/>
</svg>

Jeśli używasz powyższego svg jako wbudowanego w swoim html, nie potrzebujesz atrybutu xmlns (przynajmniej tego, co wiem z svgo ).

Saftever
źródło
1
viewBox nie jest obowiązkowy, jeśli go pominiesz, otrzymasz inny układ, w niektórych przypadkach może to być to, czego chcesz. Safari dopiero co zaczęło obsługiwać href.
Robert Longson
4

Musiałem osadzić SVG w moim SVG, ale także zmienić jego kolor i zastosować transformacje.

Tylko Firefox obsługuje atrybut „transform” w zagnieżdżonych elementach svg. Zmiana koloru <image> również nie jest możliwa. Potrzebna była więc kombinacja obu.

Skończyło się na tym, że zrobiłem następujące

<svg>
  <image x="0" y="0" xlink:href="data:image/svg+xml;base64,[base64 of nested svg]"></image>
</svg>

Działa to przynajmniej na przeglądarkach Firefox, Chrome i Inkscape.

Zachowuje się tak samo, jak podrzędny plik SVG w odpowiedzi nadrzędnego pliku SVG, z wyjątkiem tego, że można teraz zastosować do niego transformacje.

Christiaan
źródło