D3.js D3树:如何在检查父节点时递归检查和禁用子节点

D3.js D3树:如何在检查父节点时递归检查和禁用子节点,d3.js,D3.js,我正在使用d3开发一个角度应用程序。我的代码如下 var treeData=[{ “名称”:“MD”, “儿童”:[{ “姓名”:“专业人士”, “儿童”:[{ “名称”:“第三个A”, “儿童”:[{ “名称”:“第四个A”, “儿童”:[{ “名称”:“第五个A” }, { “名称”:“第五个B” }, { “名称”:“第五个C” }, { “名称”:“第五个D” }] }, { “名称”:“第四个B” }, { “名称”:“第四个C” }, { “名称”:“第四个D” }] }, { “名

我正在使用d3开发一个角度应用程序。我的代码如下

var treeData=[{
“名称”:“MD”,
“儿童”:[{
“姓名”:“专业人士”,
“儿童”:[{
“名称”:“第三个A”,
“儿童”:[{
“名称”:“第四个A”,
“儿童”:[{
“名称”:“第五个A”
}, {
“名称”:“第五个B”
}, {
“名称”:“第五个C”
}, {
“名称”:“第五个D”
}]
}, {
“名称”:“第四个B”
}, {
“名称”:“第四个C”
}, {
“名称”:“第四个D”
}]
}, {
“名称”:“第三个B”
}]
}, {
“姓名”:“领导”,
“儿童”:[{
“名称”:“第三个C”
}, {
“名称”:“第三个D”
}]
}, {
“姓名”:“倡导者”,
“儿童”:[{
“名称”:“第三个E”
}, {
“名称”:“第三个F”
}]
}, {
“姓名”:“临床医生”,
“儿童”:[{
“名称”:“第三个G”
}, {
“名称”:“第三个H”
}, ]
}, ]
}];
var colorscale=d3.scale.ordinal()
.domain([“医学博士”、“专业人士”、“领导者”、“倡导者”、“临床医生”])
.范围([“#6695c8”、“#cd3838”、“#d48440”、“#a8ba5f”、“#63b7c0”);
//*************生成树形图*****************
var保证金={
前20名,
右:120,,
底数:20,
左:120
},
宽度=1200-margin.right-margin.left,
高度=650-边距.顶部-边距.底部;
var i=0,
持续时间=750,
根;
var tree=d3.layout.tree()
.尺寸([高度、宽度]);
var diagonal=d3.svg.diagonal()
.投影(功能(d){
返回[d.y,d.x];
});
var svg=d3.选择(“正文”).追加(“svg”)
.attr(“宽度”,宽度+边距。右侧+边距。左侧)
.attr(“高度”,高度+边距。顶部+边距。底部)
.附加(“g”)
.attr(“转换”、“平移”(+margin.left+)、“+margin.top+”);
根=树数据[0];
root.x0=高度/2;
root.y0=0;
更新(根);
d3.选择(self.frameElement).style(“高度”,“500px”);
//在第二层之后崩溃
根。子。forEach(塌陷);
更新(根);
//折叠节点及其所有子节点
功能崩溃(d){
如果(d.儿童){
d、 _children=d.children
d、 _儿童。forEach(崩溃)
d、 children=null
}
}
函数更新(源){
console.log('UPDATE')
//计算新的树布局。
var nodes=tree.nodes(root).reverse(),
链接=树。链接(节点);
//为固定深度进行规格化。
nodes.forEach(函数(d){
d、 y=d.深度*200;
});
//更新节点…
var node=svg.selectAll(“g.node”)
.数据(节点、功能(d){
返回d.id | |(d.id=++i);
});
//在父节点的上一个位置输入任何新节点。
var nodeEnter=node.enter().append(“g”)
.attr(“类”、“节点”)
.attr(“转换”,函数(d){
返回“translate”(“+source.y0+”,“+source.x0+”);
})
。开启(“点击”,点击);
nodeEnter.append(“圆”)
.attr(“r”,1e-6)
.样式(“填充”,功能(d){
返回d.“儿童?”#C0C0C0:“#fff”;
});
nodeEnter.append(“文本”)
.attr(“x”,函数(d){
返回d.children | | d.| U儿童?-13:13;
})
.attr(“dy”,“.35em”)
.attr(“文本锚定”,函数(d){
返回d.children | d.| u children?“结束”:“开始”;
})
.文本(功能(d){
返回d.name;
})
.样式(“填充不透明度”,1e-6);
nodeEnter.append('foreignObject').attr('width','20'))
.attr(“x”,10)
.attr(“y”,1)
.attr('height','20')。append('xhtml:input'))
.attr('type','checkbox')
.attr(“id”,d=>`checkbox-${d.id}`)
//.attr(“填充”、“无”)
//.style(“不透明度”、“1”)
//复选框的单击功能
.on(“单击”,d=>{
如果(d.儿童){
d、 children.forEach(child=>{
const cb=d3.select(`checkbox-${child.id}`);
//log('CB:',CB.node());
cb.node().checked=d3.event.target.checked;
cb.attr('disabled',d3.event.target.checked?true:null);
})
}
否则{
如果(d3.事件.目标.选中){
d、 parent.children.forEach(child=>{
console.log('CID:',child.id,d.id);
if(child.id!==d.id){
const cb=d3.select(`checkbox-${child.id}`);
console.log('CB:',CB.node())
cb.node().checked=false;
} 
});
}
}
d3.event.stopPropagation();
//控制台日志(d);
//日志(d3.event.target.checked);
})
//将节点转换到其新位置。
var nodeUpdate=node.transition()
.持续时间(持续时间)
.attr(“转换”,函数(d){
返回“translate”(“+d.y+”,“+d.x+”);
});
节点更新。选择(“圆圈”)
.attr(“r”,10)
.attr(“填充不透明度”,“0.7”)
.attr(“笔划不透明度”,“1”)
.样式(“填充”,功能(d){
返回值(类型为d.。(U children!='undefined')?(色标(findParent(d))):'#FFF';
})
.样式(“笔划”,功能(d){
返回色标(findParent(d));
});
nodeUpdate.select(“文本”)
.样式(“填充不透明度”,1);
//将退出节点转换到父节点的新位置。
var nodeExit=node.exit().transition()
.持续时间(持续时间)
.attr(“转换”,函数(d){
返回“translate”(“+source.y+”,“+source.x+”);
})
.remove();
nodeExit.select(“圆”)
.attr(“r”,1e-6);
nodeExit.select(“文本”)
.样式(“填充不透明度”,1e-6);
//更新链接…
var link=svg.selectAll(“path.link”)
.数据(链接、功能(d){
返回d.target.id;
});
//在父对象的上一个位置输入任何新链接。
link.enter()插入(“路径”,“g”)
.attr(“类”、“链接”)
.attr(“笔划宽度”,函数(d){
返回1;
})
.attr(“d”,函数(d){