javascripthtmlsvgdom

How to trigger SVG render same as manual DOM edit in Chrome using JS?


When I modify the DOM structure of an SVG element within an HTML document in Chrome via JS (specifically using replaceWith or appendChild to bring in new content), although the Chrome Elements tree reflects the modification, the result is not rendered. However if I make any manual edit to the DOM content via Edit as HTML above the offending modification, this will cause any unrendered content of a descendant in the DOM to be rendered. Adding a single white space to any ancestor Element will do. Edits in Chrome obviously trigger some kind of deeper re-render which is what I'd like to access programmatically.

Is there a way to do this in JS? Note that I did test the obvious "use JS to modify the DOM" but this does not have the effect that doing it manually does.

document.body.insertAdjacentText('afterbegin', 'XXXX')

The Node I'm supplying to replaceWith is from a section in the HTML like this:

<template id=mytemplate>
<rect width="139.12148" height="130.4722" x="298.91934" y="233.69247"></rect>
</template>

And this is my JS:

clone = document.querySelector('#mytemplate').content.cloneNode(true).firstChild;
placeholder = document.querySelector('#placeholderelementinSVG');
placeholder.replaceWith(clone);

Solution

  • You've two problems.

    1. That's not an SVG rect, it's an HTML rect. An SVG rect needs to have an ancestor <svg> element in HTML.
    2. firstChild will get you the whitespace between the end of the <template> element and the beginning of the <rect> element.

    If you edit the rect markup after it's been put in the tree then the HTML parser will correct the namespace of the rect from the HTML namespace to the SVG namespace when it runs but that's kind of expensive compared to creating the rect in the correct namespace in the first place. You want to avoid reparsing things if you can.

    I've corrected both of the issues below. Given the position of the rect you might need to make the snippet full page in order to see the rect.

    let clone = document.querySelector('#mytemplate').content.children[0].children[0].cloneNode(true);
    placeholder = document.querySelector('#placeholderelementinSVG');
    placeholder.replaceWith(clone);
    html, body {
      width: 100%;
      height: 100%;
    }
    <template id=mytemplate>
    <svg>
    <rect width="139.12148" height="130.4722" x="298.91934" y="233.69247"></rect>
    </svg>
    </template>
    <svg width="100%" height="100%"><rect id="placeholderelementinSVG"/></svg>