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