Issue with dynamic SVG rendering from JavaScript

I am foraying back into the world of web development, so there is a good chance that this is something silly I have overlooked.

I have been able to dynamically create all the HTML components for the SVG I am trying to create, however the resulting image isn’t displayed in it’s container. My aim is to create an SVG element with a random number of circles, this needs to be repeatable so that I can display more than one on the page at a time.

This is an example of what my code outputs:

<svg class="canvas" id="gen1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
 <filter id="shadow">
   <feDropShadow dx="0" dy="10" stdDeviation="2" flood-opacity="0.4"></feDropShadow> 
 </filter>
 <radialGradient id="highlight" cx="50%" cy="50%" r="50%" fx="50%" fy="25%">
  <stop offset="0%" stop-color="#FF4D4D"></stop>
  <stop offset="100%" stop-color="#8B0000"></stop>
 </radialGradient>
 <circle id="circle1" cx="500" cy="166.66666666666666" r="83.33333333333333" fill="url(#highlight)" filter="url(#shadow)"></circle>
 <circle id="circle2" cx="500" cy="666.6666666666666" r="83.33333333333333" fill="url(#highlight)" filter="url(#shadow)"></circle>
 <circle id="circle3" cx="166.6666666666669" cy="744.0169358562925" r="83.33333333333333" fill="url(#highlight)" filter="url(#shadow)"></circle>
 <circle id="circle4" cx="750.0000000000001" cy="599.6793685588859" r="83.33333333333333" fill="url(#highlight)" filter="url(#shadow)"></circle>
</svg>

If I take the above code and paste it into an online SVG viewer the output is exactly what I expect it to be. However inside the basic page I have built it doesn’t show any of the circles, even though when I inspect the HTML I can see all these elements there.

This is the code I am using to generate the SVG:

function buildCanvas(canvasNumber) {
    let canvas = buildNode(new Node("div", [new Attribute("class", "canvas"), new Attribute("id", "gen" + canvasNumber)], undefined, [
        new Node("h1", [new Attribute("class", "canvasTitle"), new Attribute("id", "canvas" + canvasNumber + "Title")], "Canvas " + canvasNumber),
        new Node("svg", [new Attribute("ns", "http://www.w3.org/2000/svg"), new Attribute("class", "canvas"), new Attribute("id", "canvas" + canvasNumber + "Layout"), new Attribute("xmlns", "http://www.w3.org/2000/svg"), new Attribute("viewBox", "0 0 1000 1000")], undefined,  [
            new Node("filter", [new Attribute("ns", "http://www.w3.org/2000/svg"), new Attribute("id", "shadow")], undefined, [
                new Node("feDropShadow", [new Attribute("ns", "http://www.w3.org/2000/svg"), new Attribute("dx", "0"), new Attribute("dy", "10"), new Attribute("stdDeviation", "2"), new Attribute("flood-opacity", "0.4")])
            ]),
            new Node("radialGradient",  [new Attribute("ns", "http://www.w3.org/2000/svg"), new Attribute("id", "highlight"), new Attribute("cx", "50%"), new Attribute("cy", "50%"), new Attribute("r", "50%"), new Attribute("fx", "50%"), new Attribute("fy", "25%")], undefined, [
                new Node("stop", [new Attribute("ns", "http://www.w3.org/2000/svg"), new Attribute("offset", "0%"), new Attribute("stop-color", "#FF4D4D")]),
                new Node("stop", [new Attribute("ns", "http://www.w3.org/2000/svg"), new Attribute("offset", "100%"), new Attribute("stop-color", "#8B0000")])
            ])
        ].concat(drawHole(canvases[canvasNumber - 1]))),
        new Node("h3", [new Attribute("class", "canvasTarget"), new Attribute("id", "canvas" + canvasNumber + "Target")], "Target " + canvases[canvasNumber - 1].target),
        new Node("div", [new Attribute("class", "canvasScores"), new Attribute("id", "canvas" + canvasNumber + "Scores")])
    ]));
    return canvas;
}

function drawHole(canvas) {
    const circlePositions = canvas.circles;
    let circleNum = 1;
    let circles = [];
    ballPositions.forEach(ball => {
        balls.push(new Node("circle", [
            new Attribute("ns", "http://www.w3.org/2000/svg"),
            new Attribute("id", "ball" + circleNum),
            new Attribute("cx", ball.x),
            new Attribute("cy", ball.y),
            new Attribute("r", 1000/12),
            new Attribute("fill", "url(#highlight)"),
            new Attribute("filter", "url(#shadow)")]))
        circleNum++;
    });

    return balls;
}

function buildNode(node = new Node("div")) {
    let nodeComp = document.createElement(node.type);
    if (node.attributes != null && typeof node.attributes !== "undefined" && node.attributes.length > 0) {
        let ns;
        for (let position = 0; position < node.attributes.length; position++) {
            if (node.attributes[position].type == "ns") {
                ns = node.attributes[position].value;
                nodeComp = document.createElementNS(ns, node.type);
                continue;
            }
            if (ns != null && typeof ns !== "undefined") {
                try {
                    nodeComp.setAttributeNS(ns, node.attributes[position].type, node.attributes[position].value);
                    continue;
                }
                catch (err) {

                }
            }
            let attribute = document.createAttribute(node.attributes[position].type);
            attribute.value = node.attributes[position].value;
            nodeComp.setAttributeNode(attribute);
        }
    }
    if (node.content != null && typeof node.content !== "undefined") {
        nodeComp.innerHTML = node.content;
    }
    if (node.childNodes != null && typeof node.childNodes !== "undefined" && node.childNodes.length > 0) {
        for (let childNode = 0; childNode < node.childNodes.length; childNode++) {
            nodeComp.insertAdjacentElement("beforeend", buildNode(node.childNodes[childNode]));
        }
    }
    return nodeComp;
}

If anyone can spot my mistake or niggle to make the circles display on the canvas please put me out of my misery.