Incorporer SVG dans SVG?

98

J'ai un document SVG et j'aimerais y inclure une image svg externe, c'est-à-dire quelque chose comme:

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

("objet" est juste un exemple - le document externe sera SVG plutôt que xhtml).

Des idées? Est-ce seulement possible? Ou est-ce que la meilleure chose pour moi est de simplement gifler le xml logo.svg dans mon document SVG externe?

Marcin
la source

Réponses:

135

Utilisez l' imageélément et référencez votre fichier SVG. Pour le plaisir, enregistrez les éléments suivants sous 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
la source
3
Merci, pour une raison quelconque, ma recherche sur Google pour cela n'a tout simplement pas fonctionné avant d'avoir posté cette question. Je note que la largeur et la hauteur doivent être présentes pour que l'image soit rendue.
Marcin
19
Une observation intéressante: les dernières versions de Firefox, Chrome et Safari affichent toutes un seul niveau de récursivité (deux points) en utilisant ce qui précède. Cependant, si vous enregistrez ce qui précède en tant que "a.svg" et changez l'image en "b.svg", puis enregistrez-le également sous "b.svg" avec l'image faisant référence à "a.svg", Firefox affichera alors des niveaux de récursivité à chaque fois que vous rechargez les fichiers alternés . Il semble mettre en cache le résultat à chaque fois que vous chargez le fichier, allant d'un niveau plus profond.
Phrogz
6
@IanStormTaylor Un élément SVG n'a pas de propriétés de style lui-même; les éléments à l'intérieur de l'élément SVG ont plutôt du style. Cependant, lorsque vous utilisez <image>en SVG (ou <img>ou <embed>en HTML) pour référencer un fichier SVG, vous n'avez pas accès au DOM sous-jacent. En tant que tel, non, vous ne pouvez pas styliser des éléments à l'intérieur d'un élément SVG qui a été référencé par un <image>.
Phrogz
2
@proteneer <image xlink:href="data:image/svg+xml;utf8,&lt;svg …&gt;… &lt;/svg&gt;" />. (Si vous utilisez JavaScript pour définir l' hrefattribut, vous n'avez pas besoin d'échapper aux <caractères, etc.)
Phrogz
1
xlink:hrefest obsolète , vous devez maintenant simplement utiliser href. Pourriez-vous mettre à jour votre réponse pour inclure cela?
Donald Duck
91

Ou vous pouvez en fait incorporer un svg enfant dans un svg parent comme ceci:

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

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

toshi
la source
@toshi avez-vous un autre exemple de votre réponse? J'essaye mais échoue à mettre en application vos conseils. mon SVG «extérieur» définit un cercle et des dégradés. mon SVG intérieur est un objet. autonome, le SVG interne fonctionne comme prévu. mais le SVG interne ne s'affiche pas dans ma mise en œuvre de vos conseils. d'où ma demande de voir un autre exemple.
Jay Gray
+1 pour mentionner une alternative autonome. Comment fonctionne le positionnement / dimensionnement d'un tel svg intégré?
bluenote10
40

Il est à noter que lorsque vous intégrez des SVG dans un autre SVG avec:

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

alors le SVG incorporé prend une forme rectangulaire avec des dimensions données.

Autrement dit, si votre SVG incorporé est un cercle ou une forme autre qu'un carré, il devient alors un carré avec transparence. Par conséquent, les événements de souris sont piégés dans ce carré incorporé et n'atteignent pas le SVG parent. Attention à ça.

Une meilleure approche consiste à utiliser un modèle. Pour remplir une forme, soit un cercle, un carré ou même un tracé.

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

Ensuite, utilisez le modèle comme ceci:

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

Désormais, les événements de votre souris ne restent pas coincés dans des carrés d'image transparents!

oabarca
la source
Ce motif de remplissage est parfait, merci. Pour des insertions plus petites ou des zones de visualisation plus petites, les codeurs peuvent vouloir réduire toutes les largeurs et hauteurs dans une mesure égale.
Steve Taylor
7

J'ai trouvé que l'utilisation de la <image>balise donnait un rendu de mauvaise qualité du fichier intégré. Cependant, la technique suivante a fonctionné (pour incorporer un fichier SVG dans un fichier SVG - pas nécessairement pour le rendu sur une page HTML):

  • Modifiez le fichier SVG dans un éditeur de texte.

  • Trouvez la fin des métadonnées:

    </metadata>
      <g
       id="layer1"
       inkscape:groupmode="layer"
       inkscape:label="Layer 1">
  • Insérez cette ligne après cette balise de groupe:

    <use xlink:href="OTHERFILE.svg#layer1" y="0" x="0" />
  • Dans ce cas, nous incluons OTHERFILE.svg dans le fichier, et tout le layer1 (le premier calque par défaut).

  • Enregistrez-le, puis ouvrez le fichier dans Inkscape.

Cette technique est utile pour avoir un arrière-plan ou un logo standard sur chaque page. En le mettant en premier dans le fichier, il sera rendu en premier (et donc en bas). Vous pouvez également le verrouiller en ajoutant cet attribut:

sodipodi:insensitive="true" 

En d'autres termes:

<use xlink:href="OTHERFILE.svg#layer1" sodipodi:insensitive="true" y="0" x="0" />
Nick Gammon
la source
@WilliamEntriken Qu'entendez-vous par "fichiers externes"? La méthode que j'ai décrite utilise un fichier externe, à savoir le fichier contenant les autres éléments.
Nick Gammon
5

Remarque xlink:hrefest obsolète , utilisez simplement à la hrefplace, par exemple

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

viewBox, widthet les heightvaleurs (dans cette réponse) sont simplement à des fins d'illustration, ajustez la mise en page en conséquence (en savoir plus ).

Depuis <image> partage des spécifications similaires à <img>, ce qui signifie qu'il ne prend pas en charge le style SVG, comme mentionné dans la réponse de Christiaan . Par exemple, si j'ai la ligne css suivante qui définit la couleur de la forme svg pour qu'elle soit la même que la couleur de la police,

svg {
  fill: currentColor;
}

Le style ci-dessus ne s'appliquerait pas s'il <image>est utilisé. Pour cela, vous devez utiliser <use>, comme indiqué dans la réponse de Nick .

La note id="layer1"et les href="OTHERFILE.svg#layer1"valeurs dans sa réponse sont obligatoires .

Cela signifie que vous devez ajouter l' idattribut au fichier svg externe, vous devez donc héberger le fichier svg externe (modifié) par vous-même (votre site Web) ou ailleurs. Le fichier svg externe résultant ressemble à ceci (remarquez où je mets le id):

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

La valeur de id peut être n'importe quoi, j'utilise "logo" dans cet exemple.

Pour intégrer ce svg,

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

Si vous utilisez le svg ci-dessus en ligne dans votre html, vous n'avez pas besoin de l'attribut xmlns (du moins ce que je sais de svgo ).

Saftever
la source
1
viewBox n'est pas obligatoire, si vous l'omettez, vous obtiendrez une mise en page différente, dans certains cas, cela peut être ce que vous voulez. Safari vient tout juste de commencer à prendre en charge href.
Robert Longson
4

J'avais besoin d'intégrer un SVG dans mon SVG mais aussi de changer sa couleur et d'appliquer des transformations.

Seul Firefox prend en charge l'attribut "transform" sur les éléments svg imbriqués. Changer la couleur de <image> n'est pas non plus possible. Une combinaison des deux était donc nécessaire.

Ce que j'ai fini par faire était le suivant

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

Cela fonctionne au moins sur Firefox, Chrome et Inkscape.

Cela se comporte de la même manière que le svg enfant dans la réponse svg parent, à l'exception du fait que vous pouvez maintenant y appliquer des transformations.

Christiaan
la source