71

我正在研究 D3 中的力有向图。我想通过将所有其他节点和链接设置为较低的不透明度来突出显示鼠标悬停的节点、其链接及其子节点。

在这个例子中,http://jsfiddle.net/xReHA/,我能够淡出所有的链接和节点,然后淡入连接的链接,但是,到目前为止,我还不能优雅地淡入作为当前鼠标悬停节点的子节点的连接节点。

这是代码中的关键功能:

function fade(opacity) {
    return function(d, i) {
        //fade all elements
        svg.selectAll("circle, line").style("opacity", opacity);

        var associated_links = svg.selectAll("line").filter(function(d) {
            return d.source.index == i || d.target.index == i;
        }).each(function(dLink, iLink) {
            //unfade links and nodes connected to the current node
            d3.select(this).style("opacity", 1);
            //THE FOLLOWING CAUSES: Uncaught TypeError: Cannot call method 'setProperty' of undefined
            d3.select(dLink.source).style("opacity", 1);
            d3.select(dLink.target).style("opacity", 1);
        });
    };
}

Uncaught TypeError: Cannot call method 'setProperty' of undefined当我尝试在从 source.target 加载的元素上设置不透明度时出现错误。我怀疑这不是将该节点加载为 d3 对象的正确方法,但是如果不再次遍历所有节点以找到与链接的目标或源匹配的节点,我就找不到另一种加载它的方法。为了保持性能合理,我不想过多地迭代所有节点。

我以淡化来自http://mbostock.github.com/d3/ex/chord.html的链接为例:

在此处输入图像描述

但是,这并没有显示如何更改连接的子节点。

任何关于如何解决或改进这个问题的好建议都将受到热烈的支持:)

4

1 回答 1

93

该错误是因为您选择的是数据对象(d.source 和 d.target),而不是与这些数据对象关联的 DOM 元素。

您已经使行突出显示工作,但我可能会将您的代码合并到一个迭代中,如下所示:

 link.style("opacity", function(o) {
   return o.source === d || o.target === d ? 1 : opacity;
 });

突出显示相邻节点更难,因为您需要了解每个节点的邻居。用您当前的数据结构来确定这些信息并不容易,因为您所拥有的只是一个节点数组和一个链接数组。暂时忘记 DOM,并问自己如何确定两个节点a和是否b是邻居?

function neighboring(a, b) {
  // ???
}

一种昂贵的方法是遍历所有链接并查看是否存在连接 a 和 b 的链接:

function neighboring(a, b) {
  return links.some(function(d) {
    return (d.source === a && d.target === b)
        || (d.source === b && d.target === a);
  });
}

(这假设链接是无向的。如果您只想突出前向连接的邻居,则消除 OR 的后半部分。)

如果您必须经常这样做,一种更有效的计算方法是拥有一个允许恒定时间查找以测试 a 和 b 是否是邻居的映射或矩阵。例如:

var linkedByIndex = {};
links.forEach(function(d) {
  linkedByIndex[d.source.index + "," + d.target.index] = 1;
});

现在你可以说:

function neighboring(a, b) {
  return linkedByIndex[a.index + "," + b.index];
}

因此,您现在可以遍历节点并正确更新它们的不透明度:

node.style("opacity", function(o) {
  return neighboring(d, o) ? 1 : opacity;
});

(您可能还想对鼠标悬停的链接本身进行特殊处理,方法是为 中的每个节点设置一个自链接linkedByIndex,或者在计算样式时直接测试d,或者使用 !important css:hover样式。)

我要在您的代码中更改的最后一件事是使用填充不透明度和笔划不透明度而不是不透明度,因为它们提供了更好的性能。

于 2012-01-08T18:57:34.570 回答