当数据通过`selectAll.data(data)`

时间:2016-05-10 05:47:25

标签: d3.js

我正在制作一个d3图,我有多个元素,在绘制时可能会重叠。

每个元素都会渲染一个时间轴,并有多个图形单元(起始圆,直线和结束圆),如下所示:

O----------O     O
       O--------------------O
      O-------O-----O-------O

例如,第三行有两个时间线绘图元素,它们重叠,因为第二个时间轴的开始时间是在第一个时间轴的结束时间之前。请注意,第一行中的第二个时间轴只有开始时间(因为结束时间和开始时间相同)。

现在,下面的代码通过将DOM节点移动到其父节点的最后一个子节点,将时间轴的元素带到鼠标悬停的前面。

d3.selection.prototype.moveToFront = function() {
    return this.each(function(){
   this.parentNode.appendChild(this);
  });
}; 

但问题在于,这并没有改变绑定数据的顺序,并打破了整体情节。

每个绘图元素在dom中具有特定顺序,该顺序以相同顺序绑定到d3数据。当上面的代码更改顺序以将任何元素带到前面时它会破坏顺序,它仍然认为子项的顺序是相同的,这是错误的。

以下是一个描述问题的JSFiddle示例: https://jsfiddle.net/pixelord/g2gt1f03/57/

一旦我更改了dom元素,如何保留数据顺序? 谢谢。

2 个答案:

答案 0 :(得分:2)

不要自己做html更新,让d3这样做,记住d3代表数据驱动文档,所以重写你的问题

  

在鼠标悬停时将选择的数据移动到最后一个位置,然后重新渲染图形

想象一下,您的数据是[0,1,2,3],当您将鼠标悬停在代表第二个数据的任何元素上时,您将第二个数据移动到最后一个位置,即[0,2,3,1],而且几乎就是< / p>

.on("mouseover", function() {
  var selection = d3.select(this);
  var d = selection.datum()

  // find d in data, extract it and push it
  var index = data.indexOf(d)
  var extract = data.splice(index, 1)
  data = data.concat(extract)
  draw()
});

接下来当您绑定数据时,请确保添加一种方法来区分使用发送到.data()函数的第二个参数完成的两个状态,这可能是一个id

var data = [
  [5, 8, 6],
  [10, 10, 6],
  [20, 25, 6],
  [23, 27, 6]
].map(function (d, i) {
    return {
    id: i,
    x1: d[0],
    y1: d[2],
    x2: d[1],
    y2: d[2]
  }
});
// ...
var itemGroup = maingroup.selectAll(".itemGroup")
  .data(data, function (d) { return d.id })

最后你需要告诉d3我们已经修改了元素的顺序,并且它需要做你手工做的事情,这是重新排序元素

// update
itemGroup.order()

Demo

答案 1 :(得分:1)

我喜欢Mauricio解决问题的方式。

然而,经过一些调查后,我才知道我可以在绑定数据时指定键值。所以这是我的解决方案,没有重新排序数据本身:

  1. 我为每个数据对象添加了一个唯一的键值属性。
  2. 我在绑定数据时指定键值,如

    data(data_list,funcion(d){return d.keyValue})

  3. 问题得到解决。