【问题标题】:d3: need different behaviour on click depending on node's class attributed3:根据节点的类属性需要不同的点击行为
【发布时间】:2013-09-13 00:56:58
【问题描述】:

我觉得这是我的一个非常基本的误解。

我正在使用此树可视化:http://bl.ocks.org/mbostock/4339083

当用户单击具有子节点的节点时,原始版本的节点会打开和折叠。我想让它使单击没有子节点的节点具有其他效果(具体来说,我希望它在另一个窗口中打开图像)。

所以,这里是分配点击功能的地方:

var nodeEnter = node.enter().append("g")
    .attr("class", "node")
    .attr("class", function(n) {
        if (n.children) {
            return "inner node"
        } else {
            return "leaf node"
        }
        })
    .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
    .on("click", click);

我添加了第二类分配来区分有子节点和没有子节点。

这是我修改后的点击功能:

function click(d) {
  if (d.attr("class") == "inner node") {
    if (d.children) {
      d._children = d.children;
      d.children = null;
    } else {
      d.children = d._children;
      d._children = null;
    }
  } else if (d.attr("class") == "leaf node") {
    // open image
  }
  update(d);
}

我添加了外部 if 语句来区分这两种节点。

所以,当我点击时,目前没有任何效果。我假设我的 'd.attr("class") == "inner node"' 出现错误,要么是因为该类属性的分配不起作用,要么是因为我写的是胡言乱语。但是,当我将其更改为“节点”时,它也不起作用。

我还想到,分配可能会因所有节点开始折叠这一事实而失败 - 因此“n.children”可能会返回 false,即使有子节点也是如此。让孩子崩溃会影响这个吗?

非常感谢任何帮助。

------------------** 编辑 **------------ ------------------

通过玩了一下,我想我已经确定我应该使用“d.class”,而不是“d.attr('class')”。但是,这仍然无法正常工作。我假设我误解了 d 在这里代表什么 - 对吗?

------------------** 编辑 2 **------------ ------------------

好的,我的第一次编辑是错误的。不过多亏了祈祷者,我已将代码更改为:

function click(d) {
  if (d.children || d._children) {
    if (d.children) {
      d._children = d.children;
      d.children = null;
    } else {
      d.children = d._children;
      d._children = null;
    }
  } else {
    d3.select( this ).attr("fill", "#CCCCCC");
  }
  update(d);
}

现在可以了。但是,与我的预期相反,我更改的是文本填充,而不是圆形填充。这是为什么?文本和圆圈是可以点击的不同区域,但无论我点击哪一个,总是会改变文本。我假设“this”指的是节点,而不是特定的圆圈或文本,那么为什么它会选择一个而不是另一个呢?

【问题讨论】:

  • 您能否提供一些上下文与 JSFiddle 包含您的问题的最小示例?我已经回答了,但没有更多信息,我只能猜测。
  • bl.ocks.org/mbostock/4339083 非常相似。我已将其放入 jsFiddle 并进行了一些更改以适应我当前的问题,但树形图未显示(抱歉,我之前没有使用过 jsFiddle)。我想我只是误解了 jsFiddle 的工作原理。这是:jsfiddle.net/v8S9j/1。我电脑上的版本会显示树,但不会响应点击。
  • 只要您在群组 (svg:g) 上注册您的点击处理程序,this 就应该引用群组。请参阅此fiddle 进行澄清。因此,您无法通过this 真正设置视觉属性,因为它指的是本身不可见的组。另请注意,视觉属性(您将放入 CSS 中的内容)是通过 .style() 而不是 .attr() 更改的。

标签: javascript d3.js


【解决方案1】:

编辑:您正在覆盖您的课程。它应该是

var nodeEnter = node.enter().append("g")
    .attr("class", function(n) {
    if (n.children) {
        return "node inner node"
    } else {
        return "node leaf node"
    }
    });

还要注意innernode 是两个不同的类,因为它们之间有空格。


简短回答:您似乎试图在 D3 选择之外的其他东西上使用 .attr()

更长的答案:在 D3 的函数中,大多数情况下您有两个参数:di,其中 d 指的是与您的节点关联的数据,i 是您的节点的索引。

因此,例如,内部节点上的点击处理程序如下所示:

d3.selectAll( ".inner.node" ).on( "click", function( d, i ) { /* do somehting */ });

d 不是节点的 SVG 元素(“视图”),而是它背后的数据(“模型”)。因此它没有.attr() 方法。要使用它,您必须选择您的视图:

d3.select( this ).attr(...);

我想这就是你的错误的根源。

但是我也想知道为什么你必须使用节点的类而不只是在你的点击处理程序中检查d.children

【讨论】:

  • 嗯,诚实的答案是我使用了这个类,因为我在某个地方找到了一个如何做到这一点的例子,我认为它可能会起作用。我是否认为 n 与该示例中的 d 相同?如果是这样,我有一个问题,因为点击函数中的 d.children 被用于确定孩子是否折叠,而不是它们是否存在。
【解决方案2】:

您在此处操作的d 参数是绑定到该特定元素的数据,而不是元素本身。您可以以this 的身份访问该元素,并通过选择它对其执行通常的D3 操作。也就是说,在您的 click 处理程序中,您可以执行类似的操作。

function click() {
  if(d3.select(this).attr("class") == "inner node") {
    // do something
  }
}

the documentation 中的更多详细信息。另一个答案向您展示了处理这些事情的更好方法 - 您可以直接访问需要区分不同行为的数据,因此无需通过 DOM 元素进行代理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-29
    • 1970-01-01
    相关资源
    最近更新 更多