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

查看:289
本文介绍了在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);
        });
    };
}

我收到一个 Uncaught TypeError: 'setProperty'的undefined 错误,当我尝试设置不透明度从我从source.target加载的元素。我怀疑这不是正确的方式加载该节点作为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一秒钟,问自己如何确定两个节点 a b 是否是邻居? / p>

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 :hover style。)

(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.)

我最后要改变的代码是使用fill-opacity和stroke - 透明度,而不是透明度,因为这些提供了更好的性能。

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天全站免登陆