d3js强制定向图 - 单击节点弹出信息框,该信息框从JSON

时间:2017-05-27 16:16:43

标签: javascript d3.js force-layout d3-force-directed

我一直在与Force-Directed Graph合作,但我还是D3js和Javascript的新手。

我希望能够点击页面上的节点和信息框弹出窗口并打印有关该节点的一些信息(来自JSON)。

我的json文件示例:

{"directed": false, "graph": {}, 
"nodes": [{"id": 0, "name":"Ant" , "info":"Small Animal"}, 
{"id": 1 , "name":"Apple" , "info":"Fruit"}, 
{"id": 2 , "name":"Bat" , "info":"Fly Animal"}, 
{"id": 3 , "name":"Boat" , "info":"Vehicle"}, 
{"id": 4 , "name":"Banana" , "info":"Long cute Fruit"}, 
{"id": 5 , "name":"Cat" , "info":"Best Animal"}], 

"links": [{"source": 0, "target": 0 , "weight":1}, {"source": 0, "target": 2, "weight": 0.3}, 
{"source": 0, "target": 5, "weight":0.8}, {"source": 1, "target": 1, "weight":1}, 
{"source": 1, "target": 4, "weight":0.5}, {"source": 2, "target": 2, "weight":1}, 
{"source": 3, "target": 3, "weight":1}, {"source": 4, "target": 4, "weight":1}, 
{"source": 5, "target": 5, "weight":1}], 
"multigraph": false}

所以当我点击一个节点时。它应该弹出如下:

Name: Ant
Info: Small Animal
Connected to: Bat with 0.3 weight , Cat with 0.8 weight

我的图形代码非常类似于上面链接的强制定向示例。

2 个答案:

答案 0 :(得分:3)

这是一个快速实施,它可以构建您的"信息框"使用SVG:

  var tip;
  node.on("click", function(d){
    if (tip) tip.remove();

    tip  = svg.append("g")
      .attr("transform", "translate(" + d.x  + "," + d.y + ")");

    var rect = tip.append("rect")
      .style("fill", "white")
      .style("stroke", "steelblue");

    tip.append("text")
      .text("Name: " + d.name)
      .attr("dy", "1em")
      .attr("x", 5);

    tip.append("text")
      .text("Info: " + d.info)
      .attr("dy", "2em")
      .attr("x", 5);

    var con = graph.links
      .filter(function(d1){
        return d1.source.id === d.id;
      })
      .map(function(d1){
        return d1.target.name + " with weight " + d1.weight;
      })

    tip.append("text")
      .text("Connected to: " + con.join(","))
      .attr("dy", "3em")
      .attr("x", 5);

    var bbox = tip.node().getBBox();
    rect.attr("width", bbox.width + 5)
        .attr("height", bbox.height + 5)
  });

运行代码:



<!DOCTYPE html>
<meta charset="utf-8">
<style>

.links line {
  stroke: #999;
  stroke-opacity: 0.6;
}

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

text {
  font-family: sans-serif;
}

</style>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height");

var color = d3.scaleOrdinal(d3.schemeCategory20);

var simulation = d3.forceSimulation()
    .force("link", d3.forceLink().id(function(d) { return d.id; }))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2));
    
d3.json("https://jsonblob.com/api/15daa79f-7573-11e8-b9d7-1b0997147957", function(error, graph) {
  if (error) throw error;
  
  link = svg.append("g")
      .attr("class", "links")
    .selectAll("line")
    .data(graph.links)
    .enter().append("line")
      .attr("stroke-width", function(d) { return d.weight * 3; });

  var node = svg.append("g")
      .attr("class", "nodes")
    .selectAll("circle")
    .data(graph.nodes)
    .enter().append("circle")
      .attr("r", 5)
      .attr("fill", function(d) { return color(d.group); })
      .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended));

  var tip;
  svg.on("click", function(){
    if (tip) tip.remove();
  });
  node.on("click", function(d){
    d3.event.stopPropagation(); 
  
    if (tip) tip.remove();
    
    tip  = svg.append("g")
      .attr("transform", "translate(" + d.x  + "," + d.y + ")");
      
    var rect = tip.append("rect")
      .style("fill", "white")
      .style("stroke", "steelblue");
    
    tip.append("text")
      .text("Name: " + d.name)
      .attr("dy", "1em")
      .attr("x", 5);
      
    tip.append("text")
      .text("Info: " + d.info)
      .attr("dy", "2em")
      .attr("x", 5);

    var con = graph.links
      .filter(function(d1){
        return d1.source.id === d.id;
      })
      .map(function(d1){
        return d1.target.name + " with weight " + d1.weight;
      })
      
    tip.append("text")
      .text("Connected to: " + con.join(","))
      .attr("dy", "3em")
      .attr("x", 5);
    
    var bbox = tip.node().getBBox();
    rect.attr("width", bbox.width + 5)
        .attr("height", bbox.height + 5)
  });

  simulation
      .nodes(graph.nodes)
      .on("tick", ticked);

  simulation.force("link")
      .links(graph.links);

  function ticked() {
    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; });
  }
});

function dragstarted(d) {
  if (!d3.event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x;
  d.fy = d.y;
}

function dragged(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
}

function dragended(d) {
  if (!d3.event.active) simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;
}

</script>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

您可以使用.on('click', function(d){ });在节点上添加点击事件 例如:

node.on("click", function(d){
      console.log(d);
       // here you can access data of node using d.key 
      alert("You clicked on node " + d.name);
    });