gpt4 book ai didi

filter - D3中如何根据父是否被过滤来过滤子?

转载 作者:行者123 更新时间:2023-12-05 08:24:09 24 4
gpt4 key购买 nike

我使用 D3 中的 Zoomable Icicle 布局示例来可视化文件夹层次结构。我想根据文件夹是否在特定日期之前被访问来隐藏某些文件夹 - 使用过滤器可以工作:

.filter(function (d) {
return d.dateAccessed > formattedD; //formattedD is the date two weeks ago
})

我需要做的是隐藏已隐藏的父文件夹的子文件夹(子文件夹和文件),或者如果显示父文件夹则显示子文件夹。

如何将父项的过滤器值分配给其子项?

谢谢!

最佳答案

还有一个用于 hat trick ...

最后一个选项,我之后想到的,我认为它是赢家。它不仅更接近您使用的示例,而且适用于任何 D3 分层布局功能。秘诀:让 D3 为您完成这项工作。具体来说:

  1. 使用 D3 布局函数计算仅包含满足过滤条件的节点的新布局;
  2. 对于属于新布局的所有节点,显示它们并更新它们的位置/大小。
  3. 在新布局中隐藏没有布局数据的节点。

诀窍在第 1 步;让布局功能只包含满足过滤条件的节点。 .children() method分区布局函数允许您指定布局函数如何识别子项。示例中的函数是:

var partition = d3.layout.partition()
.children(function(d) { return isNaN(d.value) ? d3.entries(d.value) : null; })
.value(function(d) { return d.value; });

意思是它只希望节点包含一个子元素数组或一个数字。如果你只想包含一些 child ,你所要做的就是遍历子元素数组并返回你想要的:

var filteredPartition = d3.layout.partition()
.value(function(d) { return d.value; })
.children(function(d){

if isNaN(d.value) {
var filteredChildren = [];
d3.entries(d.value).forEach(function(d2){
if (d2.dateAccessed < formattedD) filteredChildren.push(d);
//a.push(d) adds d to the end of the array 'a'
});
return filteredChildren;
//Note that the nodes which PASS the filter test will be shown
//and the nodes that fail will be hidden; make sure your filter
//is written in the way you want.
}
else return null;
});

当然,这假定一个简单的数据结构,即数字数组的数组。对于您的数据结构,您必须更新两个子访问器函数。

在子访问器函数中应用过滤器的好处在于,一旦元素未通过过滤器,它的子子元素也会自动排除,因为布局函数甚至看不到它们。 (无需递归函数:D3 为您代劳!)

要应用新的过滤布局,创建一个将布局函数作为参数的更新函数:

var updateLayout(layoutFunction){

var newRects = rects.data(layoutFunction(rootData), keyFunction)
.transition().duration(500)
.style("visibility", "visible")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return y(d.y); })
.attr("width", function(d) { return x(d.dx); })
.attr("height", function(d) { return y(d.dy); });

newRects.exit()
.transition().duration(500)
.style("visibility", "hidden");
//don't delete, just hide; these will still be part
//of the rects selection for the next update.
}

要应用过滤器,请调用 updateLayout(filteredPartition);要恢复到未过滤的版本,请调用 updateLayout(partition)(其中 partition 是示例中原始布局函数的名称)。

只剩下几个细节了。首先,要开始这一切,我需要拥有在原始布局中使用的根数据对象。这意味着它需要在图形首次初始化时保存在一个变量中。其次,我们需要一个关键函数,可以将新布局数据对象与旧布局数据对象相匹配。以下是必要的声明和更新的初始化方法以包含它们:

var keyFunction = function(d) {

return d.FileName;
//or something else from your data structure that uniquely
//identifies each file

//You could even do it recursively to get the full, unique file path:
//return (d.parent == null) ?
// "d.FileName" : keyFunction(d.parent) + "/" + d.FileName;
}
var rootData;

d3.json("readme.json", function(error, root) {
rootData = d3.entries(root)[0];
rect = rect.data(partition(rootData), keyFunction)
.enter()
//...and the rest is the same
}

我不知道这是否算作一个简单的解决方案,但与其他两个答案相比,它是简单的。

无论如何,如果您实际实现了这些方法中的任何一个或所有,我很乐意看到最终产品,前提是您能够在线发布它。

关于filter - D3中如何根据父是否被过滤来过滤子?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20788827/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com