如何显示点击目标的源节点?

How to display source nodes of a clicked target?

如何使用 D3 在强制有向图中显示单击的目标节点的源节点名称?

下面的片段来自一些 example code for directed graphs by Mike Bostock。我该如何修改这个基本代码,以便当在图表上单击一个节点时,该节点的目标值显示在屏幕上(在这种情况下,我想显示 name 属性)?

例如 "nodes" 中的第 0 个元素是:

"nodes":[
  {"name":"Myriel","group":1},
  ...
]

而在 "links" 中,目标定义如下:

"links":[
  {"source":1,"target":0,"value":1},        // Napoleon
  {"source":2,"target":0,"value":8},        // Mlle.Baptistine
  {"source":3,"target":0,"value":10},       // Mme.Magloire
  {"source":3,"target":2,"value":6},
  {"source":4,"target":0,"value":1},        // CountessdeLo
  {"source":5,"target":0,"value":1},        // Geborand
  {"source":6,"target":0,"value":1},        // Champtercier
  {"source":7,"target":0,"value":1},        // Cravatte
  {"source":8,"target":0,"value":2},        // Count
  {"source":9,"target":0,"value":1},        // OldMan
  ...
  {"source":11,"target":0,"value":5},       // Valjean
  ...
]

然后点击节点Myriel会显示:

Napoleon,Mlle.Baptistine,Mme.Magloire,CountessdeLo,Geborand,Champtercier,Cravatte,Count,OldMan,Valjean

Myriel 位于图中的此处:

下面是JavaScript代码:

var width = 960,
    height = 500;
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);
var color = d3.scale.category20();
var force = d3.layout.force()
    .charge(-120)
    .linkDistance(30)
    .size([width, height]);
d3.json("https://gist.githubusercontent.com/mbostock/4062045/raw/9653f99dbf6050b0f28ceafbba659ac5e1e66fbd/miserables.json", function(error, graph) {
  if (error) throw error;
  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)
      .on("click",function(d){ 
        var targets = graph.links.filter(function(i){
          return i.target.name == d.name
        });
        tip.show( targets.map(function(i){ return i.source.name;}) );

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

var width = 960,
    height = 500;
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);
var color = d3.scale.category20();
var force = d3.layout.force()
    .charge(-120)
    .linkDistance(30)
    .size([width, height]);
d3.json("https://gist.githubusercontent.com/mbostock/4062045/raw/9653f99dbf6050b0f28ceafbba659ac5e1e66fbd/miserables.json", function(error, graph) {
  if (error) throw error;
  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)
      .on("click",function(d){ 
        var targets = graph.links.filter(function(i){
          return i.target.name == d.name
        });
        tip.show( targets.map(function(i){ return i.source.name;}) );
        
      });
  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; });
  });
});
.node {
  stroke: #fff;
  stroke-width: 1.5px;
}
.link {
  stroke: #999;
  stroke-opacity: .6;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.0/d3.min.js"></script>

在每个节点上添加一个点击事件,然后在里面我们可以通过过滤graph.links数组得到所有的targets,这样我们就只有target.name相同的元素作为单击的节点名称 d.name。一旦我们有了,您就可以使用 .map() 到 return 带有 .source.name 的数组来给出 targets:

中那些项目的 name
  .on("click",function(d) { 
    var targets = graph.links.filter(function(i){
      return i.target.name==d.name;
    });
    tip.show( targets.map(function(i){ return i.source.name; }) );
  });

var tip = d3.tip().attr('class', 'd3-tip').html(function(d) { return d; });

var width = 960,
    height = 500;
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

svg.call(tip);

var color = d3.scale.category20();
var force = d3.layout.force()
    .charge(-120)
    .linkDistance(30)
    .size([width, height]);
d3.json("https://gist.githubusercontent.com/mbostock/4062045/raw/9653f99dbf6050b0f28ceafbba659ac5e1e66fbd/miserables.json", function(error, graph) {
  if (error) throw error;
  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)
      .on("click",function(d){ 
        var targets = graph.links.filter(function(i){
          return i.target.name == d.name
        });
        tip.show( targets.map(function(i){ return i.source.name;}) );
        
      });
  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; });
  });
});
.node {
  stroke: #fff;
  stroke-width: 1.5px;
}
.link {
  stroke: #999;
  stroke-opacity: .6;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.6.7/d3-tip.min.js"></script>

现在为了轻松显示这些值,可以使用 d3-tip 库。这将针对图形进行初始化,如下所示:

var tip = d3.tip().attr('class', 'd3-tip').html(function(d) { return d; });
...
var svg = ..
svg.call(tip);

最后,第一个代码片段中的 tip.show(...) 函数将在图表上显示这些项目。