Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3.create() returns an element with .node(), but does not display in the browser [duplicate]

  1. I am trying to get D3.js to generate rectangle elements with d3.create(). It does not work/display.

  2. First, I create a rectangle() function, which returns an element:

    function rectangle() {
    
        _el = d3.create("rect")
            .attr("stroke", "black")
            .attr("fill", "black")
            .attr("stroke-width", "10px")
            .attr("x", 0)
            .attr("y", 0)
            .attr("width", 300)
            .attr("height", 200);
    
        return _el
    
    }
    
  3. I then create an SVG selection, to which I append an instance of rectangle().node():

    
    const SVG_WIDTH = 1000;
    const SVG_HEIGHT = 1000;
    
    svg = d3.select("body").append("svg")
        .attr("width", SVG_WIDTH)
        .attr("height", SVG_HEIGHT)
        .attr("id", "generated")
    
    svg.append(
        // () => rectangle().node()
        function () { return rectangle().node() }
    )
    
  4. Yet there is no visual output in my browser (Google Chrome).

  5. However, when I look into the DOM (via Chrome's 'Elements' tab), D3 has generated the correct SVG/rectangle code:

    <svg width="1000" height="1000" id="generated">
        <rect stroke="black" fill="black" stroke-width="10px" x="0" y="0" width="300" height="200" rx="10" ry="10"></rect>
    </svg>
    
  6. In fact, If I copy the above code and place it anywhere else in my HTML file without modification, a rectangle appears in my browser.

  7. Why is SVG's modification of the browser DOM not showing/working, yet the code it generates is correct and will show up when manually copy/pasted into the HTML?

like image 840
xax Avatar asked Dec 01 '25 06:12

xax


1 Answers

From d3.create documentation:

This method assumes the HTML namespace, so you must specify a namespace explicitly when creating SVG or other non-HTML elements [...]

    d3.create("svg") // equivalent to svg:svg  
    d3.create("svg:svg") // more explicitly  
    d3.create("svg:g") // an SVG G element  
    d3.create("g") // an HTML G (unknown) element  

Thus, the function that creates the rectangle should use svg:rect. Otherwise it will create an "HTML rect" instead of an "SVG rect".

The d3.create method by default creates elements in the HTML namespace. When you use d3.create('rect') you're not creating an SVG rectangle, but instead an HTML rectangle (which don't exist in the HTML specification). The element appears at the DOM, but the browser don't know how to render it (it has the name of an SVG element, but is not an SVG element), so it does not appear on the screen.

Every HTML element has an implict xhtml: prefix, and every SVG element inside an SVG implicitly has an svg: prefix. Usually you don't need to worry about it because the namespace is often obvious enough to be handled by the library. However, d3.create can't tell which one you want, because it is a detached element; so it defaults to HTML.

So, even though both svg:rect and xhtml:rect have the same name on the DOM, they refer to different specifications, and the only one that makes sense for browsers is the svg:rect.

like image 91
Rodrigo Divino Avatar answered Dec 03 '25 18:12

Rodrigo Divino



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!