有条件地附加而不过滤

时间:2017-04-02 00:06:54

标签: javascript jquery d3.js svg conditional-statements

我在这个网站上看到很多问题,询问如何根据绑定的数据将元素附加到选择中。 (例如,Here's one。)所有人似乎都主张过滤数据以删除不应绑定元素的项目。

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

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

我的具体情况:我有一个2D阵列。每个子数组都绑定到<g>,并且对于每个子数组中的每个元素,计算并绘制<path><path>的{​​{1}}取决于子数组中元素的索引。

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

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

1 个答案:

答案 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>