如何创建"svg"对象而不附加它?

kjo*_*kjo 34 javascript d3.js

请考虑以下代码:

var svg = d3.select('#somediv').append("svg").attr("width", w).attr("height", h);
Run Code Online (Sandbox Code Playgroud)

我想重构这段代码,以便它更像这样:

var svg = makesvg(w, h);
d3.select("#somediv").append(svg);
Run Code Online (Sandbox Code Playgroud)

请注意,与第一个版本中显示的情况相反,在第二个版本append 中不会创建 "svg"对象; 它只会附加到它d3.select("#somediv").

问题是如何实现该功能makesvg.这反过来又减少了问题:如何在不使用的情况下实例化"svg"对象append,因为可以执行以下操作:

function makesvg(width, height) {
  return _makesvg().attr("width", w).attr("height", h);
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题归结为_makesvg()上面提到的假设工厂的通用等价物是什么?

Dre*_*kes 29

您可以使用以下内容:

var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
Run Code Online (Sandbox Code Playgroud)

注意使用createElementNS.这是必需的,因为svg元素与大多数HTML元素不在同一个XHTML名称空间中.

svg无论是否使用D3,此代码都会创建一个新元素,然后在该单个元素上创建一个选择.

这可以略微简洁但更清晰,更不容易出错:

var svg = document.createElementNS(d3.ns.prefix.svg, 'svg');
Run Code Online (Sandbox Code Playgroud)


Pau*_*aul 24

要节省一点时间,可以使用d3.ns.prefix.svg

var svg = document.createElementNS(d3.ns.prefix.svg, 'svg');
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说不适用于使用D3 v4`TypeError:d3.ns is undefined`.使用接受的答案的第一选择虽然完美无瑕. (2认同)

alt*_*lus 7

最后,与D3的发布V5(3月22日第二,2018),但是现在可以在D3自身完成.这不会影响其他答案,无论如何,这些答案仍然有效,最后,D3将会document.createElementNS()像之前的帖子中描述的那样使用.

从v5开始,您现在可以使用:

# d3.创建(名称)<>

给定指定的元素名称,返回包含当前文档中给定名称的分离元素的单元素选择.

这个新功能可以使用如下:

// Create detached <svg> element.
const detachedSVG = d3.create("svg");

// Manipulate detached element.
detachedSVG
  .attr("width", 400)
  .attr("height", 200);

// Bind data. Append sub-elements (also not attached to DOM).
detachedSVG.selectAll(null)
  .data([50, 100])
  .enter()
  //...

 // Attach element to DOM.
 d3.select("body")
   .append(() => detachedSVG.node());
Run Code Online (Sandbox Code Playgroud)

请查看以下代码片段,了解创建分离子树的工作演示,该子树附加在click事件上:

// Create detached <svg> element.
const detachedSVG = d3.create("svg");

// Manipulate detached element.
detachedSVG
  .attr("width", 400)
  .attr("height", 200);

// Bind data. Attach sub-elements.
detachedSVG.selectAll(null)
  .data([50, 100])
  .enter().append("circle")
    .attr("r", 20)
    .attr("cx", d => d)
    .attr("cy", 50);

// Still detached. Attach on click.
d3.select(document)
  .on("click", () => {
     // Attach element to DOM.
     d3.select("body")
       .append(() => detachedSVG.node());
  });
Run Code Online (Sandbox Code Playgroud)
<script src="https://d3js.org/d3.v5.js"></script>
Run Code Online (Sandbox Code Playgroud)

这种方法的主要优点是易于使用和清晰.元素的创建由D3在幕后完成,并且可以作为一个完整的选择,包含所有方法.除了操作新创建的分离元素之外,返回的选择可以很容易地用于数据绑定.

还值得注意的是,该函数不限制从SVG名称空间创建元素,但可用于从使用D3注册的任何名称空间创建元素.


小智 6

这是一个创建未附加组元素的示例函数:

function createSomething(){
  return function(){
    var group = d3.select(document.createElementNS(d3.ns.prefix.svg, 'g'));
    // Add stuff...
    return group.node();
  }
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样调用它:

node.append(createSomething());
Run Code Online (Sandbox Code Playgroud)

说明

假设您正在渲染一个可折叠的树,并且您希望使用带有圆边框的加/减图标作为切换.你的绘图功能已经非常庞大,所以你想要代码在它自己的函数中绘制加号.绘制/更新方法将负责正确定位.

一种选择是将现有容器传递给函数:

createPlus(node).attr({
  x: 10,
  y: 10
});

function createPlus(node){
  var group = node.append('g');
  // Add stuff...
  return group;
}
Run Code Online (Sandbox Code Playgroud)

我们可以通过应用@Drew和@Paul中的技术来创建未附加的元素,从而使这更好.

node.append(createPlus())
    .attr({
      x: 10,
      y: 10
    });

function createPlus(){
  var group = d3.select(document.createElementNS(d3.ns.prefix.svg, 'g'));
  // Add stuff...
  return group;
}
Run Code Online (Sandbox Code Playgroud)

除了因为append()需要字符串或函数而抛出错误.

该名称可以指定为常量字符串,也可以指定为返回要追加的DOM元素的函数.

所以我们只需将其更改为:

node.append(function(){
  return createPlus();
});
Run Code Online (Sandbox Code Playgroud)

但那仍然行不通.它会导致以下错误:

TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
Run Code Online (Sandbox Code Playgroud)

幸运的是我发现selection.node()哪个确实有效!虽然,诚然,我不知道为什么.

function createPlus(){
  var group = d3.select(document.createElementNS(d3.ns.prefix.svg, 'g'));
  // Add stuff...
  return group.node();
}
Run Code Online (Sandbox Code Playgroud)

我们可以通过将匿名函数移动到createPlus以下内容来节省更多时间:

node.append(createPlus())

function createPlus(){
  return function(){
    var group = d3.select(document.createElementNS(d3.ns.prefix.svg, 'g'));
    // Add stuff...
    return group.node();
  }
}
Run Code Online (Sandbox Code Playgroud)