Javascript 在 D3 力有向图中突出显示选定节点、其链接及其子节点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8739072/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Highlight selected node, its links, and its children in a D3 force directed graph
提问by Christopher Manning
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.
我正在研究 D3 中的力有向图。我想通过将所有其他节点和链接设置为较低的不透明度来突出显示鼠标悬停的节点、其链接及其子节点。
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.
在这个例子中,http://jsfiddle.net/xReHA/,我能够淡出所有的链接和节点,然后淡入连接的链接,但是,到目前为止,我还没有能够优雅地淡入作为当前鼠标悬停节点的子节点的连接节点。
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);
});
};
}
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.
Uncaught TypeError: Cannot call method 'setProperty' of undefined
当我尝试为从 source.target 加载的元素设置不透明度时出现错误。我怀疑这不是将该节点加载为 d3 对象的正确方法,但是如果不再次遍历所有节点以找到与链接的目标或源匹配的节点,我就找不到另一种加载它的方法。为了保持性能合理,我不想过多地迭代所有节点。
I took the example of fading the links from http://mbostock.github.com/d3/ex/chord.html:
我以从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 :)
关于如何解决或改进此问题的任何好的建议都将得到热烈的支持:)
回答by mbostock
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.
错误是因为您正在选择数据对象(d.source 和 d.target)而不是与这些数据对象关联的 DOM 元素。
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;
});
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?
突出显示相邻节点更难,因为您需要知道每个节点的邻居。用您当前的数据结构确定此信息并不容易,因为您拥有的所有信息都是节点数组和链接数组。暂时忘记 DOM,问问自己如何确定两个节点a
和是否b
是邻居?
function neighboring(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:
一种昂贵的方法是遍历所有链接,看看是否有一个链接连接 a 和 b:
function neighboring(a, b) {
return links.some(function(d) {
return (d.source === a && d.target === b)
|| (d.source === b && d.target === a);
});
}
(This assumes that links are undirected. If you only want to highlight forward-connected neighbors, then eliminate the second half of the OR.)
(这假设链接是无向的。如果您只想突出显示前向连接的邻居,则消除 OR 的后半部分。)
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:
如果您必须经常这样做,则一种更有效的计算方法是使用地图或矩阵来允许恒定时间查找来测试 a 和 b 是否是邻居。例如:
var linkedByIndex = {};
links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
Now you can say:
现在你可以说:
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;
});
(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.)
(您可能还想对鼠标悬停链接本身进行特殊处理,方法是为 中的每个节点设置自链接linkedByIndex
,或者d
在计算样式时直接测试,或者使用 !important css:hover
样式。)
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.
我要在您的代码中更改的最后一件事是使用 fill-opacity 和 stroke-opacity 而不是 opacity,因为它们提供了更好的性能。