我正在尝试生成类似于以下示例的可折叠力布局:http://bl.ocks.org/mbostock/1062288:
用于生成我的部队布局的数据是从API派生的JSON对象。我能够成功遍历数据结构,并生成附加到SVG的节点(根节点及其子节点)。
但是,问题在于将父节点链接到其子节点。链接未生成,并且我的links变量返回一个空数组。与示例相比,我非常确定问题与应用程序中的数据结构有关,因此,我将发布我的JS代码和每个节点的数据结构。
任何帮助将非常感激!提前致谢!!
这是我的代码的JS小提琴:http://jsfiddle.net/tmzjW/
这是我的JS代码:
//Force Layout Code
var w = 607,
h = 500,
node,
link,
root;
var force = d3.layout.force()
.on("tick", tick)
.size([w, h]);
var vis = d3.select("#chart").append("svg:svg")
.attr("width", w)
.attr("height", h);
function initiateForceJS(currentURL) {
//Generate the URL
forceURL = currentURL + ".json?jsonp=?";
$('#commentArea').show();
$.getJSON(forceURL,handleRequest2);
function handleRequest2(json) {
//Set the root as the first object returned
root = json[1]['data']['children'][0];
update();
}
}
function update() {
nodes = flatten(root),
links = d3.layout.tree()
.sort(null)
.children(function(d) {return (!d['replies']['data']['children']|| d['replies']['data']['children'].length === 0) ? null : d['replies']['data']['children'];})
.links(nodes);
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.start();
// Update the links…
link = vis.selectAll("line.link")
.data(links, function(d) { return d.target.id; });
// Enter any new links.
link.enter().insert("svg:line", ".node")
.attr("class", "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; });
// Exit any old links.
link.exit().remove();
// Update the nodes…
node = vis.selectAll("circle.node")
.data(nodes, function(d) {return d.id; })
.style("fill", color);
// Enter any new nodes.
node.enter().append("svg:circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return Math.sqrt(d.ups) || 4.5; })
.style("fill", color)
//.on("click", click)
.call(force.drag);
// Exit any old nodes.
node.exit().remove();
//This will add the name of the character to the node
node.append("comment").text(function(d) { return d.body });
//This will put the comment in the Comment Area div
node.on("mouseover", function() {
var currentNode = d3.select(this);
var currentTitle = currentNode.select("comment").text();
$('#commentArea').html('<p>' + currentTitle + '</p>')
});
}
function tick() {
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; });
}
// Color leaf nodes orange, and packages white or blue.
function color(d) {
return d._children ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c";
}
// Returns a list of all nodes under the root.
function flatten(root) {
var nodes = [], i = 0;
function recurse(node) {
if (node['data']['replies'] != "" && node['kind'] != "more") {
node['data']['replies']['data']['children'].forEach(recurse);
}
if (node['kind'] !="more") {
//Add an ID value to the node starting at 1
node.data.id = ++i;
var comment = node.data;
nodes.push(comment);
}
}
recurse(root);
return nodes;
}
最佳答案
问题在于hierarchy.links函数无法观察到您设置的子级访问器;它仅依赖于节点的children
属性。这在原始示例中有效,因为该示例使用标准的分层节点结构(每个节点上都有一个children
数组)。由于您使用的是非标准结构(由第三方API定义),因此无法使用。
links方法不会观察子访问器,因为当您在数据上调用层次结构布局(例如树形布局)时,它会根据您定义的子访问器为您填充children
属性。它将您的非标准输入数据自动映射到标准表单。但是,由于您实际上并未在此处使用层次结构布局,因此没有机会将节点映射为标准格式,因此hierarchy.links不返回结果-节点均没有children
数组。
这里的另一个问题是您的root
节点实际上没有任何答复,因此根节点没有子级。 (有root.data.replies.data.children
,但没有root.replies.data.children
,因为定义了您的孩子访问器。)
我认为最简单的方法是将数据映射到更简单的层次结构,其中子级被定义为children
数组。您也许可以使用层次结构布局来帮助解决此问题,但是鉴于您已经编写了一个扁平函数(或至少已修改了一个函数),因此无论如何,您已经完成了大部分工作。