Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating and appending detached elements with d3.create

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?

like image 811
Nibor Avatar asked Apr 24 '18 10:04

Nibor


People also ask

What does D3 append do?

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.

How to append HTML in D3?

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.

What is use of DOM and SVG in D3?

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.

Can we group SVG elements in d3js?

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.


1 Answers

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>

Explanation

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.

like image 198
Gerardo Furtado Avatar answered Oct 25 '22 08:10

Gerardo Furtado