d3:根据节点的类属性,在点击时需要不同的行为

时间:2013-09-12 14:16:00

标签: javascript d3.js

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

我正在使用这个树形象化: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”)==“内部节点”正在变为假,因为该类属性的赋值不起作用,或者因为我写的是胡言乱语。但是,当我将它更改为“节点”时它也不起作用。

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

任何帮助都非常感激。

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

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

----------------------------- ** EDIT 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”指的是节点,而不是圆圈或文本,所以为什么它选择一个而不是另一个?

2 个答案:

答案 0 :(得分:2)

编辑:你正在覆盖你的课程。它应该读

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

答案 1 :(得分:1)

您在此处操作的d参数是绑定到该特定元素的数据,而不是元素本身。您可以将元素作为this访问,并通过选择它来执行常规的D3操作。也就是说,在你的click处理程序中,你可以做这样的事情。

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

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