如何在 D3.js 中更改径向树的根
How to change the root of a radial tree in D3.js
我在 D3.js
中的径向树有问题
我想将选定的节点(单击时)放在径向树的中心,并让整个树重新适应这个新设置。在我的更新函数中,我可以将根设置为所选节点:
root = source;
然而,这只显示了所选节点和子节点,但我希望父节点(及其子节点)位于所选节点的顶部,所选节点的子节点位于其底部。
我尝试过的是从父节点的子节点数组中删除所选节点。然后将这个更改后的父节点作为所选节点的子节点推送,但这会产生递归错误。
var index = source.parent.children.indexOf(source);
source.parent.children.splice(0, 1);
source.parent.parent = source;
source.children.push(source.parent);
完整代码here
如果有任何帮助或指示,我将不胜感激。
谢谢
这是一个负责重新排列的递归函数:
function makeRoot(source) {
if (!source.parent) return; //nothing to do if source is already root
makeRoot(source.parent); //flip the higher branches recursively so that the parent becomes root of the tree
var index = source.parent.children.indexOf(source);
source.parent.children.splice(index, 1); //corrected here: you need to remove the right element from the children list
source.parent.parent = source;
source.children.push(source.parent);
delete source.parent; //added: now that the original parent is linked, make source the root of the tree
}
我不知道如何强制将原始节点的 children 绘制到南部,将其余节点绘制到北部。首先要做的是 知道 每个节点必须在哪一侧(这很简单:默认情况下所有节点都是 "north",然后从 [=13] 访问子树=], 在调用 makeRoot
之前,告诉他们是 "south")。但在那之后,我对 d3 的树布局不够熟悉,无法强制执行 "north/south" 约束。
update 为north-south方向,你可以试试下面的方法:
- 保留一个指针
oldParent=source.parent
指向所选节点的原始parent
- 布局完成后,在更新 svg 之前,计算
offsetX= 90- oldParent.x
(parent 位置与北轴之间的差异——注意:我不确定北轴是 90°,但它应该是 0、90、180 或 270 中的一个。只需尝试所有这些 ;) )
将所有节点移动 offsetX
(保持角度在 0 到 359 之间):
nodes.forEach(function(d) {
d.x = (d.x + offsetX) % 360;
});
然后你可以更新svg:整棵树应该旋转,这样原来的parent指向北方......这应该足以获得你想要的视觉效果。
更新 #2 另一种实现 north-south 对齐的方法。
请在此处查看 Fiddle:https://jsfiddle.net/qo4w0ktn/4/
思路是计算原children中left-most和right-most叶的夹角,旋转整张图,直到这两个夹角的平均值指向南。这意味着您需要跟踪树中的 "original" children,这是通过我的 d.real_children
属性 完成的。函数 leftmostLeaf
和 rightmostLeaf
很简单(参见 fiddle)。
function rotateSouth(source, nodes) {
var lx = leftmostLeaf(source);
var rx = rightmostLeaf(source);
if (lx>rx) rx += 360; //this happens if the interval overlap angle 0
var offsetX= 180- (lx+rx)/2; //the median point (=(lx+rx)/2) should be pushed south (=180)
nodes.forEach(function(d) {
d.x = (d.x + offsetX) % 360; //rotate every node by the same offset
});
}
我在 D3.js
中的径向树有问题我想将选定的节点(单击时)放在径向树的中心,并让整个树重新适应这个新设置。在我的更新函数中,我可以将根设置为所选节点:
root = source;
然而,这只显示了所选节点和子节点,但我希望父节点(及其子节点)位于所选节点的顶部,所选节点的子节点位于其底部。
我尝试过的是从父节点的子节点数组中删除所选节点。然后将这个更改后的父节点作为所选节点的子节点推送,但这会产生递归错误。
var index = source.parent.children.indexOf(source);
source.parent.children.splice(0, 1);
source.parent.parent = source;
source.children.push(source.parent);
完整代码here
如果有任何帮助或指示,我将不胜感激。
谢谢
这是一个负责重新排列的递归函数:
function makeRoot(source) {
if (!source.parent) return; //nothing to do if source is already root
makeRoot(source.parent); //flip the higher branches recursively so that the parent becomes root of the tree
var index = source.parent.children.indexOf(source);
source.parent.children.splice(index, 1); //corrected here: you need to remove the right element from the children list
source.parent.parent = source;
source.children.push(source.parent);
delete source.parent; //added: now that the original parent is linked, make source the root of the tree
}
我不知道如何强制将原始节点的 children 绘制到南部,将其余节点绘制到北部。首先要做的是 知道 每个节点必须在哪一侧(这很简单:默认情况下所有节点都是 "north",然后从 [=13] 访问子树=], 在调用 makeRoot
之前,告诉他们是 "south")。但在那之后,我对 d3 的树布局不够熟悉,无法强制执行 "north/south" 约束。
update 为north-south方向,你可以试试下面的方法:
- 保留一个指针
oldParent=source.parent
指向所选节点的原始parent - 布局完成后,在更新 svg 之前,计算
offsetX= 90- oldParent.x
(parent 位置与北轴之间的差异——注意:我不确定北轴是 90°,但它应该是 0、90、180 或 270 中的一个。只需尝试所有这些 ;) ) 将所有节点移动
offsetX
(保持角度在 0 到 359 之间):nodes.forEach(function(d) { d.x = (d.x + offsetX) % 360; });
然后你可以更新svg:整棵树应该旋转,这样原来的parent指向北方......这应该足以获得你想要的视觉效果。
更新 #2 另一种实现 north-south 对齐的方法。
请在此处查看 Fiddle:https://jsfiddle.net/qo4w0ktn/4/
思路是计算原children中left-most和right-most叶的夹角,旋转整张图,直到这两个夹角的平均值指向南。这意味着您需要跟踪树中的 "original" children,这是通过我的 d.real_children
属性 完成的。函数 leftmostLeaf
和 rightmostLeaf
很简单(参见 fiddle)。
function rotateSouth(source, nodes) {
var lx = leftmostLeaf(source);
var rx = rightmostLeaf(source);
if (lx>rx) rx += 360; //this happens if the interval overlap angle 0
var offsetX= 180- (lx+rx)/2; //the median point (=(lx+rx)/2) should be pushed south (=180)
nodes.forEach(function(d) {
d.x = (d.x + offsetX) % 360; //rotate every node by the same offset
});
}