web-dev-qa-db-ja.com

svgの外側のボタンからd3のノードをクリックする

D3を使用して力指向グラフを作成し、ノードのIDを通常のdivで表示しました。 divでIDがクリックされたノードを強調表示する必要があります。ノードのIDを検索し、通常のJavaScriptを使用してクリックしようとしましたが、機能しません。

22
Rahul Rout

より一般的には、ユーザーが要素[〜#〜] a [〜#〜]を操作する場合、関連する要素をどのように選択(および変更)しますか[〜#〜] b [ 〜#〜]?これを達成する方法はたくさんありますが、ここに3つの一般的なアプローチがあります。

オプション1.1対1のマッピングの場合、IDで選択します。

[〜#〜] a [〜#〜]の各要素に[〜#〜] b [〜#〜]の対応する要素が1つだけある場合は、 _<div id="foo">_を選択するためのd3.select("#foo")などのIDによる関連要素B。

このアプローチでは、 selection.attr を使用して[〜#〜] b [〜#〜]の各要素のIDを設定する必要があります。これは、データに_d.name_や_d.id_などの固有の一意の識別子がある場合に最も簡単です。

_b.attr("id", function(d) { return d.id; });
_

次に、要素のクリックを有効にするには[〜#〜] a [〜#〜][〜#〜] b [〜#〜]の対応する要素の塗りつぶしの色を変更しますselection.on を使用してクリックリスナーを登録し、IDで選択します。

_a.on("click", function(d) {
  d3.select("#" + d.id).style("fill", "red");
});
_

識別子は一意で 有効の両方である必要があります。たとえば、IDは数字ではなく文字で始まる必要があり、スペースを含めることはできません。データに一意の識別子がまだない場合は、インデックスから次のような識別子を生成できます。

_b.attr("id", function(d, i) { return "b-" + i; });
_

そして後で、要素[〜#〜] a [〜#〜]が同じ順序であると仮定すると、

_a.on("click", function(d, i) {
  d3.select("#b-" + i).style("fill", "red");
});
_

データ配列を反復処理 して一意の識別子を生成することもできます。

オプション2.1対多のマッピングの場合、クラスで選択します。

_<div class="foo">_などのクラス "foo"の要素を選択するには、d3.selectAll(".foo")と言います。 [〜#〜] a [〜#〜]のいずれかの要素が[〜#〜] b [〜#〜]の複数の要素に対応する場合は、このアプローチを使用します。たとえば、学生間の関係を示す力指向のグラフがある場合、各学生の年に基づいてノードに色を付け、凡例を使用して各年の可視性を切り替えることができます。

前のアプローチと同様に、 selection.attr を使用して「class」属性を設定できます。この場合、クラス属性は一意ではないため、データの_d.type_プロパティから取得される可能性があります。

_b.attr("class", function(d) { return d.type; })
_

データのさまざまなカテゴリ属性に複数の凡例がある場合は、より具体的にクラス名の前に付けることもできます。学生年の例を続けるには:

_b.attr("class", function(d) { return "year-" + d.year; })
_

Class属性を設定すると、以前に設定したクラスが置き換えられるため、要素に複数のクラスを適用する場合は、「class」属性を設定するときに、それらをスペースで結合する必要があります。

次に、要素のクリックを有効にするには[〜#〜] a [〜#〜][〜#〜] b [〜#〜]の対応する要素の塗りつぶしの色を変更します、selection.onを使用してクリックリスナーを登録し、クラスで選択します。

_a.on("click", function(d) {
  d3.selectAll("." + d.type).style("fill", "red");
});
_

ここでは、 select ではなく selectAll を使用していることに注意してください。これは、最初の要素だけでなく、対応するすべての要素を選択するためです。繰り返しますが、クラス属性が valid であることを確認する必要があります。

オプション3.その他すべてについては、データを選択してフィルタリングします。

前の2つのアプローチでは、IDとクラスが生成されるため、ブラウザーは[〜#〜] b [〜#〜]の要素にインデックスを付けて、効率的に選択できます。要素の数が少ない場合、またはより一般的な選択メソッドが必要な場合は、「id」または「class」属性の指定を省略して、 selection.filter で手動で選択するだけです。

[〜#〜] a [〜#〜]daの各要素に関連付けられたデータムと、[〜#〜の各要素に関連付けられたデータムを呼び出しましょう。 ] b [〜#〜]db。これで、dadbと一致したときにtrueを返す式を定義するだけです。たとえば、タイプでフィルタリングしたい場合:

_a.on("click", function(da) {
  b.filter(function(db) { return da.type == db.type; }).style("fill", "red");
});
_

最初の2つのオプションが推奨されますが、範囲スライダーがあり、量的変数に基づいてフィルター処理する場合など、手動フィルタリングが役立つ場合があります。

73
mbostock

あなたが書くとき:

…そして通常のJavaScriptを使用してそれをクリックしようとしました…

どういう意味ですか?

次のようなコードを書いたことを意味する場合:

_mySVGElement.click();
_

それがあなたの問題です。すべてのDOM要素に_<button>_や_<input…>_のようなclick()メソッドがあるわけではありません。代わりに、 独自のクリックイベントをシミュレートして発生させる

_function simulateClick(elementToClick){
  var evt = document.createEvent("MouseEvents");
  evt.initMouseEvent("click", true, true, window,
    0, 0, 0, 0, 0, false, false, false, false, 0, null);
  var canceled = !elementToClick.dispatchEvent(evt);
  return canceled; //Indicate if `preventDefault` was called during handling
}
_
4
Phrogz