Javascript 使用selection.filter获取多个选择的最佳方法
我只是在玩d3.js,我想知道使用Javascript 使用selection.filter获取多个选择的最佳方法,javascript,d3.js,Javascript,D3.js,我只是在玩d3.js,我想知道使用selection.filter()或其他方法在一个循环中获得多个选择的最佳方法是什么 从数组的角度考虑,我将使用array.prototype.filter()获取所需的数据集。每当我需要基于不同条件的多组数据时,我都会使用Array.prototype.reduce(),并将数据作为对象推送到累加器中的各个键 因此,对于D3选择,我将如何在单个循环中过滤并获得不同条件的选择(类似于D3.reduce())。这样我就可以在过滤后的选择上使用选择方法。我阅读了文
selection.filter()
或其他方法在一个循环中获得多个选择的最佳方法是什么
从数组的角度考虑,我将使用array.prototype.filter()
获取所需的数据集。每当我需要基于不同条件的多组数据时,我都会使用Array.prototype.reduce()
,并将数据作为对象推送到累加器中的各个键
因此,对于D3选择,我将如何在单个循环中过滤并获得不同条件的选择(类似于
D3.reduce()
)。这样我就可以在过滤后的选择上使用选择方法。我阅读了文档,我意识到v4中的选择不再是数组。D3js有一个过滤功能用于选择
来自
选择。过滤器(过滤器)
过滤选择,返回一个新的选择,该选择仅包含指定过滤器为true的元素。筛选器可以指定为选择器字符串或函数。如果过滤器是一个函数,则会依次对每个选定元素进行计算,并传递当前数据(d)、当前索引(i)和当前组(节点),将其作为当前DOM元素(节点[i])
这意味着,假设您有一组形状(例如圆),您打算根据数据附加这些形状,您可以利用filter函数指定一个函数,如果该函数返回true,它将为该点附加圆
比如说,
svg.selectAll("dot")
.data(data)
.enter()
.append("circle")
.filter(function(d) { return d.value < 100 }) //filters those data points below value of 100
.style("fill", "red")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); });
不幸的是,您没有提到任何代码或特定示例来更好地指导您。您的问题很有趣:如何在单个循环中过滤一个选择并填充多个选择。然而,我必须说,它不仅有趣,而且可能毫无用处:惯用的方法非常简单,只需要做几个过滤器:
const bigSelection = d3.selectAll(foo);
const smallSelection1 = bigSelection.filter(function with condition 1);
const smallSelection2 = bigSelection.filter(function with condition 2);
const smallSelection3 = bigSelection.filter(function with condition 3);
//etc...
然而,出于好奇:这可能吗?是的。但是使用selection.each
,而不是selection.filter
我的第一个想法是使用选择.merge
,但我不得不很快放弃它,因为正如Bostock(D3创建者)所说
selection.merge的当前实现仅处理两个选择具有相同结构(即相同的父项和索引)的情况,并返回具有相同结构的选择
因此,我决定只连接节点,这可以通过Array.prototype.concat
实现。这就是想法:首先,我们声明一些空的选择
let foo = d3.selectAll(null);
let bar = d3.selectAll(null);
let baz = d3.selectAll(null);
然后,在较大的选择中使用每个
,检查属性(此处命名为标签
),并相应地连接节点:
bigSelection.each(function(d) {
if (d.label === "foo") {
foo = d3.selectAll(foo.nodes().concat(this))
} else if (d.label === "bar") {
bar = d3.selectAll(bar.nodes().concat(this))
} else {
baz = d3.selectAll(baz.nodes().concat(this))
}
});
这是一个演示。大选择包含10个圆圈,全部为黑色。然后,在每个
中,我们填充三个选项(circlesFoo
、circlesBar
和circlesBaz
),分别用绿色、红色和蓝色绘制:
const数据=[{
x:20,
标签:“foo”
},
{
x:50,
标签:“酒吧”
}, {
x:80,
标签:“foo”
}, {
x:110,
标签:“baz”
}, {
x:140,
标签:“酒吧”
}, {
x:170,
标签:“baz”
}, {
x:200,
标签:“baz”
}, {
x:230,
标签:“foo”
}, {
x:260,
标签:“foo”
}, {
x:290,
标签:“酒吧”
},
];
const svg=d3.选择(“svg”);
const circles=svg.selectAll(空)
.数据(数据)
.输入()
.附加(“圆圈”)
.attr(“cy”,75)
.attr(“r”,10)
.attr(“cx”,d=>d.x);
设circlesFoo=d3.selectAll(null);
设circlesBar=d3。选择全部(空);
设circlesBaz=d3.selectAll(null);
圆。每个(函数(d){
如果(d.标签==“foo”){
circlesFoo=d3.selectAll(circlesFoo.nodes().concat(此))
}否则如果(d.标签==“条”){
circlesBar=d3.selectAll(circlesBar.nodes().concat(此))
}否则{
circlesBaz=d3.selectAll(circlesBaz.nodes().concat(此))
}
});
圆形样式(“填充”、“绿色”);
圆形条样式(“填充”、“红色”);
圆形样式(“填充”、“蓝色”)代码>
Null选择,这是我没有想到的。我不知道这是可能的。好的。让我试试this@DharanBro看看我写的关于selectAll(null)
的这个Q/a对:正如你提到的惯用方法,你不认为没有必要为不同的条件反复运行过滤器吗?当bigSelection很大时,它会影响性能。为什么D3不想用一个内置的api来处理这个问题呢?有趣的是,这比惯用的方法慢50倍,因为在循环过程中创建的所有临时选择在下一次迭代中都会被丢弃:不过,这可以通过在过滤过程中先设置节点数组来避免,然后再选择(请参阅测试用例“.each()optimized”)。优化版本的执行速度是惯用解决方案的两倍。@DharanBro。这类问题的回答只是为了挑战,但应该添加“警告选择器,不要这样做…”。
bigSelection.each(function(d) {
if (d.label === "foo") {
foo = d3.selectAll(foo.nodes().concat(this))
} else if (d.label === "bar") {
bar = d3.selectAll(bar.nodes().concat(this))
} else {
baz = d3.selectAll(baz.nodes().concat(this))
}
});