2

私は現在、この例 ( http://bl.ocks.org/mbostock/1153292 ) で行われているように、フォース レイアウトに矢印を実装しており、完全に機能します。ただし、ノードのサイズは決して変わらないため、ここでは矢印の位置とサイズがハードコーディングされていることがすぐにわかります。

ノードのサイズを動的に変更した場合のグラフがあります。それ以外の場合は、ノードによってカバーされるか、ノードをカバーするか、ノードに接続されていないため、それに応じて矢印を更新したいと思います。

この問題について話している投稿が 1 つだけ見つかりました (可変半径のノードを矢印でリンクする)。しかし、それは答えられませんでした.1人のポスターが端を中心ではなくノードの半径で終わらせるという答えは、私がやりたいことではありません. エッジの位置を常に再計算する必要がありますが、これは私が持っているエッジの数を考えると実用的ではありません。

これは比較的簡単だと思いましたが、理解できませんでした。私が現在取り組んでいる変更は、マーカーの作成をノードの世代の下に移動することです。そうしないと、使用しているサイズ メソッドを実行したい場合を除き、ノード サイズ データを取得できず、大量の無駄になります。処理能力(数百のノードがあります)。

私がしようとしていること (大まかな例、私のコードはもう少し複雑です)

var path = svg.append("svg:g").selectAll("path")
    .data(force.links())
  .enter().append("svg:path")
    .attr("class", function(d) { return d.target.nodeID; });

var circle = svg.append("svg:g").selectAll("circle")
    .data(force.nodes())
      .enter().append("svg:circle")
    .attr("r", nodeSize) //Dynamically determine size
    .call(force.drag);

// Per-node markers, as each node could potentially have a unique size
svg.append("svg:defs").selectAll("marker")
    .data(nodes, function(d) { return d.nodeID; })
  .enter().append("svg:marker")
    .attr("id", function(d) { return d.nodeID; })
    .attr("viewBox", "0 -5 10 10")
    .attr("refX", function(d) { return d.r; }) //Offset by the radius of the node
    .attr("refY", 0)
    .attr("markerWidth", 6)
    .attr("markerHeight", 6)
    .attr("orient", "auto")
  .append("svg:path")
    .attr("d", "M0,-5L10,0L0,5");

//Now that we know radius data for nodes, add the arrows in
path.each(function(d) { 
    d.attr("marker-end", function(d) { return "url(#" + d.target.nodeID + ")"; })
});

これを行うための最良の方法について誰かが考えを持っていますか? 前もって感謝します!

更新: リクエストごとに、jsfiddle ( http://jsfiddle.net/herbstmb/j5wJ7/ ) を作成しました。これは、動的な矢印のサイズを機能させようとしている基本的な力のレイアウトです。

4

1 に答える 1

4

これは古い質問ですが、これが私の解決策です。アイデアは、終点がノードの中心ではなくノードの端にあるように、ノードを接続するパスを描画することです。モバイル特許訴訟の例 ( http://bl.ocks.org/mbostock/1153292 ) から始めて、linkArc メソッドを次のように置き換えました。

function drawCurve(d) {
    var sourceX = d.source.x;
    var sourceY = d.source.y;
    var targetX = d.target.x;
    var targetY = d.target.y;

    var theta = Math.atan((targetX - sourceX) / (targetY - sourceY));
    var phi = Math.atan((targetY - sourceY) / (targetX - sourceX));

    var sinTheta = d.source.r * Math.sin(theta);
    var cosTheta = d.source.r * Math.cos(theta);
    var sinPhi = d.target.r * Math.sin(phi);
    var cosPhi = d.target.r * Math.cos(phi);

    // Set the position of the link's end point at the source node
    // such that it is on the edge closest to the target node
    if (d.target.y > d.source.y) {
        sourceX = sourceX + sinTheta;
        sourceY = sourceY + cosTheta;
    }
    else {
        sourceX = sourceX - sinTheta;
        sourceY = sourceY - cosTheta;
    }

    // Set the position of the link's end point at the target node
    // such that it is on the edge closest to the source node
    if (d.source.x > d.target.x) {
        targetX = targetX + cosPhi;
        targetY = targetY + sinPhi;    
    }
    else {
        targetX = targetX - cosPhi;
        targetY = targetY - sinPhi;   
    }

    // Draw an arc between the two calculated points
    var dx = targetX - sourceX,
        dy = targetY - sourceY,
        dr = Math.sqrt(dx * dx + dy * dy);
    return "M" + sourceX + "," + sourceY + "A" + dr + "," + dr + " 0 0,1 " + targetX + "," + targetY;
}

このコードは、ノード データに "r" または radius 属性があることを想定していることに注意してください。これは、jsfiddle の size 属性と同等です。リンクを直線として描画したい場合は、代わりに次の文字列を返すことができます:

return "M" + sourceX + "," + sourceY + "L" + targetX + "," + targetY;

矢印のポイントを正しい位置に配置するために、refX および refY 属性を変更して、矢印のポイントがノードの端になるようにしました。

svg.append("defs").selectAll("marker")
    .data(["suit", "licensing", "resolved"])
  .enter().append("marker")
    .attr("id", function(d) { return d; })
    .attr("viewBox", "0 -5 10 10")
    .attr("refX", 10)
    .attr("refY", 0)
    .attr("markerWidth", 6)
    .attr("markerHeight", 6)
    .attr("orient", "auto")
  .append("path")
    .attr("d", "M0,-5L10,0L0,5");
于 2014-10-28T18:57:30.967 に答える