d3.js 自定义布局 exit() 不工作
d3.js custom layout exit() not working
我想构建一个 Windows 资源管理器,如分层可视化。由于我想手动计算 x 和 y 坐标,因此我根据此处描述的第一个示例创建了自定义布局:
我的布局函数如下所示:
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;
});
}
当我启动脚本时,元素位于正确的位置:
(因为我不允许post图片,这里放一个link:)
但是,当我点击一个元素时,退出功能似乎不起作用:
https://www.dropbox.com/s/3phyu3tx9m13ydt/2.PNG?dl=0
点击某个元素后,子元素位于合适的目标位置,但旧元素不退出。
我尽量接近 coltree 的示例,因此每次单击后我也会完全重新计算整棵树:
function update(source) {
// Compute the new tree layout.
var nodes = myTreeLayout(root);
我已经检查了节点元素,点击后它只包含所需的元素。因此,我怀疑退出功能和自定义布局存在一些问题。
相关问题:
我的问题可能与这个问题有关:
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)
仍然,元素留在图中 - none 正在退出。
我是否需要向布局函数添加一些东西,让 d3 知道如何处理现有元素?还是有其他问题?非常感谢任何帮助。
编辑:这是 jsfiddle:
http://jsfiddle.net/MathiasRiechert/nhgejcy0/8/
单击根节点时,所有子元素都应该消失。同样,当打开一个节点时,元素应该是移动的。两者似乎都没有发生。
你的代码中有一个相当简单的错误。
这是更新后的 fiddle: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(...)
将 class 添加到 g.node_coltree
的节点,但您选择使用 .node_coltree
,这并没有匹配,因此您的代码只是不断向 svg 添加越来越多的 g
元素。您的 enter
选择包含 nodes
数组中每个项目的新 g
元素。这意味着您的 update
和 exit
选择始终为空,因此不会删除任何内容。
我通过检查 DOM 发现了这一点,发现每次折叠或展开节点时都会附加一个新的 g
元素列表。如果选择工作正常,就不会发生这种情况。然后只需跟踪选择是否错误,或者您是否在创建节点时附加了不同的属性。在这种情况下,看起来属性创建不正确。
我想构建一个 Windows 资源管理器,如分层可视化。由于我想手动计算 x 和 y 坐标,因此我根据此处描述的第一个示例创建了自定义布局:
我的布局函数如下所示:
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;
});
}
当我启动脚本时,元素位于正确的位置:
(因为我不允许post图片,这里放一个link:)
但是,当我点击一个元素时,退出功能似乎不起作用:
https://www.dropbox.com/s/3phyu3tx9m13ydt/2.PNG?dl=0
点击某个元素后,子元素位于合适的目标位置,但旧元素不退出。 我尽量接近 coltree 的示例,因此每次单击后我也会完全重新计算整棵树:
function update(source) {
// Compute the new tree layout.
var nodes = myTreeLayout(root);
我已经检查了节点元素,点击后它只包含所需的元素。因此,我怀疑退出功能和自定义布局存在一些问题。
相关问题: 我的问题可能与这个问题有关:
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)
仍然,元素留在图中 - none 正在退出。
我是否需要向布局函数添加一些东西,让 d3 知道如何处理现有元素?还是有其他问题?非常感谢任何帮助。
编辑:这是 jsfiddle: http://jsfiddle.net/MathiasRiechert/nhgejcy0/8/
单击根节点时,所有子元素都应该消失。同样,当打开一个节点时,元素应该是移动的。两者似乎都没有发生。
你的代码中有一个相当简单的错误。
这是更新后的 fiddle: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(...)
将 class 添加到 g.node_coltree
的节点,但您选择使用 .node_coltree
,这并没有匹配,因此您的代码只是不断向 svg 添加越来越多的 g
元素。您的 enter
选择包含 nodes
数组中每个项目的新 g
元素。这意味着您的 update
和 exit
选择始终为空,因此不会删除任何内容。
我通过检查 DOM 发现了这一点,发现每次折叠或展开节点时都会附加一个新的 g
元素列表。如果选择工作正常,就不会发生这种情况。然后只需跟踪选择是否错误,或者您是否在创建节点时附加了不同的属性。在这种情况下,看起来属性创建不正确。