单击D3 Javascript中的节点时如何显示和隐藏链接和节点

时间:2013-11-27 17:32:12

标签: javascript css d3.js force-layout

我正在尝试关注此D3 Javascript链接:> http://bl.ocks.org/mbostock/1093130了解点击事件的工作原理。不幸的是,我无法完全理解整个代码。我现在要做的是点击蓝色节点时,将显示另外两个节点及其链接。当我再次单击同一节点时,两个节点及其链接必须隐藏。如果我点击其他两个节点中的一个节点,则不会发生任何事情。

这是JSON文件:

{
"nodes": [
    {
        "name": "Node1",
        "group": 2
    },
    {
        "name": "Node2",
        "group": 1
    },
    {
        "name": "Node3",
        "group": 1
    }
],
"links": [
    {
        "source": 0,
        "target": 1,
        "value": 2
    },
    {
        "source": 0,
        "target": 2,
        "value": 2
    }
]
}

这是我的代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<style>

.node {
stroke: #fff;
stroke-width: 1.5px;
}

.link {
stroke: #999;
stroke-opacity: .6;
}

</style>
<body>
<p>Are you there!!!</p>
<script type="text/javascript" src="d3/d3.v3.js"></script>
<script>

var width = 960,
height = 500;

d3.json("sample.json", function(error, graph) {

var color = d3.scale.category20();

var force = d3.layout.force()
    .charge(-120)
    .linkDistance(30)
    .size([width, height]);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
force
.nodes(graph.nodes)
.links(graph.links)
.start();

var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });

var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
.call(force.drag);

node.append("title")
.text(function(d) { return d.name; });

force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });

node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
</script>
</body>
</html>

请有人帮我解决这个问题。非常感谢您的协助。

1 个答案:

答案 0 :(得分:10)

您可以按以下步骤单击该节点,分解打开/关闭节点邻居/边缘可见性所需的步骤:

  1. 您需要根据源/目标的名称对链接进行分类,并根据名称给出节点ID。这使得确定哪些节点/链接切换为无关紧要。
  2. 您需要存储每个节点当前是否处于“活动状态”,您可以使用它来确定是否应该隐藏/显示节点的邻居。
  3. 您需要为每个节点添加on("click", function(){ ... })
  4. 我创建了一个演示此方法的JSFiddle。要强调的要点是,首先,我创建一个字典来将节点名称映射到其邻居的名称,这使得确定哪些链接显示/隐藏变得容易:

    // Set up dictionary of neighbors
    var node2neighbors = {};
    for (var i =0; i < json.nodes.length; i++){
        var name = json.nodes[i].name;
        node2neighbors[name] = json.links.filter(function(d){
                return d.source.name == name || d.target.name == name;
            }).map(function(d){
                return d.source.name == name ? d.target.name : d.source.name;
            });
    }
    

    要获取节点n的邻居的名称,我首先过滤包含n的所有链接,然后提取不是n的节点的名称在每个链接中。

    接下来,这是单击节点时执行的逻辑。我正在使用一组节点来跟踪我们想要打开/关闭的节点(OP表示此行为应仅适用于蓝色节点"Node1"):

    var clickableNodes = ["Node1"];
    nodes.filter(function(n){ return clickableNodes.indexOf(n.name) != -1; })
            // Determine if current node's neighbors and their links are visible
            var active   = n.active ? false : true // toggle whether node is active
            , newOpacity = active ? 0 : 1;
    
            // Extract node's name and the names of its neighbors
            var name     = n.name
            , neighbors  = node2neighbors[name];
    
            // Hide the neighbors and their links
            for (var i = 0; i < neighbors.length; i++){
                d3.select("circle#" + neighbors[i]).style("opacity", newOpacity);
                d3.selectAll("line." + neighbors[i]).style("opacity", newOpacity);
            }
            // Update whether or not the node is active
            n.active = active;
        });