2017-03-17 81 views
1

是d3(和javascript)的新手我一直在试图将强制布局和背景图像结合起来。目标是为图像中的每个人创建一个节点,并使用svg链接将该人的社交关系显示给图像中的所有其他人。我使用了一个Les Miserables强制布局的子集来测试这个。 我在部队布局中创建了几个“固定”职位(如Valjean,珂赛特,沙威,Eponine)。鼠标移动到显示/隐藏强制布局链接

See this image example of Les Miserables

关键问题是相互连接的大量的,这看起来很不错,但使得它没用呈现。 我想添加一个鼠标悬停功能,只显示在鼠标位置的人/节点的链接。

我看了一个可选的机制:Mike Bostock的airport force layout有这个鼠标悬停功能,但对我来说很不幸,因为我不需要所有这些地理脚本。

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

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

 
.nodes circle { 
 
    stroke: #fff; 
 
    stroke-width: 1.5px; 
 
} 
 
* {font-family: Arial, sans-serif;font-size:12px;color:#fff;} 
 
</style> 
 
<svg width="1400" height="900" style="background:url('miserables_op.jpg');background-size:contain;background-repeat:no-repeat"></svg> 
 
<script src="https://d3js.org/d3.v4.min.js"></script> 
 
<script> 
 
var graph = { 
 
\t nodes:[ 
 
    {"id": "Myriel", "group": 1}, 
 
    {"id": "Napoleon", "group": 1}, 
 
    {"id": "Mlle.Baptistine", "group": 1}, 
 
    {"id": "Mme.Magloire", "group": 1}, 
 
    {"id": "CountessdeLo", "group": 1}, 
 
    {"id": "Geborand", "group": 1}, 
 
    {"id": "Champtercier", "group": 1}, 
 
    {"id": "Cravatte", "group": 1}, 
 
    {"id": "Count", "group": 1}, 
 
    {"id": "OldMan", "group": 1}, 
 
    {"id": "Labarre", "group": 2}, 
 
    {"id": "Valjean", "fx":1300, "fy":570, "group": 2}, 
 
    {"id": "Marguerite", "group": 3}, 
 
    {"id": "Mme.deR", "group": 2}, 
 
    {"id": "Isabeau", "group": 2}, 
 
    {"id": "Gervais", "group": 2}, 
 
    {"id": "Tholomyes", "group": 3}, 
 
    {"id": "Listolier", "group": 3}, 
 
    {"id": "Fameuil", "group": 3}, 
 
    {"id": "Blacheville", "group": 3}, 
 
    {"id": "Favourite", "group": 3}, 
 
    {"id": "Dahlia", "group": 3}, 
 
    {"id": "Zephine", "group": 3}, 
 
    {"id": "Fantine", "group": 3}, 
 
    {"id": "Mme.Thenardier", "group": 4}, 
 
    {"id": "Thenardier", "group": 4}, 
 
    {"id": "Cosette", "fx":1245, "fy":625, "group": 5}, 
 
    {"id": "Javert", "fx":110, "fy":450,"group": 4}, 
 
    {"id": "Fauchelevent", "group": 0}, 
 
    {"id": "Bamatabois", "group": 2}, 
 
    {"id": "Perpetue", "group": 3}, 
 
    {"id": "Simplice", "group": 2}, 
 
    {"id": "Scaufflaire", "group": 2}, 
 
    {"id": "Woman1", "group": 2}, 
 
    {"id": "Judge", "group": 2}, 
 
    {"id": "Champmathieu", "group": 2}, 
 
    {"id": "Brevet", "group": 2}, 
 
    {"id": "Chenildieu", "group": 2}, 
 
    {"id": "Cochepaille", "group": 2}, 
 
    {"id": "Pontmercy", "group": 4}, 
 
    {"id": "Boulatruelle", "group": 6}, 
 
    {"id": "Eponine", "fx":535, "fy":535, "group": 4}, 
 
    {"id": "Anzelma", "group": 4}, 
 
    {"id": "Woman2", "group": 5}, 
 
    {"id": "MotherInnocent", "group": 0}, 
 
    {"id": "Gribier", "group": 0}, 
 
    {"id": "Jondrette", "group": 7}, 
 
    {"id": "Mme.Burgon", "group": 7}, 
 
    {"id": "Gavroche", "group": 8}, 
 
    {"id": "Gillenormand", "group": 5}, 
 
    {"id": "Magnon", "group": 5}, 
 
    {"id": "Mlle.Gillenormand", "group": 5}, 
 
    {"id": "Mme.Pontmercy", "group": 5}, 
 
    {"id": "Mlle.Vaubois", "group": 5}, 
 
    {"id": "Lt.Gillenormand", "group": 5}, 
 
    {"id": "Marius", "group": 8} 
 
\t ], 
 
    links: [ 
 
    {"source": "Napoleon", "target": "Myriel", "value": 1}, 
 
    {"source": "Mlle.Baptistine", "target": "Myriel", "value": 8}, 
 
    {"source": "Mme.Magloire", "target": "Myriel", "value": 10}, 
 
    {"source": "Mme.Magloire", "target": "Mlle.Baptistine", "value": 6}, 
 
    {"source": "CountessdeLo", "target": "Myriel", "value": 1}, 
 
    {"source": "Geborand", "target": "Myriel", "value": 1}, 
 
    {"source": "Champtercier", "target": "Myriel", "value": 1}, 
 
    {"source": "Cravatte", "target": "Myriel", "value": 1}, 
 
    {"source": "Count", "target": "Myriel", "value": 2}, 
 
    {"source": "OldMan", "target": "Myriel", "value": 1}, 
 
    {"source": "Valjean", "target": "Labarre", "value": 1}, 
 
    {"source": "Valjean", "target": "Mme.Magloire", "value": 3}, 
 
    {"source": "Valjean", "target": "Mlle.Baptistine", "value": 3}, 
 
    {"source": "Valjean", "target": "Myriel", "value": 5}, 
 
    {"source": "Marguerite", "target": "Valjean", "value": 1}, 
 
    {"source": "Mme.deR", "target": "Valjean", "value": 1}, 
 
    {"source": "Isabeau", "target": "Valjean", "value": 1}, 
 
    {"source": "Gervais", "target": "Valjean", "value": 1}, 
 
    {"source": "Listolier", "target": "Tholomyes", "value": 4}, 
 
    {"source": "Fameuil", "target": "Tholomyes", "value": 4}, 
 
    {"source": "Fameuil", "target": "Listolier", "value": 4}, 
 
    {"source": "Blacheville", "target": "Tholomyes", "value": 4}, 
 
    {"source": "Blacheville", "target": "Listolier", "value": 4}, 
 
    {"source": "Blacheville", "target": "Fameuil", "value": 4}, 
 
    {"source": "Favourite", "target": "Tholomyes", "value": 3}, 
 
    {"source": "Favourite", "target": "Listolier", "value": 3}, 
 
    {"source": "Favourite", "target": "Fameuil", "value": 3}, 
 
    {"source": "Favourite", "target": "Blacheville", "value": 4}, 
 
    {"source": "Dahlia", "target": "Tholomyes", "value": 3}, 
 
    {"source": "Dahlia", "target": "Listolier", "value": 3}, 
 
    {"source": "Dahlia", "target": "Fameuil", "value": 3}, 
 
    {"source": "Dahlia", "target": "Blacheville", "value": 3}, 
 
    {"source": "Dahlia", "target": "Favourite", "value": 5}, 
 
    {"source": "Zephine", "target": "Tholomyes", "value": 3}, 
 
    {"source": "Zephine", "target": "Listolier", "value": 3}, 
 
    {"source": "Zephine", "target": "Fameuil", "value": 3}, 
 
    {"source": "Zephine", "target": "Blacheville", "value": 3}, 
 
    {"source": "Zephine", "target": "Favourite", "value": 4}, 
 
    {"source": "Zephine", "target": "Dahlia", "value": 4}, 
 
    {"source": "Fantine", "target": "Tholomyes", "value": 3}, 
 
    {"source": "Fantine", "target": "Listolier", "value": 3}, 
 
    {"source": "Fantine", "target": "Fameuil", "value": 3}, 
 
    {"source": "Fantine", "target": "Blacheville", "value": 3}, 
 
    {"source": "Fantine", "target": "Favourite", "value": 4}, 
 
    {"source": "Fantine", "target": "Dahlia", "value": 4}, 
 
    {"source": "Fantine", "target": "Zephine", "value": 4}, 
 
    {"source": "Fantine", "target": "Marguerite", "value": 2}, 
 
    {"source": "Fantine", "target": "Valjean", "value": 9}, 
 
    {"source": "Mme.Thenardier", "target": "Fantine", "value": 2}, 
 
    {"source": "Mme.Thenardier", "target": "Valjean", "value": 7}, 
 
    {"source": "Thenardier", "target": "Mme.Thenardier", "value": 13}, 
 
    {"source": "Thenardier", "target": "Fantine", "value": 1}, 
 
    {"source": "Thenardier", "target": "Valjean", "value": 12}, 
 
    {"source": "Cosette", "target": "Mme.Thenardier", "value": 4}, 
 
    {"source": "Cosette", "target": "Valjean", "value": 31}, 
 
    {"source": "Cosette", "target": "Tholomyes", "value": 1}, 
 
    {"source": "Cosette", "target": "Thenardier", "value": 1}, 
 
    {"source": "Javert", "target": "Valjean", "value": 17}, 
 
    {"source": "Javert", "target": "Fantine", "value": 5}, 
 
    {"source": "Javert", "target": "Thenardier", "value": 5}, 
 
    {"source": "Javert", "target": "Mme.Thenardier", "value": 1}, 
 
    {"source": "Javert", "target": "Cosette", "value": 1}, 
 
    {"source": "Fauchelevent", "target": "Valjean", "value": 8}, 
 
    {"source": "Fauchelevent", "target": "Javert", "value": 1}, 
 
    {"source": "Bamatabois", "target": "Fantine", "value": 1}, 
 
    {"source": "Bamatabois", "target": "Javert", "value": 1}, 
 
    {"source": "Bamatabois", "target": "Valjean", "value": 2}, 
 
    {"source": "Perpetue", "target": "Fantine", "value": 1}, 
 
    {"source": "Simplice", "target": "Perpetue", "value": 2}, 
 
    {"source": "Simplice", "target": "Valjean", "value": 3}, 
 
    {"source": "Simplice", "target": "Fantine", "value": 2}, 
 
    {"source": "Simplice", "target": "Javert", "value": 1}, 
 
    {"source": "Scaufflaire", "target": "Valjean", "value": 1}, 
 
    {"source": "Woman1", "target": "Valjean", "value": 2}, 
 
    {"source": "Woman1", "target": "Javert", "value": 1}, 
 
    {"source": "Judge", "target": "Valjean", "value": 3}, 
 
    {"source": "Judge", "target": "Bamatabois", "value": 2}, 
 
    {"source": "Champmathieu", "target": "Valjean", "value": 3}, 
 
    {"source": "Champmathieu", "target": "Judge", "value": 3}, 
 
    {"source": "Champmathieu", "target": "Bamatabois", "value": 2}, 
 
    {"source": "Brevet", "target": "Judge", "value": 2}, 
 
    {"source": "Brevet", "target": "Champmathieu", "value": 2}, 
 
    {"source": "Brevet", "target": "Valjean", "value": 2}, 
 
    {"source": "Brevet", "target": "Bamatabois", "value": 1}, 
 
    {"source": "Chenildieu", "target": "Judge", "value": 2}, 
 
    {"source": "Chenildieu", "target": "Champmathieu", "value": 2}, 
 
    {"source": "Chenildieu", "target": "Brevet", "value": 2}, 
 
    {"source": "Chenildieu", "target": "Valjean", "value": 2}, 
 
    {"source": "Chenildieu", "target": "Bamatabois", "value": 1}, 
 
    {"source": "Cochepaille", "target": "Judge", "value": 2}, 
 
    {"source": "Cochepaille", "target": "Champmathieu", "value": 2}, 
 
    {"source": "Cochepaille", "target": "Brevet", "value": 2}, 
 
    {"source": "Cochepaille", "target": "Chenildieu", "value": 2}, 
 
    {"source": "Cochepaille", "target": "Valjean", "value": 2}, 
 
    {"source": "Cochepaille", "target": "Bamatabois", "value": 1}, 
 
    {"source": "Pontmercy", "target": "Thenardier", "value": 1}, 
 
    {"source": "Boulatruelle", "target": "Thenardier", "value": 1}, 
 
    {"source": "Eponine", "target": "Mme.Thenardier", "value": 2}, 
 
    {"source": "Eponine", "target": "Thenardier", "value": 3}, 
 
    {"source": "Anzelma", "target": "Eponine", "value": 2}, 
 
    {"source": "Anzelma", "target": "Thenardier", "value": 2}, 
 
    {"source": "Anzelma", "target": "Mme.Thenardier", "value": 1}, 
 
    {"source": "Woman2", "target": "Valjean", "value": 3}, 
 
    {"source": "Woman2", "target": "Cosette", "value": 1}, 
 
    {"source": "Woman2", "target": "Javert", "value": 1}, 
 
    {"source": "MotherInnocent", "target": "Fauchelevent", "value": 3}, 
 
    {"source": "MotherInnocent", "target": "Valjean", "value": 1}, 
 
    {"source": "Gribier", "target": "Fauchelevent", "value": 2}, 
 
    {"source": "Mme.Burgon", "target": "Jondrette", "value": 1}, 
 
    {"source": "Gavroche", "target": "Mme.Burgon", "value": 2}, 
 
    {"source": "Gavroche", "target": "Thenardier", "value": 1}, 
 
    {"source": "Gavroche", "target": "Javert", "value": 1}, 
 
    {"source": "Gavroche", "target": "Valjean", "value": 1}, 
 
    {"source": "Gillenormand", "target": "Cosette", "value": 3}, 
 
    {"source": "Gillenormand", "target": "Valjean", "value": 2}, 
 
    {"source": "Magnon", "target": "Gillenormand", "value": 1}, 
 
    {"source": "Magnon", "target": "Mme.Thenardier", "value": 1}, 
 
    {"source": "Mlle.Gillenormand", "target": "Gillenormand", "value": 9}, 
 
    {"source": "Mlle.Gillenormand", "target": "Cosette", "value": 2}, 
 
    {"source": "Mlle.Gillenormand", "target": "Valjean", "value": 2}, 
 
    {"source": "Mme.Pontmercy", "target": "Mlle.Gillenormand", "value": 1}, 
 
    {"source": "Mme.Pontmercy", "target": "Pontmercy", "value": 1}, 
 
    {"source": "Mlle.Vaubois", "target": "Mlle.Gillenormand", "value": 1}, 
 
    {"source": "Lt.Gillenormand", "target": "Mlle.Gillenormand", "value": 2}, 
 
    {"source": "Lt.Gillenormand", "target": "Gillenormand", "value": 1}, 
 
    {"source": "Lt.Gillenormand", "target": "Cosette", "value": 1}, 
 
    {"source": "Marius", "target": "Mlle.Gillenormand", "value": 6}, 
 
    {"source": "Marius", "target": "Gillenormand", "value": 12}, 
 
    {"source": "Marius", "target": "Pontmercy", "value": 1}, 
 
    {"source": "Marius", "target": "Lt.Gillenormand", "value": 1}, 
 
    {"source": "Marius", "target": "Cosette", "value": 21}, 
 
    {"source": "Marius", "target": "Valjean", "value": 19}, 
 
    {"source": "Marius", "target": "Tholomyes", "value": 1}, 
 
    {"source": "Marius", "target": "Thenardier", "value": 2}, 
 
    {"source": "Marius", "target": "Eponine", "value": 5}, 
 
    {"source": "Marius", "target": "Gavroche", "value": 4} 
 
    ] 
 
}; 
 
var svg = d3.select("svg"), 
 
    width = +svg.attr("width"), 
 
    height = +svg.attr("height"); 
 

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

 
var simulation = d3.forceSimulation() 
 
    \t .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(400)) 
 
    .force("charge", d3.forceManyBody()) 
 
    .force("center", d3.forceCenter(width/2, height/1.8)); 
 

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

 
var node = svg.selectAll(".node") //essential to define the nodes 
 
    .data(graph.nodes) 
 
    .enter().append("g") 
 
