我在这个网站上看到很多问题,询问如何根据绑定的数据将元素附加到选择中。 (例如,Here's one。)所有人似乎都主张过滤数据以删除不应绑定元素的项目。
我不能这样做,因为过滤掉数据中的项目会改变所有元素的索引,而我的代码依赖于索引。我意识到我可以为每个项目创建一个元组,包含一个数据及其原始位置,然后安全地过滤,但我想知道是否有更好的方法。
如何在不过滤数据的情况下根据绑定的数据追加元素?
我的具体情况:我有一个2D阵列。每个子数组都绑定到<g>
,并且对于每个子数组中的每个元素,计算并绘制<path>
。 <path>
的{{1}}取决于子数组中元素的索引。
对于任何给定子数组中的某些元素,我不希望绘制transform
。我意识到我可以在不添加<path>
的情况下完成此任务(例如,通过使<path>
完全半透明),但我正在尝试减少层次结构中元素的数量。
目前,我将所有数据绑定到<path>
,然后根据其数据过滤并删除某些<path>
。尽管......这似乎并不是特别有效。
答案 0 :(得分:1)
正如我在comment中所说,一种可能的解决方案是保留两个数组,一个用于附加元素(过滤的一个),另一个用于引用它们的索引(原始索引)。这种方法是否密集(关于处理器资源)?这取决于您的实际代码和案例。有时,性能较差的代码可能会比应该更快的代码执行得更好(例如,添加元素并在以后删除它们...浏览器通常比操作实际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>