title: how to append a circle with a label to indicate information to rectangle node and remove the circle before download
body: <p>I have a vertical D3JS tree where the nodes are rectangles.  I would like to append a circle with the italic letter &quot;<em>i</em>&quot; to the top right corner of the rectangle node to indicate that the node has additional information.  I managed to append the italic letter &quot;i&quot; only, however, I am not able to put it in a circle and still keep the node clickable. Also I use cloning for downloading the tree as a SVG file and would like to remove this appended circle and the letter &quot;<em>i</em>&quot; from the cloned group element before downloading and printing.</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="false" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var treeData = [{
    "name": "Top Level",
    "parent": "null",
    "remark": "yes",
    "children": [{
        "name": "Level 2: A",
        "parent": "Top Level",
        "remark": "yes",
        "children": [{
            "name": "Son of A",
            "parent": "Level 2: A",
            "remark": "null"
          },
          {
            "name": "Daughter of A",
            "parent": "Level 2: A",
            "remark": "null"
          }
        ]
      },
      {
        "name": "Level 2: B",
        "parent": "Top Level",
        "remark": "null"
      }
    ]
  }];
  
  //*************************************************************************************
  // 1. Create the button
  var button = document.createElement("button");
  button.innerHTML = "download file";
  //*************************************************************************************
  
  // ************** Generate the tree diagram  *****************
  var margin = {
      top: 20,
      right: 120,
      bottom: 20,
      left: 120
    },
    width = 960 - margin.right - margin.left,
    height = 500 - margin.top - margin.bottom;
  
  var i = 0,
    rectW = 100,
    rectH = 30,
    duration = 750,
    root;
  
  var tree = d3.layout.tree()
    .size([height, width]);
  
  //swap x and y for vertical
  var diagonal = d3.svg.diagonal()
    .projection(function(d) {
      return [d.x + rectW / 2, d.y + rectH / 2];
      //  .projection(function(d) { return [d.x, d.y]; });
    });
  
  //var gElement = document.createElement('svg:g');
  var gElement = document.createElementNS(d3.ns.prefix.svg, 'g');
  gElement.setAttribute("id", "fg");
  console.log(gElement);
  
  var svg = d3.select("body").append("svg")
    .attr("width", width + margin.right + margin.left)
    .attr("height", height + margin.top + margin.bottom)
    .append(function() {
      return gElement;
    }) //The argument to .append() has to be a function, you can't just pass element to it.
    //    .append("svg:g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  
  root = treeData[0];
  root.x0 = height / 2;
  root.y0 = 0;
  
  update(root);
  
  d3.select(self.frameElement).style("height", "500px");
  
  
  function update(source) {
  
    // Compute the new tree layout.
    var nodes = tree.nodes(root).reverse(),
      links = tree.links(nodes);
  
    // Normalize for fixed-depth.
    nodes.forEach(function(d) {
      d.y = d.depth * 180;
    });
  
    // Update the nodes…
    var node = svg.selectAll("g.node")
      .data(nodes, function(d) {
        return d.id || (d.id = ++i);
      });
  
    // Enter any new nodes at the parent's previous position.
    //swap x and y for vertical
    var nodeEnter = node.enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) {
        return "translate(" + source.x0 + "," + source.y0 + ")";
      })
      .on("click", click);
  
    nodeEnter.append("rect")
      //nodeEnter.append("circle")
      //  .attr("r", 1e-6)
      .attr("width", rectW)
      .attr("height", rectH)
      .style("fill", function(d) {
        return d._children ? "lightsteelblue" : "#fff";
      });
  
    nodeEnter.append("text")
      .attr("x", function(d) {
        return d.children || d._children ? -13 : 13;
      })
      .attr("dy", ".35em")
      .attr("text-anchor", function(d) {
        return d.children || d._children ? "end" : "start";
      })
      .text(function(d) {
        return d.name;
      })
      .style("fill-opacity", 1e-6);
  
  
    // IAH 20/01/2019 Filter to put tooltip only on nodes that have information associated with it
    nodeEnter.filter(function(d) {
        return (d.remark != 'null')
      })
      .append("text")
      .attr("id", "infoText")
      .attr("x", 96)
      .attr("y", 7)
      .attr("dy", ".30em")
      .style("font-style", "italic")
      .style("font-family", "serif")
      .style("font-weight", "bold")
      .text("i");
  
    // Transition nodes to their new position.
    //swap x and y for vertical layout
    var nodeUpdate = node.transition()
      .duration(duration)
      .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
      });
  
    //nodeUpdate.select("circle")
    nodeUpdate.select("rect")
      .attr("width", rectW)
      .attr("height", rectH)
      .style("stroke", "black")
      //  .attr("r", 10)
      .style("fill", function(d) {
        return d._children ? "lightsteelblue" : "#fff";
      });
  
    nodeUpdate.select("text")
      .attr("x", rectW / 2)
      .attr("y", rectH / 2)
      .attr("dy", ".35em")
      .attr("text-anchor", "middle")
      .style("fill-opacity", 1);
  
    // Transition exiting nodes to the parent's new position.
    //vertical switch x and y positions
    var nodeExit = node.exit().transition()
      .duration(duration)
      .attr("transform", function(d) {
        return "translate(" + source.x + "," + source.y + ")";
      })
      .remove();
  
    //nodeExit.select("circle")
    nodeExit.select("rect")
      .attr("r", 1e-6);
  
    nodeExit.select("text")
      .style("fill-opacity", 1e-6);
  
    // Update the links…
    var link = svg.selectAll("path.link")
      .data(links, function(d) {
        return d.target.id;
      });
  
    // Enter any new links at the parent's previous position.
    link.enter().insert("path", "g")
      .attr("class", "link")
      .attr("stroke", "#ccc")
      .attr("fill", "none")
      .attr("stroke-width", "2px")
      .attr("d", function(d) {
        var o = {
          x: source.x0,
          y: source.y0
        };
        return diagonal({
          source: o,
          target: o
        });
      });
  
    // Transition links to their new position.
    link.transition()
      .duration(duration)
      .attr("d", diagonal);
  
    // Transition exiting nodes to the parent's new position.
    link.exit().transition()
      .duration(duration)
      .attr("d", function(d) {
        var o = {
          x: source.x,
          y: source.y
        };
        return diagonal({
          source: o,
          target: o
        });
      })
      .remove();
  
    // Stash the old positions for transition.
    nodes.forEach(function(d) {
      d.x0 = d.x;
      d.y0 = d.y;
    });
  
  }
  
  // Toggle children on click.
  function click(d) {
    if (d.children) {
      d._children = d.children;
      d.children = null;
    } else {
      d.children = d._children;
      d._children = null;
    }
    update(d);
  }
  
  //*************************************************************************************
  // 2. Append button somewhere
  var body = document.getElementsByTagName("body")[0];
  body.appendChild(button)
    .setAttribute("transform", "translate(" + 0 + "," + 0 + ")");
  
  //*************************************************************************************
  
  function svgDataURL(svg) {
    var svgAsXML = (new XMLSerializer).serializeToString(svg);
    var dataURL = "data:image/svg+xml," + encodeURIComponent(svgAsXML);
    return dataURL;
  }
  
  button.onclick = function() {
    var svgElement = document.querySelector('svg');
    var svgWH = svgElement.getBBox();
  
    var canvasWidth = svgWH.width;
    var canvasHeight = svgWH.height;
  
    var groupElement = document.getElementById('fg');
    groupElement.setAttribute("transform", "translate(0,0)");
  
    const bb = groupElement.getBBox();
  
    // clone the svg to avoid destroying it while appending to the svg namespace
    let clonedGroupElement = groupElement.cloneNode(true);
  
    var svgContent = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  
    svgContent.setAttribute('viewBox', ' ' + bb.x + ' ' + bb.y + '  ' + bb.width + ' ' + bb.height);
  
    svgContent.setAttribute("width", "100%");
    svgContent.setAttribute("height", "100%");
    svgContent.setAttribute("preserveAspectRatio", "xMidYMid meet");
  
    // try to remove the information icon before downloading
    var rmText = document.getElementById('infoText');
    console.log(rmText);
  
    svgContent.appendChild(clonedGroupElement); // use the cloned nodes
  
    var dl = document.createElement('a');
    document.body.appendChild(dl);
    dl.setAttribute("href", svgDataURL(svgContent)); // function svgDataURL expects a node
    dl.setAttribute("download", "test.svg");
    dl.click();
    dl.remove();
  
    svgContent.removeChild(clonedGroupElement);
  };</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>.node {
    cursor: pointer;
  }
  
  .node circle {
    fill: #fff;
    stroke: steelblue;
    stroke-width: 3px;
  }
  
  .node text {
    font: 12px sans-serif;
  }
  
  .link {
    /*
        fill: none;
        stroke: #ccc;
        stroke-width: 2px;*/
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"&gt;&lt;/script&gt;</code></pre>
  </div>
  </div>
  </p>