web-dev-qa-db-ja.com

D3フォースレイアウトリンクの中央に矢印を表示します

私はD3を使用して、この例に非常によく似た力指向グラフを描画しています。 http://bl.ocks.org/mbostock/1153292

リンクの最後ではなく、中央に矢印を配置しようとしています。

マーカーのattr("refX", 0)で遊んでもあまり役に立ちません。これは絶対的なものであり、リンクの長さに相対的ではないためです。私のリンクの長さはさまざまです。

私はぐるぐる回っていました、そして私の最善の考えはこれに従ってlink.attr("marker-end", ...)link.attr("marker-segment", ...)に置き換えることでした (真ん中の十字を探してくださいグラフ)。しかし、これは機能していないようです。これはSVG2ドラフトの一部であるためだと思いますが、私のブラウザはより低いバージョンをサポートしていますか? (私はChromeところで)の最新バージョンを使用しています。

リンクの中央に矢印を配置するにはどうすればよいですか?

17
talkol

マーカーを端に配置する代わりに、線の中央に1つの点を使用して線(<polyline>または<path>)を作成し、 marker-mid を使用して矢じりを適用します。

このデモ for この回答 私の場合、この手法を使用して、パスの長さに沿ってmarker-midとともに複数の内部ポイントを作成します。多数ではなく、単一の「ウェイポイント」を作成するだけです。

編集:これは私が何を意味するかを示す既存のデモへの簡単なハックです:

デモ: http://jsfiddle.net/tk7Wv/2/

Arrowheads in the middle of curves

唯一の変更点は次のとおりです。

  1. marker-endmarker-midに変更し、
  2. パス生成コードを変更して、1つではなく2つの円弧(中央で接続)を作成します。

線に必要な曲がりの量に基づいて適切な中点を選択するには、Superbogglyが示すような単純な三角法が必要になります。

19
Phrogz

私はOPです。この回答は、同じ質問を持つ他の人のために、上記の優れた回答への追加にすぎません。

答えは、アークリンクのあるグラフでこれを実現する方法を示しています。ストレートリンクがある場合は、受け入れられた回答を少し変更する必要があります。こうやって:

ストレートリンクはおそらくlineで実装されているため、polylineに変換する必要があります。そのようです:

// old: svg.selectAll(".link").data(links).enter().append("line")
svg.selectAll(".link").data(links).enter().append("polyline")

次に、これに従ってポリラインをエンコードする必要があります example なので、lineをエンコードする元のコード:

force.on("tick", function() {
   link.attr("x1", function(d) {return d.source.x;})
       .attr("y1", function(d) {return d.source.y;})
       .attr("x2", function(d) {return d.target.x;})
       .attr("y2", function(d) {return d.target.y;});

に変更:

force.on("tick", function() {
   link.attr("points", function(d) {
      return d.source.x + "," + d.source.y + " " + 
             (d.source.x + d.target.x)/2 + "," + (d.source.y + d.target.y)/2 + " " +
             d.target.x + "," + d.target.y; });

そして最後に、変換を忘れないでくださいmarker-endからmarker-mid

// old: link.attr("marker-end",
link.attr("marker-mid",

道を示してくれた@Phrogzの功績。

15
talkol

私はPhrogzとは少し異なるアプローチを取りました。パスのマーカーを削除し、代わりに、円弧の中点に移動し、ストロークが表示されない新しいパスを使用して描画してみました。中点の計算は少し厄介なので、アークの特性を変更したい場合は、Phrogzのアプローチまたはいくつかのハイブリッドを使用した方がよい場合があります。

この場合、トリガーはそれほど悪くはありません。よく見ると、リンクの生成に使用される円弧が、同じ半径とノード間の距離を持つ円からのものであることがわかります。したがって、正三角形があり、実際に行う必要があるのは、リンク線分の中点から円弧の中点までの距離を計算することだけです。

説明する図が必要だと思います。

Find arc midpoint したがって、三角形ABCは正三角形であり、ECはABを二等分します。 AとBの座標があるので、Mを見つけるのは簡単です(座標を平均します)。これは、AからBへの傾き(デルタy /デルタx)もわかっているため、MからEへの傾きは負の逆数であることを意味します。 MとEへの傾きを知っているということは、私たちがほぼそこにいることを意味します。どこまで行くかを知る必要があります。

そのために、ACMが30-60-90の三角形であるという事実を使用します。

| CM | = sqrt(3)* | AM |

しかし| AM | = | AB |/2および| CE | = | AB |

そう

| ME | = | AB | --sqrt(3)* | AB |/2

この長さを意味のあるものにするために、傾斜ベクトルの長さで正規化する必要があります。これは、円の半径と同じであることがすでにわかっています。

とにかく、それをすべてまとめると、次のようになります。

var markerPath = svg.append("svg:g").selectAll("path.marker")
  .data(force.links())
  .enter().append("svg:path")
  .attr("class", function(d) { return "marker_only " + d.type; })
  .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });


... later in the tick handler

markerPath.attr("d", function(d) {
  var dx = d.target.x - d.source.x,
      dy = d.target.y - d.source.y,
      dr = Math.sqrt(dx * dx + dy * dy);

  // We know the center of the arc will be some distance perpendicular from the
  // link segment's midpoint. The midpoint is computed as:
  var endX = (d.target.x + d.source.x) / 2;
  var endY = (d.target.y + d.source.y) / 2;

  // Notice that the paths are the arcs generated by a circle whose 
  // radius is the same as the distance between the nodes. This simplifies the 
  // trig as we can simply apply the 30-60-90 triangle rule to find the difference
  // between the radius and the distance to the segment midpoint from the circle 
  // center.
  var len = dr - ((dr/2) * Math.sqrt(3));

  // Remember that is we have a line's slope then the perpendicular slope is the 
  // negative inverse.
  endX = endX + (dy * len/dr);
  endY = endY + (-dx * len/dr);

  return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + endX + "," + endY;
});

それをチェックしてください ここ 。マーカーパスのパスcssが透明な赤に設定されていることに注意してください。通常、線を非表示にするには、ストロークを「なし」に設定します。

10
Superboggly