19

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

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

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

私はグーグルで調べてきましたが、私の最良のアイデアは、このlink.attr("marker-end", ...)に従って置き換えることでした(グラフの中央にある十字を探してください)。しかし、これは機能していないようです.. SVG2ドラフトのみの一部であるためだと思いますが、私のブラウザは下位バージョンをサポートしていますか? (私はChromeの最新バージョンを使用しています)。link.attr("marker-segment", ...)

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

4

3 に答える 3

17

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

回答は、アーク リンクを含むグラフでこれを達成する方法を示しています。直接リンクがある場合は、受け入れられた回答を少し変更する必要があります。こうやって:

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

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

次に、この例に従ってポリラインをエンコードする必要があるため、エンコードする元のコードは次の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の功績。

于 2013-04-02T07:47:36.527 に答える
10

私は Phrogz とは少し異なるアプローチを取りました。パスのマーカーを削除しようとしましたが、代わりに、円弧の中点に行き、ストロークが見えない新しいパスを使用して描画しました。中点の計算は少し面倒なので、円弧の特性を変更したい場合は、Phrogz のアプローチまたはハイブリッドを使用する方がよいかもしれません。

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

説明するには図が必要だと思います:

円弧の中点を見つける したがって、三角形 ABC は正三角形で、EC は AB を二等分します。A と B の座標があるので、M を見つけるのは簡単です (座標の平均)。つまり、A から B への勾配 (デルタ y / デルタ x) もわかっているため、M から E への勾配は負の逆数になります。M と E への勾配がわかれば、あとはあとどれくらいかを知る必要があるだけです。

これを行うには、ACM が 30-60-90 三角形であるという事実を使用します。

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

しかし|午前| = |AB| / 2 および |CE| = |AB|

そう

|私| = |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 は透明な赤に設定されていることに注意してください。通常は、線を非表示にするためにストロークを「なし」に設定します。

于 2013-04-01T22:36:15.417 に答える