12

我想创建一个可以采用通用 D3 选择的 javascript 函数,并将其副本附加到 SVG 对象。

这是一个最小的工作示例:

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

svg = d3.select("body").append("svg")
                         .attr("width", 300)
                         .attr("height", 300);

circle = svg.append("circle")
              .attr("cx", 100)
              .attr("cy", 100)
              .attr("r", 20)

function clone_selection(x, i) {
  for (j = 0; j < i; j++) {
    // Pseudo code:
    // svg.append(an exact copy of x, with all the attributes)
  }
}

clone_selection(circle, 5);
</script>

Mike Bostock 说这在这里是不可能的,但那是前一阵子了。

有没有人对如何实现这一点有任何新的想法?请记住,在函数内部,clone_selection我们不知道 x 中的 svg 元素是什么。

4

5 回答 5

12

这是另一种可能性:做事很长。这解决了使用<use>无法单独设置styleortransform属性的元素的问题。

我很惊讶这个惊人的d3js库本身并没有这样的功能,但这是我的 hack:

function clone_d3_selection(selection, i) {
            // Assume the selection contains only one object, or just work
            // on the first object. 'i' is an index to add to the id of the
            // newly cloned DOM element.
    var attr = selection.node().attributes;
    var length = attr.length;
    var node_name = selection.property("nodeName");
    var parent = d3.select(selection.node().parentNode);
    var cloned = parent.append(node_name)
                 .attr("id", selection.attr("id") + i);
    for (var j = 0; j < length; j++) { // Iterate on attributes and skip on "id"
        if (attr[j].nodeName == "id") continue;
        cloned.attr(attr[j].name,attr[j].value);
    }
    return cloned;
}
于 2013-08-30T15:52:06.793 回答
5

感谢@nrabinowitz 向我指出<use>元素。

这是 MWE 完整的工作解决方案:

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

svg = d3.select("body").append("svg")
             .attr("width", 300)
             .attr("height", 300);

circle = svg.append("circle")
          .attr("id", "circleToClone")
          .attr("cx", 100)
          .attr("cy", 100)
          .attr("r", 20)

function clone_selection(object, i) {
  for (j = 0; j < i; j++) {
    // Here's the solution:
    cloned_obj = svg.append("use")
                .attr("xlink:href","#" + object.attr("id"));
  }
}

clone_selection(circle, 5);
</script>
于 2013-08-30T12:09:32.377 回答
5

此函数对 d3 的选择进行深层复制并返回复制元素的选择:

function cloneSelection(appendTo, toCopy, times) {
  toCopy.each(function() {
    for (var i = 0; i < times; i++) {
        var clone = svg.node().appendChild(this.cloneNode(true));
        d3.select(clone).attr("class", "clone");
    }
  });
  return appendTo.selectAll('.clone');
}

在此处查看演示。

如果选择 toCopy 包含多个元素,此功能也有效。

但请注意,它会复制所有内容,以及所有内部元素的类、ID 和其他属性,如果您直接在其他地方引用内部元素,这可能会破坏您的代码。因此,请密切注意您的选择。拥有一个能够区分克隆和原始克隆的父代,并在选择链中提及它可以保证您的安全。

一个合理的做法(如果你真的需要 id 这么多)是只在你正在复制的外部元素上设置 id ,你可以通过修改函数轻松更改它:d3.select(clone).attr("class", "clone").attr("id", "clone-" + i).

于 2014-12-12T12:16:25.920 回答
3

4 年零 4 个月后……我制作了这个 D3 插件。 https://github.com/jkutianski/d3-clone

于 2018-01-22T20:43:13.267 回答
0

也许回答有点晚了,但是当我开发自己的解决方案时,我发现了这个问题。这就是我创建重复项的方式。

    d3.select("#some_id")
      .append("div")
      .attr("class","some_other_id")
      .each(function(d) {

    for (var i = 1; i < number_duplicate; i++) {
        d3.select("#some_other_id")
          .append("button")
          .attr("type","button")
          .attr("class","btn-btn")
          .attr("id","id_here")
          .append("div")
          .attr("class","label")
          .text("text_here")


    }
});

我创建了一个 div,对其执行 .each() 并将 for 循环放入每个函数中。数字 some_number 会给我预期的重复数量。

变化是可能的,可能一秒钟就可以工作等。也许是穷人的版本-我不是专业人士。我想听听你的反馈。

于 2015-07-07T19:47:16.633 回答