adobe-webplatform / Snap.svg

The JavaScript library for modern SVG graphics.
http://snapsvg.io
Apache License 2.0
13.95k stars 1.15k forks source link

Embed an SVG in another #613

Open Sashkan opened 5 years ago

Sashkan commented 5 years ago

Is it possible to add a Fragment inside of another one ?

Let's say I've got two SVGs, one of a landscape, the other one is a tree. I'd like to put my tree inside of my landscape, at a specific place, defined by a rect.

I tried several solutions, none of them seem to work. I tried turning my tree SVG into a pattern, then using it to fill my rect, but it seems like I cannot turn a Fragment into a pattern.


    Snap.load(landscapeUrl, function (landscape) {
      if (element) {
        element.add(landscape);
        Snap.load(treeUrl, function (tree) {
          if (element) {
            const rect = landscape.select('rect').getBBox();
            var s = Snap(0, 0)
            let image = tree.select('image')
            var image = s.paper.image(design, 0, 0, rect.width, rect.height);
            image = image.pattern(0, 0, rect.width, rect.height);
            landscape.select('rect').attr({fill: image})
          }
        })
      }
    })

Is there a way to achieve this ?

ibrierley commented 5 years ago

Should be possible without a pattern, as long as element is a container object, like group,svg etc. Maybe if you put up links to the images or whatever it may help.

Sashkan commented 5 years ago

@ibrierley I edited the snippet with the URLs. When you say "element is a container object", I assume you're talking about the rect in which I'd like to display the 2nd SVG ?

ibrierley commented 5 years ago

Hi, yes, I guess you are trying to use a pattern because a rect can't have a child element, which is one approach, but not sure why you need a pattern...why not just place the image on top of the other image ?

Sashkan commented 5 years ago

My first SVG includes several layers, some of which are supposed to go over the second one.

I managed to accomplish what I wanted, although I stumbled upon some weird things.

First, the difference between a Fragment and an Element is quite blurry.

Second, I had to use a weird workaround to access my SVG. If I load an SVG, I cannot access it directly.

loadedFragment.select('svg') // returns null
loadedFragment.select([any first-depth element in my SVG]).parent() // returns my SVG

in the end, this was what I had to use in order to get a proper display, scale after my rect


                const rect = baseProduct.select('rect').getBBox();
                var s = Snap(0, 0)
                let test = Snap(rect.width, rect.height);
                let svg = baseProduct.select('rect').parent()
                baseProduct.select('rect').attr({fill: 'transparent'})

                var spot = Snap.parse("<g id='designGroup'></g>");
                svg.add(spot, rect.x, rect.y, rect.width, rect.height)
                design.select('g').parent().attr({
                  y: rect.y,
                  x: rect.x,
                  height: rect.height,
                  width: rect.width,
                })
                baseProduct.select('#designGroup').add(design)
                element.add(baseProduct);