martin.p
martin.p

Reputation: 363

Why <rect> element is not rendered after appending to its parent

I'm exploring SVG manipulation with plain JS. Here below the code I created (svg image is just something random for testing purposes):

const svgCode = `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<g id="mainGroup">
<rect x="59.638" y="67.625" width="305.644" height="27.689"
    style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); transform-box: fill-box; transform-origin: 29.4425% 42.3077%;"
    transform="matrix(0.875498, 0.483221, -0.483221, 0.875498, -59.105443, -22.364276)" />
    <rect x="59.638" y="67.625" width="305.644" height="27.689"
    style="fill: rgb(216, 216, 216); stroke: rgb(0, 0, 0); transform-origin: 149.627px 79.34px;"
    transform="matrix(0.793105, -0.609085, 0.609085, 0.793105, -43.863688, 64.15233)" />
    </g>
</svg>`;

let baseViewBox = new DOMRect();
let curViewBox = new DOMRect();

function update() {

    let parser = new DOMParser().parseFromString(svgCode, 'image/svg+xml');

    let svgNode = document.importNode(parser.documentElement, true);

    let svgMapNode = svgNode.cloneNode(true);
    
    svgNode.classList.add('mainSvg');

    //svgNode must be appended BEFORE calculating width and height or they will be 0
    container.appendChild(svgNode);
    baseViewBox = svgNode.getBBox();
    curViewBox = baseViewBox;

    setViewBox(svgNode, curViewBox);

    let mapViewPort = document.createElementNS('xmlns="http://www.w3.org/2000/svg"', 'rect');
    mapViewPort.setAttribute('x', '10');
    mapViewPort.setAttribute('y', '10');
    mapViewPort.setAttribute('width', '100');
    mapViewPort.setAttribute('height', '100');

    svgMapNode.appendChild(mapViewPort);

    map.appendChild(svgMapNode);

    setViewBox(svgMapNode, baseViewBox);

}

function setViewBox(svgArg, rectArg) {
    svgArg.setAttribute('viewBox', `${rectArg.x} ${rectArg.y} ${rectArg.width} ${rectArg.height}`);
}

window.addEventListener('load', update);

const container = document.querySelector('#container');
const map = document.querySelector('#map');
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

div {
    background-color: rgb(250, 235, 215);
    border: solid 1px black;
}

#container {
    width: 90lvw;
    height: 90lvh;
}

#map {
    background-color: rgba(250, 235, 215, 0.9);
    position: absolute;
    top: 5lvh;
    right: 5lvh;
    width:12lvw;
    height:auto;
    padding: 3px 3px 0px 3px;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./css/svg-006.css" />
</head>

<body>
    <div id="container">
    </div>

    <div id="map">
        
    </div>

</body>

<script src="./js/svg-006.js">
</script>

</html>

In this page I'm showing the same SVG image in the div#container and in the div#map as a sort of thumbnail. Once i parsed the SVG code to create a document element, I made a deep clone of it in order to append it in the div#map. Then I want to add a rectangle in the div#map to overlap the image (I didn't define any style yet, just black rectangle to test).

The problem is that when I'm inspecting the page I can see the code for the <rect> element was added but it is not rendered nor seems to be inspectable by the browser. Instead, in developer console, if I delete manually the <rect> element and re-add it by editing the code of parent <svg> then the rectangle is correctly rendered apparently with the same identical code generated by the script. An other way I found to show the rectangle is to add it with JS at the end of the .innerHTML property of containing <svg> element. I could use this method to add the rectangle, but I'd like to understand why the code I wrote is not working. Thanks

Upvotes: 0

Views: 47

Answers (0)

Related Questions