【问题标题】:How can I bring a circle to the front with d3?如何使用 d3 将圆圈置于最前面?
【发布时间】:2013-01-05 02:14:58
【问题描述】:

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

这是一个代码示例:

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

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

【问题讨论】:

  • 我还是 d3.js 的新手,但我认为您应该能够通过隐藏/显示元素以重新渲染它来实现这一点?
  • 从这篇文章看来,将元素重新附加到 svg 会产生这种效果。 stackoverflow.com/questions/482115/…
  • d3.selection.prototype.moveToFront = function() { return this.each(function() { this.parentNode.appendChild(this); }); };然后你可以说 selection.moveToFront()。
  • 查看 Ian 如何在此支流条目中使用此方法:enjalot.com/tributary/3651456
  • Fiddle here 使用 moveToFront 方法。

标签: javascript d3.js visualization


【解决方案1】:

TL;DR

使用最新版本的 D3,您可以使用 selection.raise(),正如 tmpearceits answer 中所解释的那样。请向下滚动并投票!


原答案

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

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

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

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

编辑: 正如Henrik Nordberg 所建议的,有必要使用.data() 的第二个参数将数据绑定到DOM。这对于不失去对元素的约束是必要的。请阅读 Henrick 的回答(并投赞成票!)以获取更多信息。作为一般建议,在将数据绑定到 DOM 时,始终使用 .data() 的第二个参数,以利用 d3 的全部性能功能。


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

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

【讨论】:

  • 我也需要反过来:这就是我所做的:d3.selection.prototype.moveToBack = function() { return this.each(function() { var firstChild = this.parentNode.firstChild; if (firstChild) { this.parentNode.insertBefore(this, firstChild); } }); };
  • 请参阅下面的@Henrik Nordberg 回答。这样做您的数据将不同步
  • 嗨@christopher Chiche,我在这里尝试了您的解决方案:stackoverflow.com/questions/33000725/… 但仍然无法更改折线图的位置。想法?
  • 如果节点上的其他事件处理程序被移动,则在 IE 中不起作用...它们被删除
【解决方案2】:

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

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

selection.raise()

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

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

【讨论】:

  • 迈克帮我们搞定了!!
  • 这是从 v4.x 开始的正确方法。
【解决方案3】:

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

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

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

【讨论】:

  • 你能详细说明..要传递哪些数据吗?
  • @DavidWilton 迟到总比没有好,我在回答中添加了对这个答案的引用。
【解决方案4】:

根据我对 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;
            }
          }
        });
      })

【讨论】:

  • 你能在这里详细说明一下吗..你的代码中有什么。 'node' 是你的 svg 元素的一类吗?我在 IE 上遇到了同样的问题
  • vis 是包含要重新排序的元素的父元素的 D3 选择。 'node' 是这些元素应该具有的 CSS 类。
  • 更简洁的排序功能:function(a,b) {s = selected.id; return (a.id == s) - (b.id == s);}
  • IE9 的绝佳解决方案。
  • 如何从鼠标悬停事件之外获得对vis 的引用?我试图在dragstart 事件中找到vis,但我在任何地方都找不到。 this 引用了我想要置顶的元素。
猜你喜欢
  • 2012-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-06
  • 1970-01-01
  • 2014-07-08
  • 2013-01-23
相关资源
最近更新 更多