在 D3 力有向图中突出显示选定节点、其链接及其子节点 [英] Highlight selected node, its links, and its children in a D3 force directed graph

查看:22
本文介绍了在 D3 力有向图中突出显示选定节点、其链接及其子节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am working on a force directed graph in D3. I want to highlight the mouseover'd node, its links, and its child nodes by setting all of the other nodes and links to a lower opacity.

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

In this example, http://jsfiddle.net/xReHA/, I am able to fade out all of the links and nodes then fade in the connected links, but, so far, I haven't been able to elegantly fade in the connected nodes that are children of the currently mouseover'd node.

这是代码中的关键功能:

This is the key function from the code:

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 对象的正确方法,但是如果不再次迭代所有节点以找到与链接的目标或源匹配的节点,我就找不到另一种加载它的方法.为了保持性能合理,我不想过多地迭代所有节点.

I am getting a Uncaught TypeError: Cannot call method 'setProperty' of undefined error when I try to set the opacity on an element I loaded from the source.target. I suspect this is not the right way to load that node as a d3 object, but I can't find another way to load it without iterating over all of the nodes again to find the ones that match the link's target or source. To keep the performance reasonable, I don't want to iterate over all the nodes more than necessary.

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

然而,这并没有显示如何改变连接的子节点.

However, that doesn't show how to alter the connected child nodes.

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

Any good suggestions on how to solve or improve this will be furiously upvoted :)

推荐答案

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

The error is because you are selecting the data objects (d.source and d.target) rather than the DOM elements associated with those data objects.

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

You've got the line highlighting working, but I would probably combine your code into a single iteration, like this:

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

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

Highlighting the neighboring nodes is harder because what you need to know the neighbors for each node. This information isn't that easy to determine with your current data structures, since all you have as an array of nodes and an array of links. Forget the DOM for a second, and ask yourself how you would determine whether two nodes a and b are neighbors?

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

一种代价高昂的方法是遍历所有链接,看看是否存在连接 a 和 b 的链接:

An expensive way to do that is to iterate over all of the links and see if there is a link that connects a and b:

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

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

(This assumes that links are undirected. If you only want to highlight forward-connected neighbors, then eliminate the second half of the OR.)

一种更有效的计算方法(如果您必须经常这样做)是使用地图或矩阵来允许恒定时间查找来测试 a 和 b 是否是邻居.例如:

A more efficient way of computing this, if you have to do it frequently, is to have a map or a matrix which allows constant-time lookup to test whether a and b are neighbors. For example:

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

现在你可以说:

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

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

And thus, you can now iterate over the nodes and update their opacity correctly:

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

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

(You may also want to special-case the mouseovered link itself, either by setting a self-link for every node in linkedByIndex, or by testing for d directly when computing the style, or by using a !important css :hover style.)

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

The last thing I would change in your code is to use fill-opacity and stroke-opacity rather than opacity, because these offer much better performance.

这篇关于在 D3 力有向图中突出显示选定节点、其链接及其子节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