我有一个巨大的层次结构作为输入数据。我使用(仅) d3.js 库管理可视化。在另一个视图旁边,我显示了一个数据表。 我需要根据事件修改行。
在下面的示例中,我想着色与所点击节点的子树相对应的行。
http://jsfiddle.net/dqpwgvmk/2/
var dataIN =
{"name":"R","value":0,"children":[
{"name":"F","value":42,"children":[]},
{"name":"K","value":0,"children":[
{"name":"H","value":10,"children":[
{"name":"E","value":6,"children":[]},
{"name":"D","value":4,"children":[]}
]},
{"name":"J","value":0,"children":[
{"name":"I","value":0,"children":[
{"name":"C","value":3,"children":[]},
{"name":"G","value":5,"children":[
{"name":"B","value":2,"children":[]},
{"name":"A","value":8,"children":[]}
]}
]}
]}
]}
]};
var nodes = d3.layout.treemap().nodes(dataIN);
/*create table*/
d3.select("body").append("table")
.selectAll("tr").data(nodes).enter().append("tr")
.attr("class",function(d){return "n"+d.name+"-"+d.value;})
.attr("title",function(d){return d.name;})
.selectAll("td").data(["name","value","button"]).enter().append("td")
.attr("class",function(d){return d;});
//fill name
d3.selectAll(".name").data(nodes)
.text(function(d){return d.name;});
//fill value
d3.selectAll(".value").data(nodes)
.text(function(d){return d.value;});
//fill button
d3.selectAll(".button").data(nodes)
.append("button").text("subtree")
.on("click",function(d){return color(d);});
/*getsubtree*/
function getSubtree(n,ns) {
//get a list of all nodes in subtree of n, n included
if(n.children) {
n.children.forEach(function(c){
ns = getSubtree(c,ns);
});
}
ns.push(n);
return ns;
}
/*color*/
function color(n) {
//reset
d3.selectAll("tr").style("background-color","");
//set
var sub = getSubtree(n,[]);
console.log("sub",sub);
sub.forEach(function(d){
d3.select(".n"+d.name+"-"+d.value)
.style("background-color","#800080");
});
}
我没有找到一个“短路”来用d3.js选择一个节点的所有后代。如你所见,我的DOM元素是“tr”,所以是平面列表。
为了解决这个问题,我的方法是“从数据中过滤”节点(带有层次结构)。 然后“选择对应的DOM元素”。
以下示例有效。我通过递归我的数据树中的walk来列出子树的节点。然后选择每个相应的DOM元素。
我的问题是在数据量很大的情况下,d3.select()
循环中的sub.forEach()
需要多次。
调查d3.select().filter()
和d3.select().data(values,Key())
,但我找不到根据节点列表过滤DOM元素的解决方案。
d3有办法吗?
谢谢Maxime HEBRARD