\t .attr("class", "node") 
 
    .call(d3.drag() //enables the dragging function (see further down) 
 
      .on("start", dragstarted) 
 
      .on("drag", dragged) 
 
      .on("end", dragended)); 
 
\t \t \t 
 
node.append("circle") 
 
    .attr("r", 8) 
 
    .attr("fill", function(d) { return color(d.group); }); 
 

 
node.append("text") 
 
    \t .attr("dx", -5) 
 
\t .attr("dy", -15) 
 
    .text(function(d) { return d.id; }); 
 
\t 
 
simulation 
 
     .nodes(graph.nodes) 
 
     .on("tick", tick); 
 

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

 
function ticked() { 
 
\t node.attr("transform", function(d) { 
 
    return "translate(" + d.x + "," + d.y + ")"; }); 
 
    } 
 

 
function tick() { //creates layout, essential 
 
     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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 
 
    }; 
 

 
function dragstarted(d,i) { 
 
     simulation.stop() 
 
} 
 

 
function dragged(d, i) { 
 
     d.x += d3.event.dx; 
 
     d.y += d3.event.dy; 
 
     tick(); 
 
} 
 
function dragended(d, i) {l 
 
     d.fixed = true; 
 
\t \t simulation.alphaTarget(0).restart(); 
 
} 
 
