2013-08-29 110 views
9

的附加重複我想創建,可以採取通用D3選擇和附加的重複它到SVG對象JavaScript函數。D3:選擇

這裏有一個最低工作例如:

<!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

您是否在尋找類似['cloneNode'](http://www.w3schools.com/jsref/met_node_clonenode.asp)? –

+2

你需要一個真正的克隆,還是元素的工作? – nrabinowitz

+0

感謝您的評論。雖然這些都不適用於通用的D3選擇。關於這個(這裏)有更多的對話(https://github.com/mbostock/d3/pull/732#issuecomment-7390693),但我猜想,Mike Bostock提到的selection.clone()方法尚未實現。 – LondonRob

回答

9

這裏的另一種可能性:做事很長的路要走。這可避免使用<use>元素的問題,因爲您無法單獨設置styletransform屬性。

我很驚訝驚人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; 
} 
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> 
+0

嗯..我剛剛測試過這表明這種方法並不理想,因爲你不能將'style'或'transform'屬性應用到''對象。這意味着你被初始對象的真實副本卡住了。回到繪圖板... – LondonRob

+0

嗯 - 我敢肯定你可以覆蓋'use'元素上的'fill','cx','cy'等屬性。我很驚訝你不能使用'transform',但你總是可以用'g'將元素包裝成一個變形和樣式。 – nrabinowitz

+0

這應該是更好的答案:)非常感謝。 –

3

此功能使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包含多個元素,此函數也可以使用。

但要知道,這一切複製,帶班,IDS和所有內部元素,這可能會破壞你的代碼,如果你直接引用內部元素其他地方的其他的屬性。所以請留意你的選擇。擁有一個父母,區分克隆和原始,並在選擇鏈中提及它會讓你安全。

一個合理的事情要做(如果你真的需要這麼多ID)就是讓id只設置在你正在複製的外部元素上,在這裏你可以通過修改函數d3.select(clone).attr("class", "clone").attr("id", "clone-" + i)輕鬆改變它。

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將給我預期數量的重複。

變化將是可能的,可能是第二個用於將工作等等。也許一個窮人的版本 - 我不是一個職業。我想聽聽您的反饋。