我怎样才能用d3把一个圆圈带到前面?

IT技术 javascript d3.js visualization
2021-02-08 05:59:25

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

这是一个代码示例:

   .on("mouseover", function() { 
    d3.select(this).attr("r", function(d) { return 100; })
  })

我尝试使用 sort 和 order 方法,但它们不起作用。我很确定我没有做对。有什么想法吗?

4个回答

TL; 博士

使用最新版本的 D3,您可以selection.raise()按照tmpearce其答案中的解释使用请向下滚动并投票!


原答案

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

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

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

circles.on("mouseover",function(){
  var sel = d3.select(this);
  sel.moveToFront();
});

编辑:正如Henrik Nordberg所建议的,有必要使用.data(). 这对于不失去对元素的约束是必要的。请阅读 Henrick 的回答(并点赞!)了解更多信息。作为一般建议,始终使用.data()when 将数据绑定到 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);
        }
    });
};
嗨@christopher Chiche,我在这里尝试了您的解决方案:stackoverflow.com/questions/33000725/...但仍然无法改变折线图的位置。想法?
2021-03-22 05:59:25
请参阅下面的@Henrik Nordberg 回答。这样做您的数据将不同步
2021-04-02 05:59:25
如果节点上的其他事件处理程序被移动,则在 IE 中不起作用......它们被删除
2021-04-05 05:59:25
我也需要反过来:这就是我所做的: d3.selection.prototype.moveToBack = function() { return this.each(function() { var firstChild = this.parentNode.firstChild; if (firstChild) { this.parentNode.insertBefore(this, firstChild); } }); };
2021-04-07 05:59:25

从 d3 版本 4 开始,有一组内置函数可以处理此类行为,而无需自己实现。有关更多信息,请参阅d3v4 文档

长话短说,要将元素放在前面,请使用 selection.raise()

selection.raise()

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

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

迈克为我们提供了保障!!
2021-03-18 05:59:25
这是从 v4.x 开始的正确方法。
2021-03-22 05:59:25

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

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

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

你能详细说明..要传递哪些数据?
2021-04-03 05:59:25
@DavidWilton 迟到总比没有好,我在我的回答中添加了对这个答案的引用。
2021-04-08 05:59:25

根据我对 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;
            }
          }
        });
      })
你能在这里详细说明一下..你的代码中的可见性是什么。“节点”是你的 svg 元素的一类吗?我在 IE 上遇到了同样的问题
2021-03-21 05:59:25
我如何vis从鼠标悬停事件外部获取引用我试图visdragstart事件内部找到,但在任何地方都找不到。 this引用我想要带到顶部的元素。
2021-03-21 05:59:25
vis 是包含要重新排序的元素的父元素的 D3 选择。'node' 是这些元素应该具有的 CSS 类。
2021-03-27 05:59:25
IE9 的绝佳解决方案。
2021-03-28 05:59:25
更简洁的排序功能: function(a,b) {s = selected.id; return (a.id == s) - (b.id == s);}
2021-04-06 05:59:25