javascript - 使用 selection.filter 获得多项选择的最佳方式
问题描述
我只是在玩 d3.js,我想知道selection.filter()
在单个循环中获得多个选择的最佳使用方式或其他方式是什么。
从数组的角度思考,我会用它Array.prototype.filter()
来获取所需的数据集。每当我需要基于不同条件的多组数据时,我会使用Array.prototype.reduce()
并将数据推送到累加器中的相应键作为对象。
因此,使用 D3 选择,我将如何过滤并在单个循环中获取不同条件的选择。(类似于d3.reduce()
)。这样我就可以在过滤的选择上使用选择方法。我阅读了文档,我知道从 v4 开始,选择不再是数组。
解决方案
您的问题很有趣:如何过滤选择并在单个循环中填充多个选择。但是,我必须说,它很有趣,但可能毫无用处:惯用的方式非常简单,只需要做几个过滤器:
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
。
我的第一个想法是使用selection.merge
,但我不得不迅速放弃它,因为正如 Bostock(D3 创建者)所说,
selection.merge 的当前实现只处理两个选择具有相同结构(即相同的父项和索引)的情况,并返回具有相同结构的选择。
所以,我决定只连接节点,你可以用Array.prototype.concat
. 这就是想法:首先,我们声明一些空选择......
let foo = d3.selectAll(null);
let bar = d3.selectAll(null);
let baz = d3.selectAll(null);
然后,each
在更大的选择中使用 an ,我们检查一个属性(这里命名为label
)并相应地连接节点:
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 个圆圈,所有圆圈都是黑色的。然后,在 中each
,我们填充三个选择(circlesFoo
和circlesBar
)circlesBaz
,分别用绿色、红色和蓝色绘制:
const data = [{
x: 20,
label: "foo"
},
{
x: 50,
label: "bar"
}, {
x: 80,
label: "foo"
}, {
x: 110,
label: "baz"
}, {
x: 140,
label: "bar"
}, {
x: 170,
label: "baz"
}, {
x: 200,
label: "baz"
}, {
x: 230,
label: "foo"
}, {
x: 260,
label: "foo"
}, {
x: 290,
label: "bar"
},
];
const svg = d3.select("svg");
const circles = svg.selectAll(null)
.data(data)
.enter()
.append("circle")
.attr("cy", 75)
.attr("r", 10)
.attr("cx", d => d.x);
let circlesFoo = d3.selectAll(null);
let circlesBar = d3.selectAll(null);
let circlesBaz = d3.selectAll(null);
circles.each(function(d) {
if (d.label === "foo") {
circlesFoo = d3.selectAll(circlesFoo.nodes().concat(this))
} else if (d.label === "bar") {
circlesBar = d3.selectAll(circlesBar.nodes().concat(this))
} else {
circlesBaz = d3.selectAll(circlesBaz.nodes().concat(this))
}
});
circlesFoo.style("fill", "green");
circlesBar.style("fill", "red");
circlesBaz.style("fill", "blue");
<svg></svg>
<script src="https://d3js.org/d3.v5.min.js"></script>
推荐阅读
- dictionary - 当我尝试从 @agm/core/services/google-maps-types 导入 {google} 时出现此错误
- python - 从嵌套字典中递归删除 None 值或 None 键
- c# - 如何在将文本添加到 Xamarin 表单中的条目之前加载视图
- wordpress - FacetWP 地图更改地图标记基于方面选择
- javascript - 图片加载不出来
功能 - c# - 如何在 WPF 应用程序中的项目之间传递属性?
- mongodb - MongoDB和并发
- vue.js - 如何控制“b-form-checkbox-group”中多个复选框的呈现
- three.js - Autodesk forge viewer api v7.* 对齐多个 2d dwg 模型
- angular - 当焦点出现在 Mat-Select 上时,在 Angular 中打开 Mat-Select 下拉菜单