Let's say I create a simple graphic like this:
<!doctype html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<svg></svg>
<script>
const svg = d3.select('svg');
const g = svg.append('g');
g.append('g')
.selectAll('g')
.data([5, 10, 20, 40])
.enter()
.append('rect')
.attr('fill', 'green')
.attr('x', d => d)
.attr('y', d => d)
.attr('height', d => d)
.attr('width', d => d);
</script>
</body>
</html>
But instead of just appending to it, I want to create a detached <g> which can then be appended at will (e.g. it could be returned from a function).
With d3 V5 there is a d3.create() function which creates a detached element.
<!doctype html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<svg></svg>
<script>
const svg = d3.select('svg');
const g = svg.append('g');
const detachedG = d3.create('g');
detachedG.selectAll('g')
.data([5, 10, 20, 40])
.enter()
.append('rect')
.attr('fill', 'green')
.attr('x', d => d)
.attr('y', d => d)
.attr('height', d => d)
.attr('width', d => d);
g.append(() => detachedG.node());
</script>
</body>
</html>
But it doesn't appear in the browser, even though the DOM looks the same.
Any ideas how to fix this?
d3 append() append() - Appends a new element with the specified name as the last child of each element in the current selection, returning a new selection containing the appended elements.
append() Function. The selection. append() function is used to append a new element to the HTML tag name as given in the parameters to the end of the element.
SVG is text-based, and it is an image format that is vector-based. SVG is the same as the HTML structure. It can be illustrated as the DOM (Document Object Model). The properties of SVG can be described as attributes.
The <g> SVG element is a container used to group other SVG elements. Transformations applied to the <g> element are performed on its child elements, and its attributes are inherited by its children. We can create a group element with D3. js by appending a g element using any selection.
Just namespace it:
const detachedG = d3.create('svg:g');
Here is the code with that change:
<!doctype html>
<html lang="en">
<head><script src="https://d3js.org/d3.v5.min.js"></script></head>
<body>
<svg></svg>
<script>
const svg = d3.select('svg');
const g = svg.append('g');
const detachedG = d3.create('svg:g');
detachedG.selectAll('g')
.data([5,10,20,40])
.enter()
.append('rect')
.attr('fill', 'green')
.attr('x', d => d)
.attr('y', d => d)
.attr('height', d => d)
.attr('width', d => d);
g.append(() => detachedG.node());
</script>
</body>
</html>
When appending SVG elements with the append() method, 98.47% of D3 programmers don't use namespaces (source: Fakedata Inc.). Therefore, instead of:
selection.append("svg:rect")
We normally just do:
selection.append("rect")
So, why do you need a namespace here?
Internally, d3.create uses d3.creator calling it with document.documentElement:
export default function(name) {
return select(creator(name).call(document.documentElement));
}
That changes the this for the d3.creator method. We normally don't use namespaces when we create SVG elements using append (which internally uses d3.creator), since:
If no namespace is specified, the namespace will be inherited from the parent element.
However, because of the use of document.documentElement as this, the namespace becomes necessary in this case.
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