有条件地追加而不进行筛选



我在这个网站上看到了很多问题,询问如何根据元素绑定到的数据将元素附加到选择中。(例如,这里有一个。他们似乎都主张首先过滤数据,以删除不应绑定元素的项目。

我不能这样做,因为过滤掉数据中的项目会在之后更改所有元素的索引,并且我的代码依赖于索引。我意识到我可以为每个项目创建一个元组,其中包含一个基准面及其原始位置,然后安全地过滤,但我想知道是否有更好的方法。

如何在不先过滤数据的情况下根据要绑定的数据附加元素?


的情况是:我有一个2D阵列。每个子数组绑定到一个<g>,对于每个子数组中的每个元素,计算并绘制一个<path><path>transform取决于子数组中元素的索引。

对于任何给定子数组中的某些元素,我不希望绘制<path>。我意识到我可以在不附加<path>的情况下完成此操作(例如,通过使<path>完全半透明),但我正在尝试减少层次结构中的元素数量。

目前,我将所有数据绑定到一个<path>,然后根据其数据过滤并删除某些<path>。不过,这似乎不是特别有效...

正如我在评论中所说,一种可能的解决方案是保留两个数组,一个用于附加元素(过滤后的元素),另一个用于引用它们的索引(原始数组)。这种方法是否密集(关于处理器资源)?这取决于您的实际代码和大小写。有时,看起来性能较差的代码可能比应该更快的代码性能更好(例如,附加元素并在以后删除它们......浏览器通常比操作实际的 DOM 元素更快处理数组和对象)。

无论如何,这是另一种方法:创建引用原始数据中每个元素的索引的新过滤数据。

例如,在下面的代码片段中,我有这个数据集:

var originalData = [16, 18, 4, 17, 12, 2, 15, 13, 8, 19, 17, 3, 8]; 

我们将创建一个过滤数组,仅保留小于 10 的值。但是,在过滤之前,我们将创建一个保存值和原始索引的对象:

var filteredData = originalData.map((d, i) => ({
value: d,
index: i
})).filter(e => e.value < 10);

然后,您只需要访问index即可知道原始索引。

这是演示,点击圆圈:

var svg = d3.select("svg");
var originalData = [16, 18, 4, 17, 12, 2, 15, 13, 8, 19, 17, 3, 8];
var filteredData = originalData.map((d, i) => ({
value: d,
index: i
})).filter(e => e.value < 10);
var circles = svg.selectAll("foo")
.data(filteredData)
.enter()
.append("circle")
.attr("r", 20)
.attr("cy", 40)
.attr("cx", (d, i) => 40 + 60 * i)
.attr("fill", "teal")
.attr("cursor", "pointer")
.on("click", function(d) {
console.log("My original index is " + d.index)
})
.as-console-wrapper { max-height: 20% !important;}
<script src="https://d3js.org/d3.v4.js"></script>
<svg></svg>

最新更新