2012-01-05 49 views
66

我正在研究D3中的力指向图。我想通过将所有其他节点和链接设置为较低的不透明度来突出显示mouseover'd节点,其链接及其子节点。在D3强制指示图中突出显示所选节点,其链接及其子节点

在这个例子中,我可以淡出所有的链接和节点,然后淡入连接的链接,但到目前为止,我还没有能够优雅地淡入所有连接的孩子节点当前鼠标悬停的节点。

这是从代码中键功能:

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

enter image description here

但是,这并不表明如何改变所连接的子节点。

如何解决或改善这个有什么好建议,将奋力upvoted :)

回答

86

的错误是因为你选择与相关的数据对象(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或通过使用a!important css :hover style。)

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

+1

这很有用@mbostock,非常感谢你:D我用你的解决方案更新了[jsfiddle](http://jsfiddle.net/xReHA/1/)。 – 2012-01-09 07:46:38

+1

在链接中删除了不必要的样式调用:http://jsfiddle.net/xReHA/2/ – 2012-01-09 08:08:44

+0

Mike,该解决方案非常美丽。只是在说'。 – Vivek 2012-07-11 20:04:08

相关问题