简体   繁体   English

D3强制布局:折叠子节点的子集(不透明度更改)

[英]D3 Force Layout: Collapse Subset of Child Nodes (Opacity Change)

I am using a D3 force layout and trying to collapse child nodes whilst keeping the graph fixed, eg by simply changing them and their links' opacity. 我正在使用D3强制布局,并尝试折叠子节点,同时保持图形固定,例如通过简单地更改它们及其链接的不透明度。 However, I am not trying to just collapse all nodes at once - I actually have an attribute in each node called "group", which can be 1,2 or 3. 但是,我并不是想立即折叠所有节点-实际上,每个节点中都有一个名为“ group”的属性,该属性可以为1,2或3。

When I click on a node, a tooltip appears with 3 buttons for each of these groups - upon clicking on the correct button, I would like the child node of that type to collapse, but all of its children (of all 3 groups) to collapse as well. 当我单击一个节点时,将为每个组显示一个带有3个按钮的工具提示-单击正确的按钮后,我希望该类型的子节点折叠,但其所有3个组的所有子节点都将折叠也会崩溃

Here is the fiddle . 这是小提琴

I have so far tried to create arrays of the node group ids and corresponding link IDs, and then use JQuery to hide those DOM objects but this didn't work: 到目前为止,我已经尝试创建节点组ID和对应的链接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 };
}

Does anyone know how best to do this? 有谁知道如何做到最好?

Thanks. 谢谢。

If its only the opacity you wish to change this is fairly simple. 如果您只是想改变它的不透明度,那将非常简单。 I guess if you hide a nodes children you want to hide their childrens children and so on ? 我想如果您隐藏节点的孩子,您想隐藏其孩子的孩子,依此类推?

First I set a variable d.hiddenNode . 首先,我设置一个变量d.hiddenNode This is so I can toggle the opacity. 这样我就可以切换不透明度。 I set it to false. 我将其设置为false。 And then on click function : 然后点击功能:

.on('click', function(d) {
    console.log(d);
    if(d.hiddenNode){
        hideChildren(d, false);
      d.hiddenNode = false;
    } else {
        hideChildren(d, true);
      d.hiddenNode = true;
    }

  })

Now because you want the childrens children etc to be hidden you need a recursive function like so. 现在,因为您希望隐藏孩子的孩子等,因此需要像这样的递归函数。 One that hides links and nodes ( I have commented to explain) : 隐藏链接和节点的一种(我已评论解释):

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]);
      }
    }
  }
}

Here is the updated fiddle : http://jsfiddle.net/thatOneGuy/3g4fqfa8/2/ 这是更新的小提琴: http : //jsfiddle.net/thatOneGuy/3g4fqfa8/2/

EDIT 编辑

For the pop up i just created a div that contains the 3 groups, 1,2,3 : 对于弹出窗口,我刚刚创建了一个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>

Set this to hidden in CSS : 将此设置为隐藏在CSS中:

.group{
  width: 50px;
  height:50px;
  border : 1px solid black;
}

#groupChoice{
  visibility:hidden;
}

I have changed the logic slightly but this is the updated fiddle with commentary : http://jsfiddle.net/thatOneGuy/3g4fqfa8/3/ 我已略微更改了逻辑,但这是带有注释的更新小提琴: http : //jsfiddle.net/thatOneGuy/3g4fqfa8/3/

Theres some work that needs to be done with the links. 链接需要完成一些工作。 I havent got enough time atm to finish it off, im sorry. 我没有足够的时间来完成它,对不起。 But that should get you started. 但这应该可以帮助您入门。

Basically, when you click a node, pop up comes up, you chose a group to hide, they get hidden. 基本上,当您单击一个节点时,会弹出一个弹出窗口,您选择了一个要隐藏的组,它们被隐藏了。 Hit the same node again, chose a node to show. 再次点击同一节点,选择要显示的节点。 This was done super quick, so there's a lot wrong with it, but the basics are the so it should help :) 这是非常快地完成的,所以有很多问题,但是基本知识应该可以帮助:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM