【问题标题】:Highlight selected node, its links, and its children in a D3 force directed graph在 D3 力有向图中突出显示选定节点、其链接及其子节点
【发布时间】:2012-02-03 01:47:55
【问题描述】:

我正在研究 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);
        });
    };
}

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

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

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

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

【问题讨论】:

    标签: javascript d3.js highlight force-layout chord


    【解决方案1】:

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

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

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

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

    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,或者使用!重要的 CSS :hover 样式。)

    我要在您的代码中更改的最后一件事是使用 fill-opacity 和 stroke-opacity 而不是 opacity,因为它们提供了更好的性能。

    【讨论】:

    • 效果很好@mbostock,非常感谢:D 我已经用你的解决方案更新了the jsfiddle
    • 迈克,这个解决方案简直太棒了。只是说。
    • Mike,有没有办法从数据对象获取到 DOM 元素?我已经编写了一个方法来让我所有相邻的数据节点到一个“鼠标悬停”节点。如何更改属于这些数据节点的 DOM 元素的 CSS/Style/Class/...?
    • @fgysin 以下是一些可能的方法:stackoverflow.com/questions/11206015/…
    • 正如 kdazzle 上面所说,那个 fiddle 试图动态加载 json 数据,并且数据不再存在并且 jsfiddle 也不想加载 X-domain。这是一个内联数据的更新小提琴:jsfiddle.net/tristanreid/xReHA/636
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-27
    • 2019-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多