Creating and appending detached elements with d3.c

2020-02-06 10:21发布

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?

1条回答
相关推荐>>
2楼-- · 2020-02-06 10:51

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 namespace (source: Fakedata Inc.). Therefore, instead of:

selection.append("svg:rect")

We 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.

查看更多
登录 后发表回答