</script> 
 
</head> 
 
<body> 
 
</body> 
 
</html>

回答

0

您指向也由上的地理特征顶部的沃罗诺伊镶嵌复杂以上实施例中的小鼠。但是如果您只想要

添加一个鼠标悬停功能,该功能仅在鼠标位置显示 人/节点的链接。

那么你的解决方案相对容易。你需要在每个节点上添加事件侦听mouseovermouseout事件:

var node = svg.selectAll(".node") //essential to define the nodes 
    .data(graph.nodes) 
    .enter().append("g") 
    .attr("class", "node") 
    .on('mouseover',mouseover) 
    .on('mouseout',mouseout) 
    .call(d3.drag() //enables the dragging function (see further down) 
      .on("start", dragstarted) 
      .on("drag", dragged) 
      .on("end", dragended)); 

然后对每个创建功能:

function mouseover(d) { 
    link.filter(function(e) { return e.target.id == d.id || e.source.id == d.id; }) 
    .style('opacity',1) 
    .style('stroke','black') 
} 

function mouseout(d) { 
    link.style('stroke', "#9cf") 
     .style('stroke-opacity', 0.6); 
} 

的mouseon功能有一个过滤器来过滤节点,以便只有那些具有与当前鼠标移动的节点相同的源或目标的节点被修改 - mouseout函数不需要这个,所以它是不加区分的。

