D3中绑定数据时,索引代表什么?
When binding data in D3, what does the index represent?
当我在下面的例子中看到传递给步骤3的数据绑定函数的索引值时,我有点惊讶:
1) 创建两个包装 div,每个 div 都绑定一个数据数组
2) 在每个包装器中创建两个 "sub-divs",每个
绑定一个数组
3) 向每个"sub-div"
追加p个元素
由于元素的嵌套方式,我希望在步骤 3 中看到索引 0,1 传递给数据绑定函数。相反,我看到索引 0,1,2,3。
var data = d3.select("#data");
var idx = d3.select("#indexes");
//---- STEP 1
//create two divs with [1, 4] and [7, 10] bound
var dbox = data.selectAll("tbody").data([[1, 4], [7, 10]]);
dbox.enter().append("div").text(function(d,i){return "Group " + i });
dbox.exit().remove();
dbox.style({"clear":"both","padding":"5px","border":"1px solid #dddddd","overflow":"hidden","margin-bottom":"10px"});
//---- STEP 2
//create sub-divs
var tr = dbox.selectAll("div").data(function(d,i){
return d.map(function(d,i,a){ return [d, d+1, d+2]; }); //return an array of arrays [[x,y,z], [a,b,c]]
});
tr.enter().append("div").text(function(d,i){return "Index " + i});
tr.exit().remove();
tr.style({"clear":"both","overflow":"hidden","padding":"2px","border":"1px dotted #dddddd","margin-top":"5px"});
//---- STEP 3
//add text (and record indexes in the "INDEXES" section)
//since the tr selection is grouped--with two "tr" divs per "dbox", I expected to see indexes of 0,1 only, instead I see 0, 1, 2, 3.
var td = tr.selectAll("p").data(function(d,i){
idx.append("p").text(i); //track the indexes
return d;
})
td.enter().append("p");
td.exit().remove();
td.text(function(d,i){return d}).style({});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="data">
</div>
<div id="indexes" style="clear:both;padding-top:20px;">
<p>INDEXES</p>
</div>
我认为这里的混淆是,当使用 .attr() 或 .style() 等方法对选择进行操作时,传递给函数参数的索引表示元素在其父组中的索引。
使用 .data() 方法绑定数据时,传递给函数参数的索引表示父元素的索引。这就是拉尔斯在他的评论中所表达的意思。
我想这是有道理的,因为 D3 选择使用固定的两级层次结构(尽管听起来可能 change in the future)。因此,当您绑定新数据时,选择的层次结构会发生变化。 IE。父元素不再嵌套在选择中。
这是一个说明性的例子:
var L1 = d3.select("div#boxes");
L1.append("p").text("Level 1");
var L2 = L1.selectAll("div").data([1,2]);
L2.enter().append("div");
L2.append("p").text(function(d,i){return "Level 2"})
var L3 = L2.selectAll("div").data(function(d,i){
return [i,i];
});
L3.enter().append("div");
L3.append("p").text(function(d,i){return "Level 3 - Index during data binding: "+d+". Index after appended: "+i+"." })
var L4 = L3.selectAll("div").data(function(d,i){
return [i,i];
});
L4.enter().append("div");
L4.append("p").text(function(d,i){return "Level 4 - Index during data binding: " +d+". Index after appended: "+i+"."})
div{
padding:5px;
margin:5px;
border:1px solid #555555;
}
p{
font-family:Arial, Helvetica, sans-serif;
font-size:13px;
}
#indexes p{
float:left;
margin-left:5px;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="boxes">
</div>
selectAll
只是将选择中的所有元素提升到父节点(忽略组结构)并将提供的选择器依次应用于每个新父节点以在其上形成新组。在此之后,选择中没有对先前父节点的引用,该状态丢失。
tr.selectAll("p")
将 tr
中的所有 div(其中 2x2 = 4 个)提升为父节点,并根据绑定到它们的数据形成输入选择。因此有 4 个组(tr
中的每个 div),每个组有 3 个成员(绑定在父 div 上的数据的第一个维度的长度为 3)。对先前父节点的引用将被丢弃。
if values
in selection.data(
values
)
是函数,那么它的 d
参数是绑定在父组上的数据,而 i
是组索引。
如果values
不是一个函数,那么相同的数据将绑定到每个组。
当我在下面的例子中看到传递给步骤3的数据绑定函数的索引值时,我有点惊讶:
1) 创建两个包装 div,每个 div 都绑定一个数据数组
2) 在每个包装器中创建两个 "sub-divs",每个
绑定一个数组3) 向每个"sub-div"
追加p个元素由于元素的嵌套方式,我希望在步骤 3 中看到索引 0,1 传递给数据绑定函数。相反,我看到索引 0,1,2,3。
var data = d3.select("#data");
var idx = d3.select("#indexes");
//---- STEP 1
//create two divs with [1, 4] and [7, 10] bound
var dbox = data.selectAll("tbody").data([[1, 4], [7, 10]]);
dbox.enter().append("div").text(function(d,i){return "Group " + i });
dbox.exit().remove();
dbox.style({"clear":"both","padding":"5px","border":"1px solid #dddddd","overflow":"hidden","margin-bottom":"10px"});
//---- STEP 2
//create sub-divs
var tr = dbox.selectAll("div").data(function(d,i){
return d.map(function(d,i,a){ return [d, d+1, d+2]; }); //return an array of arrays [[x,y,z], [a,b,c]]
});
tr.enter().append("div").text(function(d,i){return "Index " + i});
tr.exit().remove();
tr.style({"clear":"both","overflow":"hidden","padding":"2px","border":"1px dotted #dddddd","margin-top":"5px"});
//---- STEP 3
//add text (and record indexes in the "INDEXES" section)
//since the tr selection is grouped--with two "tr" divs per "dbox", I expected to see indexes of 0,1 only, instead I see 0, 1, 2, 3.
var td = tr.selectAll("p").data(function(d,i){
idx.append("p").text(i); //track the indexes
return d;
})
td.enter().append("p");
td.exit().remove();
td.text(function(d,i){return d}).style({});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="data">
</div>
<div id="indexes" style="clear:both;padding-top:20px;">
<p>INDEXES</p>
</div>
我认为这里的混淆是,当使用 .attr() 或 .style() 等方法对选择进行操作时,传递给函数参数的索引表示元素在其父组中的索引。
使用 .data() 方法绑定数据时,传递给函数参数的索引表示父元素的索引。这就是拉尔斯在他的评论中所表达的意思。
我想这是有道理的,因为 D3 选择使用固定的两级层次结构(尽管听起来可能 change in the future)。因此,当您绑定新数据时,选择的层次结构会发生变化。 IE。父元素不再嵌套在选择中。
这是一个说明性的例子:
var L1 = d3.select("div#boxes");
L1.append("p").text("Level 1");
var L2 = L1.selectAll("div").data([1,2]);
L2.enter().append("div");
L2.append("p").text(function(d,i){return "Level 2"})
var L3 = L2.selectAll("div").data(function(d,i){
return [i,i];
});
L3.enter().append("div");
L3.append("p").text(function(d,i){return "Level 3 - Index during data binding: "+d+". Index after appended: "+i+"." })
var L4 = L3.selectAll("div").data(function(d,i){
return [i,i];
});
L4.enter().append("div");
L4.append("p").text(function(d,i){return "Level 4 - Index during data binding: " +d+". Index after appended: "+i+"."})
div{
padding:5px;
margin:5px;
border:1px solid #555555;
}
p{
font-family:Arial, Helvetica, sans-serif;
font-size:13px;
}
#indexes p{
float:left;
margin-left:5px;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="boxes">
</div>
selectAll
只是将选择中的所有元素提升到父节点(忽略组结构)并将提供的选择器依次应用于每个新父节点以在其上形成新组。在此之后,选择中没有对先前父节点的引用,该状态丢失。
tr.selectAll("p")
将 tr
中的所有 div(其中 2x2 = 4 个)提升为父节点,并根据绑定到它们的数据形成输入选择。因此有 4 个组(tr
中的每个 div),每个组有 3 个成员(绑定在父 div 上的数据的第一个维度的长度为 3)。对先前父节点的引用将被丢弃。
if values
in selection.data(
values
)
是函数,那么它的 d
参数是绑定在父组上的数据,而 i
是组索引。
如果values
不是一个函数,那么相同的数据将绑定到每个组。