I am trying to get D3.js to generate rectangle elements with d3.create(). It does not work/display.
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
}
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() }
)
Yet there is no visual output in my browser (Google Chrome).
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>
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.
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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With