我想创建一个javascript函数,它可以选择一般的D3,并将它的副本附加到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>
迈克博斯托克说,这是不可能的here,但那是一段时间了。
有没有人对如何实现这一点有任何新想法?请记住,在函数clone_selection
中,我们不知道x中的svg元素是什么。
答案 0 :(得分:11)
这是另一种可能性:做很多事情。这解决了使用<use>
元素的问题,您无法单独设置style
或transform
属性。
令我惊讶的是,令人惊讶的d3js
库本身没有这样的功能,但这是我的黑客:
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;
}
答案 1 :(得分:4)
感谢@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>
答案 2 :(得分:4)
此函数对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');
}
请参阅演示here。
如果选择toCopy包含多个元素,则此功能也可用。
但请注意,它会复制所有内容,以及所有内部元素的类,ID和其他属性,这可能会破坏您的代码,如果您直接在其他地方引用内部元素。所以请留意你的选择。拥有一个将克隆与原始区分开来的父母,并在选择链中提及它将确保您的安全。
一个合理的事情(如果你真的需要id那么多)就是只在你复制的外部元素上设置id,你可以通过修改函数轻松地改变它:d3.select(clone).attr("class", "clone").attr("id", "clone-" + i)
答案 3 :(得分:2)
4年零4个月后......我制作了这个D3插件。 https://github.com/jkutianski/d3-clone
答案 4 :(得分: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数字将给我预期的重复数量。
变化是可能的,可能是工作的第二个等等。也许是一个穷人的版本 - 我不是专业人士。我想听听您的反馈。