Javascript 组织结构图 - 树状、在线、动态、可折叠、图片 - 在 D3 中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30926539/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Organization chart - tree, online, dynamic, collapsible, pictures - in D3
提问by d-_-b
I am a noob in web-development. I'm trying to create a tree-like hierarchical company org chart. I tried both google's visualization chartand Mike Bostock's D3 Reingold tree.
我是网络开发的菜鸟。我正在尝试创建一个树状分层公司组织结构图。我尝试了 google 的可视化图表和 Mike Bostock 的D3 Reingold tree。
I want these features :
我想要这些功能:
- tree structure : either top-down (google) or left-right (D3)
- online/dynamic : viewable in browser and able to read data from json (both google& D3), not static visio or ppt diagram
- collapsible : able to hide subtrees (both)
- space-adjusting : nodes should fill visible area, to reduce scrolling (only D3)
- attributes : display name, title & possibly picture (only google)
- 树结构:自上而下(google)或左右(D3)
- 在线/动态:可在浏览器中查看并能够从 json(谷歌和D3)中读取数据,而不是静态 visio 或 ppt 图
- collapsible :能够隐藏子树(两者)
- 空间调整:节点应填充可见区域,以减少滚动(仅D3)
- 属性:显示名称、标题和可能的图片(仅限谷歌)
Above I've marked which tool allows which features, afaik.
I prefer the D3 versionbecause it looks cool.
I can modify the .json to include additional fields (title, url to photo etc.) - here is a sample
上面我已经标记了哪个工具允许哪些功能,afaik。
我更喜欢 D3 版本,因为它看起来很酷。
我可以修改 .json 以包含其他字段(标题、照片的 url 等) - 这是一个示例
My question is - how do I modify the D3 codeto display an employee's name, then title in the next line, and maybe picture too ?
我的问题是 - 如何修改D3 代码以显示员工姓名,然后在下一行显示标题,也许还有图片?
Or if that's not feasible - how do I modify the google codeto automatically adjust spacing, so that all children of a node are close together, and I don't have to horizontally scroll ?
或者,如果这不可行 - 我如何修改谷歌代码以自动调整间距,以便节点的所有子节点都靠近在一起,而我不必水平滚动?
回答by Mark
Here's a quick example. It modifies this example, to add in first name, last name, a title and a picture.
这是一个快速示例。它修改了这个例子,添加了名字、姓氏、标题和图片。
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 960 - margin.right - margin.left,
height = 300 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = {
"fname": "Rachel",
"lname": "Rogers",
"title": "CEO",
"photo": "http://lorempixel.com/60/60/cats/1",
"children": [{
"fname": "Bob",
"lname": "Smith",
"title": "President",
"photo": "http://lorempixel.com/60/60/cats/2",
"children": [{
"fname": "Mary",
"lname": "Jane",
"title": "Vice President",
"photo": "http://lorempixel.com/60/60/cats/3",
"children": [{
"fname": "Bill",
"lname": "August",
"title": "Dock Worker",
"photo": "http://lorempixel.com/60/60/cats/4"
}, {
"fname": "Reginald",
"lname": "Yoyo",
"title": "Line Assembly",
"photo": "http://lorempixel.com/60/60/cats/5"
}]
}, {
"fname": "Nathan",
"lname": "Ringwald",
"title": "Comptroller",
"photo": "http://lorempixel.com/60/60/cats/6"
}]
}]
}
root = data;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });
// Update the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click);
// add picture
nodeEnter
.append('defs')
.append('pattern')
.attr('id', function(d,i){
return 'pic_' + d.fname + d.lname;
})
.attr('height',60)
.attr('width',60)
.attr('x',0)
.attr('y',0)
.append('image')
.attr('xlink:href',function(d,i){
return d.photo;
})
.attr('height',60)
.attr('width',60)
.attr('x',0)
.attr('y',0);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
var g = nodeEnter.append("g");
g.append("text")
.attr("x", function(d) { return d.children || d._children ? -35 : 35; })
.attr("dy", "1.35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.fname + " " + d.lname; })
.style("fill-opacity", 1e-6);
g.append("text")
.attr("x", function(d) { return d.children || d._children ? -35 : 35; })
.attr("dy", "2.5em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.title; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 30)
.style("fill", function(d,i){
return 'url(#pic_' + d.fname + d.lname+')';
});
nodeUpdate.selectAll("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = svg.selectAll("path.link")
.data(links, function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = 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(d);
}
</script>
Reversed Direction:
反向:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 960 - margin.right - margin.left,
height = 300 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.x, d.y]; });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = {
"fname": "Rachel",
"lname": "Rogers",
"title": "CEO",
"photo": "http://lorempixel.com/60/60/cats/1",
"children": [{
"fname": "Bob",
"lname": "Smith",
"title": "President",
"photo": "http://lorempixel.com/60/60/cats/2",
"children": [{
"fname": "Mary",
"lname": "Jane",
"title": "Vice President",
"photo": "http://lorempixel.com/60/60/cats/3",
"children": [{
"fname": "Bill",
"lname": "August",
"title": "Dock Worker",
"photo": "http://lorempixel.com/60/60/cats/4"
}, {
"fname": "Reginald",
"lname": "Yoyo",
"title": "Line Assembly",
"photo": "http://lorempixel.com/60/60/cats/5"
}]
}, {
"fname": "Nathan",
"lname": "Ringwald",
"title": "Comptroller",
"photo": "http://lorempixel.com/60/60/cats/6"
}]
}]
}
root = data;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });
// Update the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.x0 + "," + source.y0 + ")"; })
.on("click", click);
// add picture
nodeEnter
.append('defs')
.append('pattern')
.attr('id', function(d,i){
return 'pic_' + d.fname + d.lname;
})
.attr('height',60)
.attr('width',60)
.attr('x',0)
.attr('y',0)
.append('image')
.attr('xlink:href',function(d,i){
return d.photo;
})
.attr('height',60)
.attr('width',60)
.attr('x',0)
.attr('y',0);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
var g = nodeEnter.append("g");
g.append("text")
.attr("x", function(d) { return d.children || d._children ? -35 : 35; })
.attr("dy", "1.35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.fname + " " + d.lname; })
.style("fill-opacity", 1e-6);
g.append("text")
.attr("x", function(d) { return d.children || d._children ? -35 : 35; })
.attr("dy", "2.5em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.title; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
nodeUpdate.select("circle")
.attr("r", 30)
.style("fill", function(d,i){
return 'url(#pic_' + d.fname + d.lname+')';
});
nodeUpdate.selectAll("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.x + "," + source.y + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = svg.selectAll("path.link")
.data(links, function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = 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(d);
}
</script>
回答by Gabriel
If you like to create your project with D3js, Just need to use the script
codes from thisand replaced3.json("/mbostock/raw/4063550/flare.json", function(error, flare)
with this :
如果你想创建D3js,只需要使用您的项目script
从码本和替换d3.json("/mbostock/raw/4063550/flare.json", function(error, flare)
本:
d3.json("yourJsonFile/jsonFileName.json", function(error, flare)
The jsonFileName.json
is your customized json file like this sample.
Also you can insert name of your pictures into the json file and replace the img
tag src with it.
这jsonFileName.json
是您自定义的 json 文件,如此 示例。您也可以将图片的名称插入 json 文件并img
用它替换标签 src。