总之,这些改进给你:

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

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

 
highlight { 
 
    stroke: black !important; 
 
    stroke-width: 10px; 
 
} 
 

 
.nodes circle { 
 
    stroke: #fff; 
 
    stroke-width: 1.5px; 
 
} 
 
* {font-family: Arial, sans-serif;font-size:12px;color:#fff;} 
 
</style> 
 
<svg width="1400" height="900" style="background:url('miserables_op.jpg');background-size:contain;background-repeat:no-repeat"></svg> 
 
<script src="https://d3js.org/d3.v4.min.js"></script> 
 
<script> 
 
var graph = { 
 
\t nodes:[ 
 
    {"id": "Myriel", "group": 1}, 
 
    {"id": "Napoleon", "group": 1}, 
 
    {"id": "Mlle.Baptistine", "group": 1}, 
 
    {"id": "Mme.Magloire", "group": 1}, 
 
    {"id": "CountessdeLo", "group": 1}, 
 
    {"id": "Geborand", "group": 1}, 
 
    {"id": "Champtercier", "group": 1}, 
 
    {"id": "Cravatte", "group": 1}, 
 
    {"id": "Count", "group": 1}, 
 
    {"id": "OldMan", "group": 1}, 
 
    {"id": "Labarre", "group": 2}, 
 
    {"id": "Valjean", "fx":1300, "fy":570, "group": 2}, 
 
    {"id": "Marguerite", "group": 3}, 
 
    {"id": "Mme.deR", "group": 2}, 
 
    {"id": "Isabeau", "group": 2}, 
 
    {"id": "Gervais", "group": 2}, 
 
    {"id": "Tholomyes", "group": 3}, 
 
    {"id": "Listolier", "group": 3}, 
 
    {"id": "Fameuil", "group": 3}, 
 
    {"id": "Blacheville", "group": 3}, 
 
    {"id": "Favourite", "group": 3}, 
 
    {"id": "Dahlia", "group": 3}, 
 
    {"id": "Zephine", "group": 3}, 
 
    {"id": "Fantine", "group": 3}, 
 
    {"id": "Mme.Thenardier", "group": 4}, 
 
    {"id": "Thenardier", "group": 4}, 
 
    {"id": "Cosette", "fx":1245, "fy":625, "group": 5}, 
 
    {"id": "Javert", "fx":110, "fy":450,"group": 4}, 
 
    {"id": "Fauchelevent", "group": 0}, 
 
    {"id": "Bamatabois", "group": 2}, 
 
    {"id": "Perpetue", "group": 3}, 
 
    {"id": "Simplice", "group": 2}, 
 
    {"id": "Scaufflaire", "group": 2}, 
 
    {"id": "Woman1", "group": 2}, 
 
    {"id": "Judge", "group": 2}, 
 
    {"id": "Champmathieu", "group": 2}, 
 
    {"id": "Brevet", "group": 2}, 
 
    {"id": "Chenildieu", "group": 2}, 
 
    {"id": "Cochepaille", "group": 2}, 
 
    {"id": "Pontmercy", "group": 4}, 
 
    {"id": "Boulatruelle", "group": 6}, 
 
    {"id": "Eponine", "fx":535, "fy":535, "group": 4}, 
 
    {"id": "Anzelma", "group": 4}, 
 
    {"id": "Woman2", "group": 5}, 
 
    {"id": "MotherInnocent", "group": 0}, 
 
    {"id": "Gribier", "group": 0}, 
 
    {"id": "Jondrette", "group": 7}, 
 
    {"id": "Mme.Burgon", "group": 7}, 
 
    {"id": "Gavroche", "group": 8}, 
 
    {"id": "Gillenormand", "group": 5}, 
 
    {"id": "Magnon", "group": 5}, 
 
    {"id": "Mlle.Gillenormand", "group": 5}, 
 
    {"id": "Mme.Pontmercy", "group": 5}, 
 
    {"id": "Mlle.Vaubois", "group": 5}, 
 
    {"id": "Lt.Gillenormand", "group": 5}, 
 
    {"id": "Marius", "group": 8} 
 
\t ], 
 
    links: [ 
 
    {"source": "Napoleon", "target": "Myriel", "value": 1}, 
 
    {"source": "Mlle.Baptistine", "target": "Myriel", "value": 8}, 
 
    {"source": "Mme.Magloire", "target": "Myriel", "value": 10}, 
 
    {"source": "Mme.Magloire", "target": "Mlle.Baptistine", "value": 6}, 
 
    {"source": "CountessdeLo", "target": "Myriel", "value": 1}, 
 
    {"source": "Geborand", "target": "Myriel", "value": 1}, 
 
    {"source": "Champtercier", "target": "Myriel", "value": 1}, 
 
    {"source": "Cravatte", "target": "Myriel", "value": 1}, 
 
    {"source": "Count", "target": "Myriel", "value": 2}, 
 
    {"source": "OldMan", "target": "Myriel", "value": 1}, 
 
    {"source": "Valjean", "target": "Labarre", "value": 1}, 
 
    {"source": "Valjean", "target": "Mme.Magloire", "value": 3}, 
 
    {"source": "Valjean", "target": "Mlle.Baptistine", "value": 3}, 
 
    {"source": "Valjean", "target": "Myriel", "value": 5}, 
 
    {"source": "Marguerite", "target": "Valjean", "value": 1}, 
 
    {"source": "Mme.deR", "target": "Valjean", "value": 1}, 
 
    {"source": "Isabeau", "target": "Valjean", "value": 1}, 
 
    {"source": "Gervais", "target": "Valjean", "value": 1}, 
 
    {"source": "Listolier", "target": "Tholomyes", "value": 4}, 
 
    {"source": "Fameuil", "target": "Tholomyes", "value": 4}, 
 
    {"source": "Fameuil", "target": "Listolier", "value": 4}, 
 
    {"source": "Blacheville", "target": "Tholomyes", "value": 4}, 
 
    {"source": "Blacheville", "target": "Listolier", "value": 4}, 
 
    {"source": "Blacheville", "target": "Fameuil", "value": 4}, 
 
    {"source": "Favourite", "target": "Tholomyes", "value": 3}, 
 
    {"source": "Favourite", "target": "Listolier", "value": 3}, 
 
    {"source": "Favourite", "target": "Fameuil", "value": 3}, 
 
    {"source": "Favourite", "target": "Blacheville", "value": 4}, 
 
    {"source": "Dahlia", "target": "Tholomyes", "value": 3}, 
 
    {"source": "Dahlia", "target": "Listolier", "value": 3}, 
 
    {"source": "Dahlia", "target": "Fameuil", "value": 3}, 
 
    {"source": "Dahlia", "target": "Blacheville", "value": 3}, 
 
    {"source": "Dahlia", "target": "Favourite", "value": 5}, 
 
    {"source": "Zephine", "target": "Tholomyes", "value": 3}, 
 
    {"source": "Zephine", "target": "Listolier", "value": 3}, 
 
    {"source": "Zephine", "target": "Fameuil", "value": 3}, 
 
    {"source": "Zephine", "target": "Blacheville", "value": 3}, 
 
    {"source": "Zephine", "target": "Favourite", "value": 4}, 
 
    {"source": "Zephine", "target": "Dahlia", "value": 4}, 
 
    {"source": "Fantine", "target": "Tholomyes", "value": 3}, 
 
    {"source": "Fantine", "target": "Listolier", "value": 3}, 
 
    {"source": "Fantine", "target": "Fameuil", "value": 3}, 
 
    {"source": "Fantine", "target": "Blacheville", "value": 3}, 
 
    {"source": "Fantine", "target": "Favourite", "value": 4}, 
 
    {"source": "Fantine", "target": "Dahlia", "value": 4}, 
 
    {"source": "Fantine", "target": "Zephine", "value": 4}, 
 
    {"source": "Fantine", "target": "Marguerite", "value": 2}, 
 
    {"source": "Fantine", "target": "Valjean", "value": 9}, 
 
    {"source": "Mme.Thenardier", "target": "Fantine", "value": 2}, 
 
    {"source": "Mme.Thenardier", "target": "Valjean", "value": 7}, 
 
    {"source": "Thenardier", "target": "Mme.Thenardier", "value": 13}, 
 
    {"source": "Thenardier", "target": "Fantine", "value": 1}, 
 
    {"source": "Thenardier", "target": "Valjean", "value": 12}, 
 
    {"source": "Cosette", "target": "Mme.Thenardier", "value": 4}, 
 
    {"source": "Cosette", "target": "Valjean", "value": 31}, 
 
    {"source": "Cosette", "target": "Tholomyes", "value": 1}, 
 
    {"source": "Cosette", "target": "Thenardier", "value": 1}, 
 
    {"source": "Javert", "target": "Valjean", "value": 17}, 
 
    {"source": "Javert", "target": "Fantine", "value": 5}, 
 
    {"source": "Javert", "target": "Thenardier", "value": 5}, 
 
    {"source": "Javert", "target": "Mme.Thenardier", "value": 1}, 
 
    {"source": "Javert", "target": "Cosette", "value": 1}, 
 
    {"source": "Fauchelevent", "target": "Valjean", "value": 8}, 
 
    {"source": "Fauchelevent", "target": "Javert", "value": 1}, 
 
    {"source": "Bamatabois", "target": "Fantine", "value": 1}, 
 
    {"source": "Bamatabois", "target": "Javert", "value": 1}, 
 
    {"source": "Bamatabois", "target": "Valjean", "value": 2}, 
 
    {"source": "Perpetue", "target": "Fantine", "value": 1}, 
 
    {"source": "Simplice", "target": "Perpetue", "value": 2}, 
 
    {"source": "Simplice", "target": "Valjean", "value": 3}, 
 
    {"source": "Simplice", "target": "Fantine", "value": 2}, 
 
    {"source": "Simplice", "target": "Javert", "value": 1}, 
 
    {"source": "Scaufflaire", "target": "Valjean", "value": 1}, 
 
    {"source": "Woman1", "target": "Valjean", "value": 2}, 
 
    {"source": "Woman1", "target": "Javert", "value": 1}, 
 
    {"source": "Judge", "target": "Valjean", "value": 3}, 
 
    {"source": "Judge", "target": "Bamatabois", "value": 2}, 
 
    {"source": "Champmathieu", "target": "Valjean", "value": 3}, 
 
    {"source": "Champmathieu", "target": "Judge", "value": 3}, 
 
    {"source": "Champmathieu", "target": "Bamatabois", "value": 2}, 
 
    {"source": "Brevet", "target": "Judge", "value": 2}, 
 
    {"source": "Brevet", "target": "Champmathieu", "value": 2}, 
 
    {"source": "Brevet", "target": "Valjean", "value": 2}, 
 
    {"source": "Brevet", "target": "Bamatabois", "value": 1}, 
 
    {"source": "Chenildieu", "target": "Judge", "value": 2}, 
 
    {"source": "Chenildieu", "target": "Champmathieu", "value": 2}, 
 
    {"source": "Chenildieu", "target": "Brevet", "value": 2}, 
 
    {"source": "Chenildieu", "target": "Valjean", "value": 2}, 
 
    {"source": "Chenildieu", "target": "Bamatabois", "value": 1}, 
 
    {"source": "Cochepaille", "target": "Judge", "value": 2}, 
 
    {"source": "Cochepaille", "target": "Champmathieu", "value": 2}, 
 
    {"source": "Cochepaille", "target": "Brevet", "value": 2}, 
 
    {"source": "Cochepaille", "target": "Chenildieu", "value": 2}, 
 
    {"source": "Cochepaille", "target": "Valjean", "value": 2}, 
 
    {"source": "Cochepaille", "target": "Bamatabois", "value": 1}, 
 
    {"source": "Pontmercy", "target": "Thenardier", "value": 1}, 
 
    {"source": "Boulatruelle", "target": "Thenardier", "value": 1}, 
 
    {"source": "Eponine", "target": "Mme.Thenardier", "value": 2}, 
 
    {"source": "Eponine", "target": "Thenardier", "value": 3}, 
 
    {"source": "Anzelma", "target": "Eponine", "value": 2}, 
 
    {"source": "Anzelma", "target": "Thenardier", "value": 2}, 
 
    {"source": "Anzelma", "target": "Mme.Thenardier", "value": 1}, 
 
    {"source": "Woman2", "target": "Valjean", "value": 3}, 
 
    {"source": "Woman2", "target": "Cosette", "value": 1}, 
 
    {"source": "Woman2", "target": "Javert", "value": 1}, 
 
    {"source": "MotherInnocent", "target": "Fauchelevent", "value": 3}, 
 
    {"source": "MotherInnocent", "target": "Valjean", "value": 1}, 
 
    {"source": "Gribier", "target": "Fauchelevent", "value": 2}, 
 
    {"source": "Mme.Burgon", "target": "Jondrette", "value": 1}, 
 
    {"source": "Gavroche", "target": "Mme.Burgon", "value": 2}, 
 
    {"source": "Gavroche", "target": "Thenardier", "value": 1}, 
 
    {"source": "Gavroche", "target": "Javert", "value": 1}, 
 
    {"source": "Gavroche", "target": "Valjean", "value": 1}, 
 
    {"source": "Gillenormand", "target": "Cosette", "value": 3}, 
 
    {"source": "Gillenormand", "target": "Valjean", "value": 2}, 
 
    {"source": "Magnon", "target": "Gillenormand", "value": 1}, 
 
    {"source": "Magnon", "target": "Mme.Thenardier", "value": 1}, 
 
    {"source": "Mlle.Gillenormand", "target": "Gillenormand", "value": 9}, 
 
    {"source": "Mlle.Gillenormand", "target": "Cosette", "value": 2}, 
 
    {"source": "Mlle.Gillenormand", "target": "Valjean", "value": 2}, 
 
    {"source": "Mme.Pontmercy", "target": "Mlle.Gillenormand", "value": 1}, 
 
    {"source": "Mme.Pontmercy", "target": "Pontmercy", "value": 1}, 
 
    {"source": "Mlle.Vaubois", "target": "Mlle.Gillenormand", "value": 1}, 
 
    {"source": "Lt.Gillenormand", "target": "Mlle.Gillenormand", "value": 2}, 
 
    {"source": "Lt.Gillenormand", "target": "Gillenormand", "value": 1}, 
 
    {"source": "Lt.Gillenormand", "target": "Cosette", "value": 1}, 
 
    {"source": "Marius", "target": "Mlle.Gillenormand", "value": 6}, 
 
    {"source": "Marius", "target": "Gillenormand", "value": 12}, 
 
    {"source": "Marius", "target": "Pontmercy", "value": 1}, 
 
    {"source": "Marius", "target": "Lt.Gillenormand", "value": 1}, 
 
    {"source": "Marius", "target": "Cosette", "value": 21}, 
 
    {"source": "Marius", "target": "Valjean", "value": 19}, 
 
    {"source": "Marius", "target": "Tholomyes", "value": 1}, 
 
    {"source": "Marius", "target": "Thenardier", "value": 2}, 
 
    {"source": "Marius", "target": "Eponine", "value": 5}, 
 
    {"source": "Marius", "target": "Gavroche", "value": 4} 
 
    ] 
 
}; 
 
var svg = d3.select("svg"), 
 
    width = +svg.attr("width"), 
 
    height = +svg.attr("height"); 
 

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

 
var simulation = d3.forceSimulation() 
 
    \t .force("link", d3.forceLink().id(function(d) { return d.id; }).distance(400)) 
 
    .force("charge", d3.forceManyBody()) 
 
    .force("center", d3.forceCenter(width/2, height/1.8)); 
 

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

 
var node = svg.selectAll(".node") //essential to define the nodes 
 
    .data(graph.nodes) 
 
    .enter().append("g") 
 
\t .attr("class", "node") 
 
    .on('mouseover',mouseover) 
 
    .on('mouseout',mouseout) 
 
    .call(d3.drag() //enables the dragging function (see further down) 
 
      .on("start", dragstarted) 
 
      .on("drag", dragged) 
 
      .on("end", dragended)); 
 
\t \t \t 
 
node.append("circle") 
 
    .attr("r", 8) 
 
    .attr("fill", function(d) { return color(d.group); }); 
 

 
node.append("text") 
 
    \t .attr("dx", -5) 
 
\t .attr("dy", -15) 
 
    .text(function(d) { return d.id; }); 
 
\t 
 
simulation 
 
     .nodes(graph.nodes) 
 
     .on("tick", tick); 
 

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

 
function ticked() { 
 
\t node.attr("transform", function(d) { 
 
    return "translate(" + d.x + "," + d.y + ")"; }); 
 
    } 
 

 
function tick() { //creates layout, essential 
 
     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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 
 
    }; 
 

 
function dragstarted(d,i) { 
 
     simulation.stop() 
 
} 
 

 
function dragged(d, i) { 
 
     d.x += d3.event.dx; 
 
     d.y += d3.event.dy; 
 
     tick(); 
 
} 
 
function dragended(d, i) {l 
 
     d.fixed = true; 
 
\t \t simulation.alphaTarget(0).restart(); 
 
} 
 

 
function mouseover(d) { 
 
    link.filter(function(e) { return e.target.id == d.id || e.source.id == d.id; }) 
 
    .style('opacity',1) 
 
    .style('stroke','black') 
 
} 
 

 
function mouseout(d) { 
 
    link.style('stroke', "#9cf") 
 
     .style('stroke-opacity', 0.6); 
 
} 
 

 

 
</script> 
 
</head> 
 
<body> 
 
</body> 
 
</html>

+0

辉煌!非常感谢安德鲁!突出显示的链接甚至比我希望的更好。强制布局,背景图像和鼠标悬停的这种组合将允许任何人将大家庭或学校图片与人的名字以及他们如何相互关联。如果我可以扩展我的问题:是否有选择使用链接来创建(例如Ajaxed)工具提示/窗口,从而给出这些人彼此之间的相互关系的更多细节? – Gert