stefanu
stefanu

Reputation: 357

Inserting SVG elements from another SVG element with plain JS

I am trying to dynamically render the content of a SVG element using svg.js library (https://svgjs.dev). Everything works fine when creating basic elements, like lines, polygons and simple textx and working with their properties.

Now, I would like to extend the drawing with more complex elements using ready-made SVGs (available in a hidden div on the page or by other means), that I need to somehow 'clone' to the main SVG element and also adjust the size and position.

The image below is an example of what I am trying to accomplish : the rectangle is created with svgjs' svg.polygon().plot(... ), and I would like to add the trees.

What would be the simple/proper way to do this ?

Upvotes: 1

Views: 595

Answers (1)

stefanu
stefanu

Reputation: 357

Once again, a good night's sleep provides the right answer, and it's a lot easier than what I expected.

Turns out all is needed is a use, with the svg element id and, optionally, an URL to load the SVG file from, which saves one from embedding the SVG into the page :

// the definition of the object to embed
// holds the item id, and transformation data
var item = ...;
var g = svg
    .group()
    .use(
        item.src, 
        resURL + '/svg/sprites.svg')
    .transform({ 
        translateX : item.x, 
        translateY : item.y });

For SVGs outside your domain, you probably need to load them differently.

As requested, below is a still partial, but more detailed code sample; adding the full code would make the solution hard to follow.

DISCLAIMER : I haven't got to the optimizations / refactoring yet, so yes, there's probably a lot of room to improve on both the data and the code.

The data is a JSON structure like so :

{ 
    "items" : { 
        "item1" : {
            "points" : [[1600,200],[2300,200],[2300,600],[1600,600],[1600,200]],
            "fill"   : "rgba(144, 238, 144, 0.3)",
            "stroke" : "#228B22"
        },
        "item2" : {
            "src":"sprite1"
            "style":{
                "opacity" : 0.3
            },
            "position":{
                "x"     : -360,
                "y"     : 75,
                "scale" : 0.8
            },
        } 
    },
}

The processing goes like this :

var svg = SVG("#drawing-" + floor.key)
Object.keys(floor.items).forEach(function(key,index) {
    var item = floor.items[key];
    if (item.hasOwnProperty('points')) {
        var polygon = svg
            .polygon()
            .stroke({ 
                color: item.stroke })
            .fill(item.fill);
        polygon.plot(item.points);
    }
    else if (item.hasOwnProperty('src')) {
        var g = svg
            .group()
            .use(item.src, resURL + '/svg/plan-sprites.svg')
            .transform({ 
                translateX : item.position.x, 
                translateY : item.position.y, 
                scale      : item.position.scale || 1.})
            .css(item.style || { });
    }
}); 

When done, the page looks like this (simplified) :

<svg id="drawing-curte" class="hwb-drawing"
    <g id="viewport">
        <polygon points="1600,200 2300,200 2300,600 1600,600 1600,200" stroke="#228b22" fill="#90ee90"></polygon>
        <g><use xlink:href="/resources/svg/plan-sprites.svg#sprite1" transform="matrix(1,0,0,1,1550,150)"></use></g>
    </g>
</svg>

Upvotes: 2

Related Questions