D3 Force Layout:折叠子节点的子集(不透明度变化)
D3 Force Layout: Collapse Subset of Child Nodes (Opacity Change)
我正在使用 D3 强制布局并尝试折叠子节点同时保持图形固定,例如只需更改它们及其 link 的不透明度即可。但是,我并不想一次折叠所有节点 - 我实际上在每个节点中都有一个名为 "group" 的属性,它可以是 1,2 或 3。
当我单击一个节点时,会出现一个工具提示,每个组都有 3 个按钮 - 单击正确的按钮后,我希望折叠该类型的子节点,但它的所有子节点(所有 3 组)也会崩溃。
这里是fiddle。
到目前为止,我已经尝试创建节点组 ID 和相应的 link ID 的数组,然后使用 JQuery 隐藏那些 DOM 对象,但这没有用:
function collapseNodes(node, collapseType, isCollapsed) {
var collapseData = minimise(node, collapseType);
var cNodes = collapseData.nodes,
cLinks = collapseData.links;
console.log(collapseData);
var newClass = isCollapsed ? "uncollapsed" : "collapsed";
cNodes.forEach(function(n) {
d3.select(n).style("opacity", 0);
});
cLinks.forEach(function(l) {
d3.select(l).style("opacity", 0);
});
}
function minimise(node, assetMinType = "") {
// Function to minimise a node
var minNodes = [];
var minLinks = [];
if (node.group == 'asset') {
node.children.forEach(function(child) {
if (child.group == assetMinType)
minimiseRec(child, node.id);
});
}
else {
minimiseRec(node, "");
// We want to keep the top node and link
minNodes.shift();
minLinks.shift();
}
function minimiseRec(node, parentID) {
minNodes.push("#" + node.id);
minLinks.push("#parent_" + parentID + "_child_" + node.address);
node.children.map(function(child) {
minimise(child, node.id);
});
}
return { nodes: minNodes, links: minLinks };
}
有谁知道如何最好地做到这一点?
谢谢。
如果您只想更改不透明度,这很简单。我想如果你隐藏一个节点 children 你想隐藏它们的 childrens children 等等?
首先我设置了一个变量d.hiddenNode
。这样我就可以切换不透明度。我把它设置为假。然后点击功能:
.on('click', function(d) {
console.log(d);
if(d.hiddenNode){
hideChildren(d, false);
d.hiddenNode = false;
} else {
hideChildren(d, true);
d.hiddenNode = true;
}
})
现在因为你想隐藏 childrens children 等你需要一个像这样的递归函数。隐藏链接和节点的一个(我已经评论解释):
function hideChildren(node, hide) {
for (var i = 0; i < node.children.length; i++) {
recurseChildren(node.children[i]); //loop through children to hide
}
function recurseChildren(node) {
nodeEnter.each(function(d) { //go through all nodes to check for children
if (d.index == node.index) { //if child is found
d3.select(this).style('opacity', function(){
return hide ? 0 : 1; //toggle opacity depending on d.hiddenNode value
}) //.remove();
}
})
link.each(function(d) { //same with links
if (d.source.index == node.index || d.target.index == node.index ) { //if source or target are hidden hide the link
d3.select(this).style('opacity', function(){
return hide ? 0 : 1;
}) //.remove();
}
})
if (node.children) { //if this node has children, call again but with their children
for (var i = 0; i < node.children.length; i++) {
recurseChildren(node.children[i]);
}
}
}
}
这是更新后的 fiddle:http://jsfiddle.net/thatOneGuy/3g4fqfa8/2/
编辑
对于弹出窗口,我刚刚创建了一个 div,其中包含 3 个组,1、2、3:
<div id='groupChoice'>
<div id='group1' class = 'group' onclick='hideGroup(1)'>1</div>
<div id='group2' class = 'group' onclick='hideGroup(2)'>2</div>
<div id='group3' class = 'group' onclick='hideGroup(3)'>3</div>
</div>
将其设置为隐藏在 CSS 中:
.group{
width: 50px;
height:50px;
border : 1px solid black;
}
#groupChoice{
visibility:hidden;
}
我稍微改变了逻辑,但这是更新后的 fiddle 评论:http://jsfiddle.net/thatOneGuy/3g4fqfa8/3/
有些链接需要完成。我没有足够的时间来完成它,对不起。但这应该让你开始。
基本上,当您单击一个节点时,会弹出一个窗口,您选择要隐藏的组,它们就会被隐藏。再次点击同一个节点,选择一个节点显示。这是完成得非常快,所以它有很多错误,但基础是所以它应该有所帮助:)
我正在使用 D3 强制布局并尝试折叠子节点同时保持图形固定,例如只需更改它们及其 link 的不透明度即可。但是,我并不想一次折叠所有节点 - 我实际上在每个节点中都有一个名为 "group" 的属性,它可以是 1,2 或 3。
当我单击一个节点时,会出现一个工具提示,每个组都有 3 个按钮 - 单击正确的按钮后,我希望折叠该类型的子节点,但它的所有子节点(所有 3 组)也会崩溃。
这里是fiddle。
到目前为止,我已经尝试创建节点组 ID 和相应的 link ID 的数组,然后使用 JQuery 隐藏那些 DOM 对象,但这没有用:
function collapseNodes(node, collapseType, isCollapsed) {
var collapseData = minimise(node, collapseType);
var cNodes = collapseData.nodes,
cLinks = collapseData.links;
console.log(collapseData);
var newClass = isCollapsed ? "uncollapsed" : "collapsed";
cNodes.forEach(function(n) {
d3.select(n).style("opacity", 0);
});
cLinks.forEach(function(l) {
d3.select(l).style("opacity", 0);
});
}
function minimise(node, assetMinType = "") {
// Function to minimise a node
var minNodes = [];
var minLinks = [];
if (node.group == 'asset') {
node.children.forEach(function(child) {
if (child.group == assetMinType)
minimiseRec(child, node.id);
});
}
else {
minimiseRec(node, "");
// We want to keep the top node and link
minNodes.shift();
minLinks.shift();
}
function minimiseRec(node, parentID) {
minNodes.push("#" + node.id);
minLinks.push("#parent_" + parentID + "_child_" + node.address);
node.children.map(function(child) {
minimise(child, node.id);
});
}
return { nodes: minNodes, links: minLinks };
}
有谁知道如何最好地做到这一点?
谢谢。
如果您只想更改不透明度,这很简单。我想如果你隐藏一个节点 children 你想隐藏它们的 childrens children 等等?
首先我设置了一个变量d.hiddenNode
。这样我就可以切换不透明度。我把它设置为假。然后点击功能:
.on('click', function(d) {
console.log(d);
if(d.hiddenNode){
hideChildren(d, false);
d.hiddenNode = false;
} else {
hideChildren(d, true);
d.hiddenNode = true;
}
})
现在因为你想隐藏 childrens children 等你需要一个像这样的递归函数。隐藏链接和节点的一个(我已经评论解释):
function hideChildren(node, hide) {
for (var i = 0; i < node.children.length; i++) {
recurseChildren(node.children[i]); //loop through children to hide
}
function recurseChildren(node) {
nodeEnter.each(function(d) { //go through all nodes to check for children
if (d.index == node.index) { //if child is found
d3.select(this).style('opacity', function(){
return hide ? 0 : 1; //toggle opacity depending on d.hiddenNode value
}) //.remove();
}
})
link.each(function(d) { //same with links
if (d.source.index == node.index || d.target.index == node.index ) { //if source or target are hidden hide the link
d3.select(this).style('opacity', function(){
return hide ? 0 : 1;
}) //.remove();
}
})
if (node.children) { //if this node has children, call again but with their children
for (var i = 0; i < node.children.length; i++) {
recurseChildren(node.children[i]);
}
}
}
}
这是更新后的 fiddle:http://jsfiddle.net/thatOneGuy/3g4fqfa8/2/
编辑
对于弹出窗口,我刚刚创建了一个 div,其中包含 3 个组,1、2、3:
<div id='groupChoice'>
<div id='group1' class = 'group' onclick='hideGroup(1)'>1</div>
<div id='group2' class = 'group' onclick='hideGroup(2)'>2</div>
<div id='group3' class = 'group' onclick='hideGroup(3)'>3</div>
</div>
将其设置为隐藏在 CSS 中:
.group{
width: 50px;
height:50px;
border : 1px solid black;
}
#groupChoice{
visibility:hidden;
}
我稍微改变了逻辑,但这是更新后的 fiddle 评论:http://jsfiddle.net/thatOneGuy/3g4fqfa8/3/
有些链接需要完成。我没有足够的时间来完成它,对不起。但这应该让你开始。
基本上,当您单击一个节点时,会弹出一个窗口,您选择要隐藏的组,它们就会被隐藏。再次点击同一个节点,选择一个节点显示。这是完成得非常快,所以它有很多错误,但基础是所以它应该有所帮助:)