¿Incrustar SVG en SVG?

98

Tengo un documento SVG y me gustaría incluir una imagen svg externa dentro de él, es decir, algo como:

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

("objeto" es solo un ejemplo; el documento externo será SVG en lugar de xhtml).

¿Algunas ideas? ¿Es esto siquiera posible? ¿O es lo mejor para mí simplemente colocar el logo.svg xml en mi documento SVG externo?

Marcin
fuente

Respuestas:

136

Utilice el imageelemento y haga referencia a su archivo SVG. Para divertirse, guarde lo siguiente como 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
fuente
3
Gracias, por alguna razón, mi búsqueda en Google no funcionó hasta que publiqué esta pregunta. Observo que el ancho y el alto deben estar presentes para que la imagen se renderice.
Marcin
19
Una observación interesante: las últimas versiones de Firefox, Chrome y Safari muestran solo un nivel de recursividad (dos puntos) usando lo anterior. Sin embargo, si guarda lo anterior como "a.svg" y cambia la imagen a "b.svg", y luego también la guarda como "b.svg" con la imagen que hace referencia a "a.svg", Firefox mostrará más niveles de recursividad para cada vez que recarga los archivos alternos . Parece almacenar en caché el resultado cada vez que carga el archivo, yendo un nivel más profundo.
Phrogz
6
@IanStormTaylor Un elemento SVG no tiene propiedades de estilo en sí mismo; más bien, los elementos dentro del elemento SVG tienen estilo. Sin embargo, cuando se utiliza <image>en SVG (o <img>, o <embed>en HTML) para hacer referencia a un archivo SVG no se les da acceso a la DOM subyacente. Como tal, no, no puede aplicar estilo a elementos dentro de un elemento SVG al que se ha hecho referencia con un <image>.
Phrogz
2
@proteneer <image xlink:href="data:image/svg+xml;utf8,&lt;svg …&gt;… &lt;/svg&gt;" />. (Si está utilizando JavaScript para establecer el hrefatributo, no necesita escapar de los <caracteres, etc.)
Phrogz
1
xlink:hrefestá en desuso , ahora solo debería usar href. ¿Podrías actualizar tu respuesta para incluir eso?
Donald Duck
91

O puede incrustar el svg secundario en el svg principal de esta manera:

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

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

toshi
fuente
@toshi, ¿tienes otro ejemplo de tu respuesta? Estoy intentando, pero no puedo implementar su consejo. mi SVG 'externo' establece un círculo y degradados. mi SVG interno es un objeto. independiente, el SVG interno funciona como se esperaba. pero el SVG interno no se muestra en mi implementación de su consejo. de ahí mi solicitud para ver otro ejemplo.
Jay Gray
+1 por mencionar una alternativa independiente. ¿Cómo funciona el posicionamiento / tamaño de un svg incrustado?
bluenote10
40

Vale la pena mencionar que cuando incrusta SVG en otro SVG con:

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

luego, el SVG incrustado toma una forma rectangular con dimensiones determinadas.

Es decir, si su SVG incrustado es un círculo o alguna forma que no sea un cuadrado, entonces se convierte en un cuadrado con transparencia. Por lo tanto, los eventos del mouse quedan atrapados en ese cuadrado incrustado y no llegan al SVG principal. Cuidado con eso.

Un mejor enfoque es usar un patrón. Para rellenar una forma, ya sea un círculo, un cuadrado o incluso un camino.

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

Luego usa el patrón como este:

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

¡Ahora los eventos de su mouse no se atascan en cuadrados de imagen transparentes!

oabarca
fuente
Ese patrón de relleno es perfecto, gracias. Para inserciones más pequeñas o cajas de visualización más pequeñas, los codificadores pueden querer reducir todo el ancho y la altura en la misma medida.
Steve Taylor
7

Descubrí que el uso de la <image>etiqueta daba un renderizado de baja calidad del archivo incrustado. Sin embargo, la siguiente técnica funcionó (para incrustar un archivo SVG dentro de un archivo SVG, no necesariamente para renderizar en una página HTML):

  • Edite el archivo SVG en un editor de texto.

  • Encuentra el final de los metadatos:

    </metadata>
      <g
       id="layer1"
       inkscape:groupmode="layer"
       inkscape:label="Layer 1">
  • Inserte esta línea después de esa etiqueta de grupo:

    <use xlink:href="OTHERFILE.svg#layer1" y="0" x="0" />
  • En este caso, estamos incluyendo OTHERFILE.svg en el archivo y todo layer1 (la primera capa predeterminada).

  • Guarde esto y luego abra el archivo en Inkscape.

Esta técnica es útil para tener un fondo o logotipo estándar en cada página. Al colocarlo primero en el archivo, se procesará primero (y por lo tanto en la parte inferior). También puede bloquearlo agregando este atributo:

sodipodi:insensitive="true" 

En otras palabras:

<use xlink:href="OTHERFILE.svg#layer1" sodipodi:insensitive="true" y="0" x="0" />
Nick Gammon
fuente
@WilliamEntriken ¿A qué te refieres con "archivos externos"? El método que describí usa un archivo externo, es decir, el archivo con las otras cosas en él.
Nick Gammon
5

La nota xlink:hrefha quedado obsoleta , solo utilícela hrefen su lugar, por ejemplo

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

viewBox, widthy los heightvalores (en esta respuesta) son simplemente para fines ilustrativos, ajuste el diseño en consecuencia ( lea más ).

Dado que <image> las acciones de especificaciones similares como <img>, lo que significa que no soporta SVG estilo, como se menciona en la respuesta de Christiaan . Por ejemplo, si tengo la siguiente línea css que establece que el color de la forma svg sea el mismo que el color de la fuente,

svg {
  fill: currentColor;
}

El estilo anterior no se aplicaría si <image>se usa. Para eso, debe usar <use>, como se muestra en la respuesta de Nick .

La nota id="layer1"y los href="OTHERFILE.svg#layer1"valores en su respuesta son obligatorios .

Lo que significa que debe agregar el idatributo al archivo svg externo, por lo que debe alojar el archivo svg externo (modificado) usted mismo (su sitio web) o en otro lugar. El archivo svg externo resultante se ve así (observe dónde coloco el id):

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

El valor de id puede ser cualquier cosa, utilizo "logo" en este ejemplo.

Para incrustar ese svg,

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

Si usa el svg anterior como en línea en su html, no necesita el atributo xmlns (al menos lo que sé de svgo ).

Seguro
fuente
1
viewBox no es obligatorio, si lo omite obtendrá un diseño diferente, aunque en algunos casos puede ser lo que desee. Safari acaba de comenzar a admitir href.
Robert Longson
4

Necesitaba incrustar un SVG en mi SVG pero también cambiar su color y aplicar transformaciones.

Solo Firefox admite el atributo "transform" en los elementos svg anidados. Tampoco es posible cambiar el color de <imagen>. Entonces se necesitaba una combinación de ambos.

Lo que terminé haciendo fue lo siguiente

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

Esto funciona al menos en Firefox, Chrome e Inkscape.

Esto se comporta de la misma manera que el svg secundario en la respuesta del svg principal, con la excepción de que ahora puede aplicar transformaciones en él.

Christiaan
fuente