我一直在尝试使用我编写的json文件实现定向强制布局。在我尝试使所有节点崩溃之前,它正常工作。我已经为所有节点声明了一个名为“index”的属性,指示它们属于哪个级别的树(root的索引是0,它的子节点是1,等等) 我猜测节点的“索引”属性存在问题,因为当我第一次启动页面时,它们的值是正确的,但是当我崩溃并重新打开一个节点时,相关节点的索引值会发生变化,它会不再正确地绘制链接。
为什么每当我点击任何内容时它会不断更改从json获取的索引值的任何想法,或者您是否有任何我可能会考虑解决问题的参考项目?
谢谢,
这是我的脚本代码:
var indx = 0;
var width = 1260, height = 1220, root;
var force = d3.layout.force().linkDistance(80).charge(-300)
.gravity(.05).size([ width, height ]).on("tick", tick);
var svg = d3.select("#chart").append("svg")
.attr("width", width).attr("height", height);
var link = svg.selectAll(".link"), node = svg
.selectAll(".node");
var text = svg.selectAll(".link");
d3.json("graph.json", function(error, json) {
root = json;
update();
});
function toggle(d) {
indx = d.index;
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update();
}
function prepareLinks(allNodes) {
var newLinks = new Array();
var allLinks = d3.layout.tree().links(allNodes);
for ( var i = 0; allLinks.length > i; i++) {
if (allLinks[i].source.index <= indx) {
console.log("source : " + allLinks[i].source.index
+ "-" + allLinks[i].source.name);
newLinks.push(allLinks[i]);
}
console.log(allLinks[i].target.index + "-"
+ allLinks[i].target.name);
}
for ( var i = 0; newLinks.length > i; i++) {
console.log("newLinks : " + newLinks[i].source.index
+ "-" + newLinks[i].source.name);
console.log(newLinks[i].target.index + "-"
+ newLinks[i].target.name);
}
return newLinks;
}
function update() {
var nodes = flatten(root, indx);
var links = prepareLinks(nodes);
// Restart the force layout.
force.nodes(nodes).links(links).start();
// Update links.
link = link.data(links, function(d) {
return d.target.id;
});
link.exit().remove();
link.enter().insert("line", ".node").attr("class", "link");
svg.selectAll("g.ltext").remove();
text = svg.append("svg:g").selectAll("g").data(links);
text.enter().append("svg:g").attr("class", "ltext");
text.append("svg:text").attr("class", "linktext").attr(
"dx", 5).attr("dy", ".35em").text(
function(d) {
return d.source.type;
});
// Update nodes.
node = node.data(nodes, function(d) {
return d.id;
});
node.exit().remove();
var nodeEnter = node.enter().append("g").attr("class",
"node").on("click", function(d) {
toggle(d);
update(d);
}).call(force.drag);
nodeEnter.append("circle").attr("r", function(d) {
return Math.sqrt(d.size) / 10 || 10;
});
nodeEnter.append("text").attr("dy", ".35em").text(
function(d) {
return d.name;
});
node.select("circle").style("fill", color);
}
function tick() {
link.attr("x1", function(d) {
return d.target.x;
}).attr("y1", function(d) {
return d.target.y;
}).attr("x2", function(d) {
return d.source.x;
}).attr("y2", function(d) {
return d.source.y;
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
text.attr("transform", function(d) {
var sourcex = d.source.x;
var sourcey = d.source.y;
var targetx = d.target.x;
var targety = d.target.y;
return "translate(" + (sourcex + targetx) / 2 + ","
+ (sourcey + targety) / 2 + ")";
});
}
function color(d) {
return d._children ? "#BA8343" // collapsed package
: d.children ? "#7C4C6B" // expanded package
: "#6F704A"; // leaf node
}
// Toggle children on click.
function click(d) {
if (d3.event.defaultPrevented)
return; // ignore drag
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
// Returns a list of all nodes under the root.
function flatten(root, indx) {
var nodes = [], i = 0;
function recurse(node) {
console.log("flatten'da başta index: " + node.index
+ "ad " + node.name);
if (node.children) {
node.children.forEach(recurse);
}
if (!node.id)
node.id = ++i;
if (indx >= node.index || indx + 1 == node.index) {
nodes.push(node);
// console.log("flatten'da index: "+ node.index+ "ad "+ node.name);
}
}
recurse(root);
return nodes;
}
以下是我的json文件中的一个示例:
{
"name": "Data Mining","type":"related","index":2,
"children": [
{
"name": "Yapay Sinir Ağları", "size": 7074,"type":"related","index":3,
"children": [
{
"name": "Compututional Intelligence","type":"narrower","index":4,
"children":[
{"name": "Genetik Algoritmalar", "size": 7074,"type":"related","index":5},
{"name": "Bulanık Mantık", "size": 7074,"type":"related","index":5},
{"name":"Soft Computing","type":"related","index":5,
"children": [
{"name": "Esnek Hesaplama", "size": 7074,"type":"related","index":6}
]
}
]
}
]
}
答案 0 :(得分:1)
问题很可能是index
是d3强制布局中节点的保留属性,并且在更新nodes属性时会被覆盖。
<强> force.nodes([节点])强>
如果指定了节点,则将布局的关联节点设置为 指定的数组。如果未指定节点,则返回当前数组, 默认为空数组。每个节点都有以下内容 属性:
index - 节点数组中节点的从零开始的索引。
x - 当前节点位置的x坐标。
y - 当前节点位置的y坐标。
px - 前一个节点位置的x坐标。
py - 前一个节点位置的y坐标。
fixed - 一个布尔值,指示节点位置是否被锁定。
重量 - 节点重量;相关链接的数量。
在将节点传递给之前,不需要设置这些属性 布局;如果未设置,则将初始化合适的默认值 调用start时的布局。 但是,请注意,如果你是 在节点上存储其他数据时,您的数据属性不应该 与布局使用的上述属性冲突。
要防止冲突,请将json中的index
属性重命名为其他内容。在我自己的项目中,我指的是给定节点与根的距离,因为它是depth
。