web-dev-qa-db-ja.com

選択したノード、そのリンク、およびその子をD3強制有向グラフで強調表示する

私は、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);
        });
    };
}

Uncaught TypeError: Cannot call method 'setProperty' of undefined source.targetから読み込んだ要素に不透明度を設定しようとするとエラーが発生します。これはそのノードをd3オブジェクトとしてロードする正しい方法ではないのではないかと思いますが、リンクのターゲットまたはソースに一致するノードを見つけるためにすべてのノードを再度反復処理せずにロードする別の方法を見つけることはできません。パフォーマンスを適切に保つために、必要以上にすべてのノードを反復処理したくありません。

http://mbostock.github.com/d3/ex/chord.html からリンクをフェードする例を取り上げました。

enter image description here

ただし、接続された子ノードを変更する方法は示していません。

これを解決または改善する方法に関する良い提案は猛烈に支持されます:)

69

エラーは、データオブジェクトに関連付けられたDOM要素ではなく、データオブジェクト(d.sourceおよびd.target)を選択しているためです。

強調表示された行は機能していますが、おそらく次のようにコードを単一の反復に結合します。

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

各ノードの隣接ノードを知る必要があるため、隣接ノードを強調表示するのはより困難です。この情報は、ノードの配列とリンクの配列としてすべてを持っているため、現在のデータ構造を使用して判断するのはそれほど簡単ではありません。少しDOMを忘れて、2つのノード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を直接テストするか、 !important css :hoverスタイルを使用します。)

コードで最後に変更するのは、不透明度ではなく塗りつぶし不透明度とストローク不透明度を使用することです。これらはパフォーマンスがはるかに優れているためです。

88
mbostock