如何用d3将圆圈带到前面?

are*_*eke 63 javascript visualization d3.js

首先,我使用d3.js在数组中显示不同大小的圆圈.鼠标悬停时,我希望将鼠标悬空变大,这是我可以做的,但我不知道如何把它带到前面.目前,一旦渲染,它就隐藏在多个其他圈子后面.我怎样才能解决这个问题?

这是一个代码示例:

   .on("mouseover", function() { 
    d3.select(this).attr("r", function(d) { return 100; })
  })
Run Code Online (Sandbox Code Playgroud)

我尝试使用排序和顺序方法,但它们不起作用.我很确定我没有正确地做到这一点.有什么想法吗?

Chr*_*che 117

您将不得不更改对象的顺序,并使鼠标悬停的圆圈成为添加的最后一个元素.正如您在此处所见:https://gist.github.com/3922684并且根据nautat的建议,您必须在主脚本之前定义以下内容:

d3.selection.prototype.moveToFront = function() {
  return this.each(function(){
    this.parentNode.appendChild(this);
  });
};
Run Code Online (Sandbox Code Playgroud)

那么你只需要在鼠标悬停时调用moveToFront对象上的函数(比如说circles):

circles.on("mouseover",function(){
  var sel = d3.select(this);
  sel.moveToFront();
});
Run Code Online (Sandbox Code Playgroud)

编辑:正如Henrik Nordberg所建议的那样,有必要使用第二个参数将数据绑定到DOM .data().这对于不失去对元素的约束是必要的.请阅读Henrick的答案(并进行投票!)了解更多信息.作为一般建议,始终使用将.data()数据绑定到DOM时的第二个参数,以便充分利用d3的完整性能.


编辑: 正如Clemens Tolboom所提到的,反向函数将是:

d3.selection.prototype.moveToBack = function() {
    return this.each(function() {
        var firstChild = this.parentNode.firstChild;
        if (firstChild) {
            this.parentNode.insertBefore(this, firstChild);
        }
    });
};
Run Code Online (Sandbox Code Playgroud)

  • 我也需要反向:这就是我所做的:`d3.selection.prototype.moveToBack = function(){return this.each(function(){var firstChild = this.parentNode.firstChild; if(firstChild){this. parentNode.insertBefore(this,firstChild);}}); };` (6认同)
  • 请参阅下面的@Henrik Nordberg答案.这样做会导致您的数据不同步 (2认同)

小智 23

如果使用该moveToFront()方法,请确保指定data()join方法的第二个参数,否则您的数据将与DOM不同步.

d3.js将您parse()创建的DOM元素的数据(提供给a )方法连接起来.如果您按照上面的建议操作DOM,d3.js将不知道哪个DOM元素对应于什么数据'point',除非您为data()调用中的每个数据'point'指定唯一值,因为API参考显示:

.data(data, function(d) { return d.name; })

  • 这确实需要添加到已接受的答案中. (4认同)

tmp*_*rce 20

从d3版本4开始,有一组内置函数可以处理这种类型的行为,而无需自己实现.有关详细信息,请参阅d3v4文档.

长话短说,要把元素带到前面,使用 selection.raise()

selection.raise()

按顺序重新插入每个选定元素作为其父元素的最后一个子元素.相当于:

selection.each(function() {
this.parentNode.appendChild(this);
});


Ily*_*din 13

根据我对IE9的痛苦经历,使用parentNode.appendChild可能会导致节点中的事件处理程序丢失.所以我倾向于使用另一种方法,即对节点进行排序,使所选节点高于其他节点:

     .on("mouseover", function(selected) {
        vis.selectAll('.node')
        .sort(function(a, b) {
          if (a.id === selected.id) {
            return 1;
          } else {
            if (b.id === selected.id) {
              return -1;
            } else {
              return 0;
            }
          }
        });
      })
Run Code Online (Sandbox Code Playgroud)