Child elements not appearing in webpage

I’m learning how to use D3. After fixing up the code from this example (https://jsfiddle.net/tgsen1bc/ ) to run the newest version of D3, I managed to get the links to show but not the nodes or their labels.

EDIT: I got the nodes to appear 🙂 My problem now is that some child elements of the <g>‘s do not appear so the labels for the nodes don’t appear. For example, in Chrome Dev Tools, the child elements of <foreignObject> (a child of <g>) do not appear on the window. I tried making <foreignObject> extremely large but the child elements still do not appear. I also tried replacing the <foreignObject> with a <div>, but the <div> ended up disappearing as well. I checked the parent css properties and it doesn’t seem like anything should be blocking the child elements from appearing. The only child element that appears are the circle <svg> and <foreignObject> The code section for the label is:

    // Add labels for the nodes     nodeEnter.append('foreignObject')       .attr("y", -30)       .attr("x", -5)       .attr("text-anchor", function (d) {         return d.children || d._children ? "end" : "start";       })       .attr('width', 100)       .attr('height', 50)       .append('div')                     // doesn't show up on webpage       .attr("class", function (d) {         return "node-label" + " node-" + d.data.type       })       .classed("disabled", function (d) {         return d.enable !== undefined && !d.enable;       })       .append("span")                   // doesn't show up on webpage       .attr("class", "node-text")       .text(function (d) {              // correct label in chrome dev tools         return d.data.name;             // but does not show up on webpage       }); 
var treedata = {     "name": "PublisherNameLongName",     "id": "id1",     "type": "type0",     "addable": false,     "editable": false,     "removable": false,     "enableble": false,     "children": [{       "name": "Landing A",       "id": "id2",       "type": "type1",       "addable": true,       "editable": true,       "removable": true,       "enablable": true,       "enable": false,       "children": null     }]   }    // Set the dimensions and margins of the diagram   var margin = { top: 20, right: 20, bottom: 20, left: 20 },     width = 800 - margin.left - margin.right,     height = 600 - margin.top - margin.bottom,     i = 0,     x = d3.scaleLinear().domain([0, width]).range([0, width]),     y = d3.scaleLinear().domain([0, height]).range([0, height]),     root;    // append the svg object to the body of the page   // appends a 'group' element to 'svg'   // moves the 'group' element to the top left margin   var vis = d3.select("#root")     .append("svg")     .attr("width", width + margin.right + margin.left)     .attr("height", height + margin.top + margin.bottom)     .attr("transform", "translate(" + margin.left + "," + margin.top + ")")     ;    vis.append("rect")     .attr("class", "overlay")     .attr("width", width + margin.right + margin.left)     .attr("height", height + margin.top + margin.bottom)     .attr("opacity", 0)    var tree = d3.tree().size([height, width]);    // Draws curved diagonal path from parent to child nodes   function diagonal(s, d) {     return `M ${s.y} ${s.x}             C ${(s.y + d.y) / 2} ${s.x},               ${(s.y + d.y) / 2} ${d.x},               ${d.y} ${d.x}`   }    root = d3.hierarchy(treedata, function (d) {     return d.children;   });   root.x0 = height / 2;   root.y0 = 0;    // open or collaspe children of selected node   function toggleAll(d) {     if (d.children) {       d.children.forEach(toggleAll);       toggle(d);     }   };    // Initialize the display to show a few nodes   // root.children.forEach(toggleAll);     update(root);    function update(source) {     // how long animations last     var duration = d3.event && d3.event.altKey ? 5000 : 500;     // Compute the new tree layout.      var treeObj = tree(root)     var nodes = treeObj.descendants(),       links = treeObj.descendants().slice(1);      // Normalize for fixed-depth.     nodes.forEach(function (d) {       d.y = d.depth * 180;     });        /********************* NODES SECTION *********************/      // Update the nodes...     var node = vis.selectAll("g.node")       .data(nodes, function (d) {         return d.id || (d.id = ++i);       });      // Enter any new nodes at the parent's previous position.     var nodeEnter = node.enter().append("g")       .attr("class", "node")       .attr("id", function (d) {         return "node-" + d.id;       })       .attr("transform", function (d) {         return "translate(" + source.y0 + "," + source.x0 + ")";       })       .on("click", function (d) {         toggle(d);         update(d);       });      // Add Circle for the nodes     nodeEnter.append("circle")       .attr("class", "circle-for-nodes")       .attr("r", 1e-6)       .style("fill", function (d) {         return d._children ? "lightsteelblue" : "#fff";       })       // Add labels for the nodes     nodeEnter.append('foreignObject')       .attr("y", -30)       .attr("x", -5)       .attr("text-anchor", function (d) {         return d.children || d._children ? "end" : "start";       })       .attr('width', 100)       .attr('height', 50)       .append('div')       .attr("class", function (d) {         return "node-label" + " node-" + d.data.type       })       .classed("disabled", function (d) {         return d.enable !== undefined && !d.enable;       })       .append("span")       .attr("class", "node-text")       .text(function (d) {         return d.data.name;       });      // Enable node button if enablable     nodeEnter.filter(function (d) {       return d.enablable;     })       .append("input", ".")       .attr("type", "checkbox")       .property("checked", function (d) {         return d.enable;       })       .on("change", toggleEnable, true)       .on("click", stopPropogation, true);      // Edit node button if editable     nodeEnter.filter(function (d) {       return d.editable;     })       .append("a")       .attr("class", "node-edit")       .on("click", onEditNode, true)       .append("i")       .attr("class", "fa fa-pencil");      // Add node button if addable     nodeEnter.filter(function (d) {       return d.addable;     })       .append("a")       .attr("class", "node-add")       .on("click", onAddNode, true)       .append("i")       .attr("class", "fa fa-plus");      // Remove node button if removable     nodeEnter.filter(function (d) {       return d.removable;     })       .append("a")       .attr("class", "node-remove")       .on("click", onRemoveNode, true)       .append("i")       .attr("class", "fa fa-times");      // UPDATE - merges all transitions together?     // var nodeUpdate = node;     var nodeUpdate = nodeEnter.merge(node);      // Transition nodes to their new position.     nodeUpdate.transition()       .duration(duration)       .attr("transform", function (d) {         return "translate(" + d.y + "," + d.x + ")";       });      // Display node     nodeUpdate.select("circle.circle-for-nodes")       .attr("r", 4.5)       .style("fill", function (d) {         return d._children ? "lightsteelblue" : "#fff";       })      // Display text     nodeUpdate.select(".node-text")       .style("fill-opacity", function (d) {         console.log(d)         return 1;       })      // Transition exiting ndoes to the parent's new position.     var nodeExit = node.exit().transition()       .duration(duration)       .attr("transform", function (d) {         return "translate(" + source.y + "," + source.x + ")";       })       .remove();      // On exit reduce the node circles size to 0     nodeExit.select("circle")       .attr("r", 1e-6);     // On exit reduce the opacity of text labels     nodeExit.select("text")       .style("fill-opacity", 1e-6);        /********************* LINKS SECTION *********************/      // Update the links...     var link = vis.selectAll("path.link")       .data(links, function (d) { return d.id; });      // Enter any new links at the parent's previous position     var linkEnter = link.enter().insert("path", "g")       .attr("class", "link")       .attr("d", function (d) {         var o = { x: source.x0, y: source.y0 };         return diagonal(o, o);       })      // UPDATE - merges all transitions together?     var linkUpdate = linkEnter.merge(link);      // Transition back to the parent element position.     linkUpdate.transition()       .duration(duration)       .attr("d", function (d) {         return diagonal(d, d.parent)       });      // Remove exiting links     var linkExit = link.exit().transition()       .duration(duration)       .attr("d", function (d) {         var o = { x: source.x, y: source.y };         return diagonal(o, o);       })       .remove();      // Stash the old positions for transition.     nodes.forEach(function (d) {       d.x0 = d.x;       d.y0 = d.y;     });      // End of function update()   }    // Toggle children   function toggle(d) {     if (d.children) {       d._children = d.children;       d.children = null;     } else {       d.children = d._children;       d._children = null;     }   }    // zoom in / out   function zoom(d) {     //vis.attr("transform", "transl3ate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");     var nodes = vis.selectAll("g.node");     nodes.attr("transform", transform);      // Update the links...     var link = vis.selectAll("path.link");     link.attr("d", translate);      // Enter any new links at hte parent's previous position     //link.attr("d", function(d) {     //      var o = {x: d.x0, y: d.y0};     //      return diagonal({source: o, target: o});     //    });   }    function transform(d) {     return "translate(" + x(d.y) + "," + y(d.x) + ")";   }    function translate(d) {     var sourceX = x(d.target.parent.y);     var sourceY = y(d.target.parent.x);     var targetX = x(d.target.y);     var targetY = (sourceX + targetX) / 2;     var linkTargetY = y(d.target.x0);     var result = "M" + sourceX + "," + sourceY + " C" + targetX + "," + sourceY + " " + targetY + "," + y(d.target.x0) + " " + targetX + "," + linkTargetY + "";      return result;   }    function onEditNode(d) {     var length = 9;     var id = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, length);     addChildNode(d.id, {       "name": "new child node",       "id": id,       "type": "type2"     });     stopPropogation();   }    function onAddNode(d) {     var length = 9;     var id = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, length);     addChildNode(d.id, {       "name": "new child node",       "id": id,       "type": "type2"     });     stopPropogation();   }    function onRemoveNode(d) {     var index = d.parent.children.indexOf(d);     if (index > -1) {       d.parent.children.splice(index, 1);     }     update(d.parent);     stopPropogation();   }    function addChildNode(parentId, newNode) {     var node = d3.select('#' + 'node-' + parentId);     var nodeData = node.datum();     if (nodeData.children === undefined && nodeData._children === undefined) {       nodeData.children = [newNode];     } else if (nodeData._children != null) {       nodeData._children.push(newNode);       toggle(nodeData);     } else if (nodeData.children != null) {       nodeData.children.push(newNode);     }     update(node);     stopPropogation();   }    function toggleEnable(d) {     d.enable = !d.enable;     var node = d3.select('#' + 'node-' + d.id + " .node-label")       .classed("disabled", !d.enable);     stopPropogation();   }     function stopPropogation() {     d3.event.stopPropagation();   }
body {   height: 100vh;   width: 100vw;   margin: 0;   padding: 0; }  .node circle {   cursor: pointer;   fill: #fff;   stroke: steelblue;   stroke-width: 1.5px; }  .node-label {   font-size: 12px;   padding: 3px 5px;   display: inline-block;   word-wrap: break-word;   max-width: 160px;   background: #d0dee7;   border-radius: 5px; }  .node a:hover {   cursor: pointer; }  .node a {   font-size: 10px;   margin-left: 5px }  a.node-remove {   color: red; } input+.node-text {   margin-left: 5px; } .node-label.node-type1 {   background: coral; } .node-label.node-type2 {   background: lightblue; } .node-label.node-type3 {   background: yellow; } .node-label.disabled {   background: #e9e9e9;   color: #838383 } .node text {   font-size: 11px; }  path.link {   fill: none;   stroke: #ccc;   stroke-width: 1.5px; }
<!DOCTYPE html>   <meta charset="utf-8" />   <script src="https://d3js.org/d3.v5.js"></script>   <body>     <div id="root"></div>   </body>

Add Comment
1 Answer(s)

Found my answer here: HTML element inside SVG not displayed

To summarize what Christopher said, <div></div> is not recognized as a xhtml paragraph because the namespace xhtml is not included in the foreignObject context (a foreignObject might contain anything (xml formated data for example). To specify the input as html, I needed to .append("xhtml:div")

Answered on July 16, 2020.
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.