我想构建一个类似于分层可视化的Windows资源管理器。由于我想手动计算x和y坐标,我根据此处描述的第一个示例创建了一个自定义布局: Custom layout in d3.js?
我的布局功能如下所示:
function myTreeLayout(data) {
var nodes = []; // or reuse data directly depending on layout
//load all nodes and their subnodes:
var coreelement=data;
coreelement.x=0;
coreelement.y=0;
positions(coreelement,0);
//nodes.push(coreelement); //core element
function child_recursion(element) {
nodes.push(element);
if (element.children!=null){
element.children.forEach(function(child) {
child_recursion(child);});
};
}
child_recursion(coreelement);
return nodes;
}
function positions(d,pos_y) { //pos_y is the target position (y) of the element
var sum_y;
sum_y=rowheight; //the sum of all vertical space used by that element
if (d.parent!=null)
{d.x=d.parent.x+10;}
else
{ d.x=0;}
d.y=pos_y;
if (d.children) {
d.children.forEach(function(child) {
child.parent=d;
sum_y+=positions(child,pos_y+sum_y);
});
}
return sum_y;
}
坐标的计算工作正常。然后,我使用以下代码绑定数据:
d3.json("data/kdsf-neu.json", function(error, data) {
root = data;
root.x0 = 0;
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 = myTreeLayout(root);
/*,links = tree.links(nodes);*/
// Update the nodes…
var node = vis.selectAll("g.node_coltree")
.data(nodes, function(d) {
return d.Nodeid;
});
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g").classed("g.node_coltree", true)
.attr("x", function(d) {
return d.x;
})
.attr("y", function(d) {
return d.y;
})
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
nodeEnter.append("svg:rect")
.attr("x", function(d) {
return 0;
})
.attr("y", function(d) {
return 0;
})
.attr("width", 10)
.attr("height", rowheight - 2)
.attr("class", function(d) {
var codearray = jQuery.makeArray(d.tags);
if ($.inArray(tags.Extended, codearray) >= 0) {
return 'erweiterungsteil_Fill';
} else if ($.inArray(tags.NotIncluded, codearray) >= 0) {
return 'nichtAufgenommen_Fill';
} else if ($.inArray(tags.Optional, codearray) >= 0) {
return 'optional_Fill';
} else if ($.inArray(tags.obligatorischWennVorhanden, codearray) >= 0) {
return 'obligatorisch_Fill';
} else if ($.inArray(tags.teilweiserForschungsbezug, codearray) >= 0) {
return 'pubSchale2_Fill';
} else if ($.inArray(tags.PublikationenSchale2, codearray) >= 0) {
return 'pubSchale2_Fill';
} else if ($.inArray(tags.Included, codearray) >= 0) {
return 'aufgenommen_Fill';
} else {
return "#FEFEFE";
}
})
.on("click", click)
.on("mouseover", function(d) {
updatedetails(d);
});
nodeEnter.append("text")
.attr("x", function(d) {
return 12;
})
.attr("y", function(d) {
return 7;
})
.text(function(d) {
return d.name;
})
.attr("dy", "0.35em")
.on("mouseover", function(d) {
updatedetails(d);
});
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
// 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();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
当我启动脚本时,元素位于正确的位置:
(因为我不允许发布图片,这里有链接:)
但是,当我单击某个元素时,退出功能似乎不起作用:
https://www.dropbox.com/s/3phyu3tx9m13ydt/2.PNG?dl=0
单击元素后,子元素位于相应的目标位置,但旧元素不会退出。 我试图接近coltree的例子,因此我也在每次点击后完全重新计算整个树:
function update(source) {
// Compute the new tree layout.
var nodes = myTreeLayout(root);
我已经检查过nodes元素,它在点击后只保存所需的元素。因此我怀疑退出功能和自定义布局存在一些问题。
相关问题: 我的问题可能与这个问题有关:
D3.js exit() not seeming to get updated information
因此,我按照那里的步骤进行了操作:
我在调用数据时使用自定义(外部计算单个)索引:
.data(nodes , function(d) { return d.Nodeid; });
我在添加节点时添加了分类函数:
var nodeEnter = node.enter().append("g").classed("g.node_coltree",true)
但是,元素仍保留在图表中 - 没有人退出。
我是否需要在布局功能中添加一些内容,d3知道如何使用现有元素?还是别的错了?任何帮助都非常感谢。
单击根节点时,所有子元素都应该消失。同样,在打开节点时,元素应该移动。两者似乎都没有发生。
答案 0 :(得分:0)
你的代码中有一个相当简单的错误。
这是一个更新的小提琴:http://jsfiddle.net/nhgejcy0/11/
唯一的区别是:
var nodeEnter = node.enter().append("g").classed("node_coltree", true)
.attr("x", function (d) {
return d.x;
})
.attr("y", function (d) {
return d.y;
})
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
具体来说,第一行改为:
var nodeEnter = node.enter().append("g").classed("g.node_coltree", true)
为:
var nodeEnter = node.enter().append("g").classed("node_coltree", true)
在您的版本中,您使用classed(...)
向g.node_coltree
的节点添加了一个类,但是您使用的.node_coltree
选择了不匹配的类,因此您的代码只是不断向svg添加越来越多的g
元素。您的enter
选项包含g
数组中每个项目的新nodes
元素。这意味着您的update
和exit
选项始终为空,导致无法删除任何内容。
我通过检查DOM并发现每次折叠或展开节点时都添加了g
元素的新列表来找到这一点。如果选择正常,则不会发生这种情况。然后,只需要跟踪选择是否错误,或者在创建节点时是否附加了不同的属性。在这种情况下,看起来属性创建不正确。