我是d3.js的新手,到目前为止我只用于小图,没有太复杂。现在我想为一些部门建立一个结构,到目前为止我找不到一个问题。我正在使用d3.js强制图,在某些情况下我希望有2个父节点用于相同的节点,这是否可以吗?
您可以在此处查看我的代码:
// rest of vars
var w = document.querySelector("#vis").clientWidth - 5,
h = document.querySelector("#vis").clientHeight - 5,
maxNodeSize = 100,
x_browser = 0,
y_browser = 0,
root;
var vis;
var force = d3.layout.force();
vis = d3.select("#vis").append("svg").attr("width", w).attr("height", h);
var json = {
"name": "lorem ipsum",
"size": 1200000,
"id": "Org",
"children": [
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"id": "GNS-Main3",
"x": 950,
"y": 300,
"fixed": true,
"children": [
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-2",
"link": "http://marvel.com/characters/54/spider-man",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-2",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-2",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-2",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"class": "gns-2",
"name": "lorem ipsum",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
}
]
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"id": "GNS-Main",
"x": 1400,
"y": 600,
"fixed": true,
"children": [
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-1",
"link": "http://marvel.com/characters/54/spider-man",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-1",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-1",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-1",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"class": "gns-1",
"name": "lorem ipsum",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-1",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
}
]
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"id": "GNS-Main2",
"x": 300,
"y": 600,
"fixed": true,
"children": [
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-3",
"link": "http://marvel.com/characters/54/spider-man",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-3",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-3",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-3",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"class": "gns-3",
"name": "lorem ipsum",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-3",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-3",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-3",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-3",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
},
{
"hero": "lorem ipsum",
"name": "lorem ipsum",
"class": "gns-3",
"link": "http://marvel.com/characters/9/captain_marvel",
"size": 40000
}
]
},
],
}
/*d3.json("marvel.json", function(json) {*/
root = json;
root.fixed = true;
root.x = w / 2;
root.y = h / 1.5;
// Build the path
var defs = vis.insert("svg:defs")
.data(["end"]);
defs.enter().append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
update();
function update() {
var nodes = flatten(root),
links = d3.layout.tree().links(nodes);
// Restart the force layout.
force.nodes(nodes)
.links(links)
.gravity(0.05)
.charge(-1500)
.linkDistance(230)
.friction(0.7)
.linkStrength(function(l, i) {return 1; })
.size([w, h])
.on("tick", tick)
.start();
var path = vis.selectAll("path.link")
.data(links, function(d) { return d.target.id; });
path.enter().insert("svg:path")
.attr("class", "link")
// .style("fill", "url(#gradient6)")
// .attr("marker-end", "url(#end)")
.style("stroke", "#eee");
// Exit any old paths.
path.exit().remove();
// Update the nodes…
var node = vis.selectAll("g.node")
.data(nodes, function(d) { return d.id; });
// Enter any new nodes.
var nodeEnter = node.enter().append("svg:g")
.attr("class", function(d) { return "node " + d.class })
.attr("id", function(d) { return d.id }) // Custom id
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.on("click", click)
.call(force.drag);
// Append a circle
nodeEnter.append("svg:circle")
.attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
.style("fill", "#eee");
// Append images
var images = nodeEnter.append("svg:image")
.attr("xlink:href", function(d) { return d.img;})
.attr("x", function(d) { return -25;})
.attr("y", function(d) { return -25;})
.attr("height", 50)
.attr("width", 50);
// Append hero name on roll over next to the node as well
nodeEnter.append("text")
.attr("class", "nodetext")
//.attr("x", x_browser - 45)
//.attr("y", y_browser + 15)
.attr("text-anchor", "middle")
//.attr("fill", tcBlack)
.text(function(d) { return d.hero; });
// Exit any old nodes.
//node.exit().remove();
// Re-select for update.
path = vis.selectAll("path.link");
node = vis.selectAll("g.node");
function tick() {
path.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + ","
+ d.source.y
+ "A" + dr + ","
+ dr + " 0 0,1 "
+ d.target.x + ","
+ d.target.y;
});
node.attr("transform", nodeTransform);
}
}
/**
* Gives the coordinates of the border for keeping the nodes inside a frame
* http://bl.ocks.org/mbostock/1129492
*/
function nodeTransform(d) {
d.x = Math.max(maxNodeSize, Math.min(w - (d.imgwidth/2 || 16), d.x));
d.y = Math.max(maxNodeSize, Math.min(h - (d.imgheight/2 || 16), d.y));
return "translate(" + d.x + "," + d.y + ")";
}
/**
* Toggle children on click.
*/
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
//update(); -- this genrates issues with paths
}
/**
* Returns a list of all nodes under the root.
*/
function flatten(root) {
var nodes = [];
var i = 0;
function recurse(node) {
if (node.children)
node.children.forEach(recurse);
if (!node.id)
node.id = ++i;
nodes.push(node);
}
recurse(root);
return nodes;
}
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900');
html{height: 100%;}
body {font-family: 'Roboto', sans-serif; line-height: 1; font-size: 14px; margin: 0;background: #eee;height: 100%; }
path.link {
fill: none;
stroke-width: 2px;
}
#vis{width: 100%;height: 100%;}
section svg{background-color:#fff;}
h1 { font-size: 36px; margin: 10px 0; text-transform: uppercase; font-weight: normal;}
h2, h3 { font-size: 18px; margin: 5px 0 ; font-weight: normal;}
header {padding: 20px; position: absolute; top: 0; left: 0;}
a:link { color: #EE3124; text-decoration: none;}
a:visited { color: #EE3124; }
a:hover { color: #A4CD39; text-decoration: underline;}
a:active { color: #EE3124; }
.nodetext{ font-size: 18px; font-weight: 100;}
#Org image{width: 220px;height: 220px;x: -110;y: -110;}
#GNS-Main circle{r:30;fill:#37556f !important;stroke-width: 4;stroke: #2e4c66;}
.gns-1 .nodetext{ font-size: 18px;font-weight: 100;transform: translateY(40px);}
#GNS-Main2 circle{r:30;fill:#ff6600 !important;stroke-width: 4;stroke: #eb5e00;}
.gns-2 .nodetext{ font-size: 18px;font-weight: 100;transform: translateY(40px);}
#GNS-Main3 circle{r:30;fill:#e7e7e7 !important;stroke-width: 4;stroke: #dadada;}
.gns-3 .nodetext{ font-size: 18px;font-weight: 100;transform: translateY(40px);}
#GNS-Main .nodetext,#GNS-Main2 .nodetext,#GNS-Main3 .nodetext{ font-size: 34px;font-weight: 800;transform: translateY(65px);}
.gns-1 circle{fill:#37556f !important;stroke-width: 4;stroke: #2e4c66;}
.gns-2 circle{fill:#e7e7e7 !important;stroke-width: 4;stroke: #dadada;}
.gns-3 circle{fill:#ff6600 !important;stroke-width: 4;stroke: #eb5e00;}
.node circle{transition: all 0.2s ease-in;}
.node:hover circle{r:25;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Marvel Characters | Force layout with images</title>
<style>
</style>
</head>
<body>
<!-- <header>
<h1>Marvel Characters</h1>
<h2>Click to view their identity</h2>
<h3>And link to their web page!</h3>
</header>-->
<!-- container for force layout visualisation -->
<section id="vis"></section>
<script>
</script>
</body>
</html>
感谢。
答案 0 :(得分:0)
实现这一目标的可能性是改变json的结构,如下所述:https://bl.ocks.org/mbostock/4062045
首先,您将描述所有节点,然后使用source(child)和target(parent)定义所有链接。
这是一个小例子:
JSON结构
{
"nodes": [
{ "id":64, "first_name":"Archived", "type":"L" } ,
{ "id":65, "first_name":"Archived 2", "type":"L" } ,
{ "id":84, "first_name":"Paymentoffice 2", "type":"P" } ,
{ "id":21, "first_name":"Contact 0", "type":"C" } ,
{ "id":41, "first_name":"Paymentoffice 1", "type":"P" } ,
{ "id":61, "first_name":"Contact 1", "type":"C" } ,
{ "id":62, "first_name":"Contact 2", "type":"C" } ,
{ "id":63, "first_name":"Contact 3", "type":"C" } ,
{ "id":1, "first_name":"Licensees", "type":"L" } ,
{ "id":94, "first_name":"Noch eins", "type":"P" }
],
"links": [
{ "source":84, "target":1 } ,
{ "source":65, "target":1 } ,
{ "source":21, "target":1 } ,
{ "source":63, "target":62 } ,
{ "source":41, "target":21 } ,
{ "source":84, "target":21 } ,
{ "source":64, "target":1 } ,
{ "source":62, "target":61 } ,
{ "source":94, "target":61 } ,
{ "source":61, "target":1 } ,
{ "source":61, "target":94 }
]
}
图表如下所示:
Paymentoffice 2节点(id:84)有两个父节点,即被许可方节点(id:1)和Contact 0节点(id:21)
希望这会对你有所帮助。