2015-12-07 18 views
6

私は、リンクに沿ってテキストラベル付きのD3強制有向視覚化を構築しました。私が実行している1つの問題は、リンクがソースノードの左側にあるときにこれらのラベルが上下逆に表示されることです。ここでは例:D3リンクのテキストを右側に表示

enter image description here

私はパスやテキストを配置コードはそうのようになります。

var nodes = flatten(data); 
var links = d3.layout.tree().links(nodes); 

var path = vis.selectAll('path.link') 
    .data(links, function(d) { 
    return d.target.id; 
    }); 

path.enter().insert('svg:path') 
    .attr({ 
    class: 'link', 
    id: function(d) { 
     return 'text-path-' + d.target.id; 
    }, 
    'marker-end': 'url(#end)' 
    }) 
    .style('stroke', '#ccc'); 

var linkText = vis.selectAll('g.link-text').data(links); 

linkText.enter() 
    .append('text') 
    .append('textPath') 
     .attr('xlink:href', function(d) { 
     return '#text-path-' + d.target.id; 
     }) 
     .style('text-anchor', 'middle') 
     .attr('startOffset', '50%') 
     .text(function(d) {return d.target.customerId}); 

私は何とか各パスの現在の角度を決定する必要があり、その後、設定されます知っていますそれに応じてテキストの位置が、私はどのようにするか分からない。ここで

は、この問題に基づいてブロックへのリンクです:以下http://blockbuilder.org/MattDionis/5f966a5230079d9eb9f4

答えは私が道の約90%を持っています。

enter image description here

...と、ここで、それは以下の回答でヒントを利用し次のようになります。:ここに私の元の可視化は、長いカップルの桁数よりもテキストを持つように見えるものである

enter image description here

テキストが「右上がり」になっても、もはや円弧をたどることはありません。

+0

https://stackoverflow.com/questions/8663844/add-text-label-onto-links-in-d3-force-directed-graph –

答えて

6

あなたが描く円弧は、真ん中の接線がテキストのベースラインの方向とまったく同じであり、2つのツリーノードを分離するベクトルと同一直線上にあります。

これを使用して問題を解決できます。

数学のビットが必要です。まず、水平軸に対してベクトルvの角度を返す関数定義でき:そして

function xAngle(v) { 
    return Math.atan(v.y/v.x) + (v.x < 0 ? Math.PI : 0); 
} 

を、各ティックでのそのベースラインのマイナス角度によって所定の位置にテキストを回転させてみましょう。まず、いくつかのユーティリティ機能:追加PIC:

example result

編集2

function isFiniteNumber(x) { 
    return typeof x === 'number' && (Math.abs(x) < Infinity); 
} 

function isVector(v) { 
    return isFiniteNumber(v.x) && isFiniteNumber(v.y); 
} 

、その後、あなたのtick機能では、

linkText.attr('transform', function (d) { 
    // Checks just in case, especially useful at the start of the sim 
    if (!(isVector(d.source) && isVector(d.target))) { 
     return ''; 
    } 

    // Get the geometric center of the text element 
    var box = this.getBBox(); 
    var center = { 
     x: box.x + box.width/2, 
     y: box.y + box.height/2 
    }; 

    // Get the tangent vector 
    var delta = { 
     x: d.target.x - d.source.x, 
     y: d.target.y - d.source.y 
    }; 

    // Rotate about the center 
    return 'rotate(' 
     + (-180/Math.PI*xAngle(delta)) 
     + ' ' + center.x 
     + ' ' + center.y 
     + ')'; 
    }); 
}); 

編集を追加します曲がった円弧の代わりに直線を使用する(単純に<text>の代わりに、<text>の内部<textPath>)、あなたはこれでlinkTextに関するtick機能の一部を置き換えることができます。

linkText.attr('transform', function(d) { 
    if (!(isVector(d.source) && isVector(d.target))) { 
     return ''; 
    } 

    // Get the geometric center of this element 
    var box = this.getBBox(); 
    var center = { 
     x: box.x + box.width/2, 
     y: box.y + box.height/2 
    }; 

    // Get the direction of the link along the X axis 
    var dx = d.target.x - d.source.x; 

    // Flip the text if the link goes towards the left 
    return dx < 0 
     ? ('rotate(180 ' 
      + center.x 
      + ' ' + center.y 
      + ')') 
     : ''; 
}); 

、これはあなたが得るものです:

rotated text

お知らせ方法リンクがより右を指すことから左を指す方向に向かうにつれてテキストが反転されます。

この問題は、テキストがリンクの下に終わることが問題です。

linkText.attr('transform', function(d) { 
    if (!(isVector(d.source) && isVector(d.target))) { 
     return ''; 
    } 

    // Get the geometric center of this element 
    var box = this.getBBox(); 
    var center = { 
     x: box.x + box.width/2, 
     y: box.y + box.height/2 
    }; 

    // Get the vector of the link 
    var delta = { 
     x: d.target.x - d.source.x, 
     y: d.target.y - d.source.y 
    }; 

    // Get a unitary vector orthogonal to delta 
    var norm = Math.sqrt(delta.x * delta.x + delta.y * delta.y); 
    var orth = { 
     x: delta.y/norm, 
     y: -delta.x/norm 
    }; 

    // Replace this with your ACTUAL font size 
    var fontSize = 14; 

    // Flip the text and translate it beyond the link line 
    // if the link goes towards the left 
    return delta.x < 0 
     ? ('rotate(180 ' 
      + center.x 
      + ' ' + center.y 
      + ') translate(' 
      + (orth.x * fontSize) + ' ' 
      + (orth.y * fontSize) + ')') 
     : ''; 
}); 

を、今結果は次のようになります:

enter image description here

あなたが見ることができるように、テキストは、行の上にきれいにしても、リンクを座って、次のようにそれを固定することができます左を指します。

最後に、アークを維持しながら、テキストを右に上向きにして問題を解決するには、2つの<textPath>要素を作成する必要があると思います。 1つはsourceからtargetに進み、もう1つは逆の方向に進むためのものです。リンクが右(delta.x >= 0)に向かうと最初のリンクを使用し、リンクが左(delta.x < 0)の方向に進むと2番目のリンクを使用すると、結果はより良く見え、コードは必ずしも元のもう少し論理を追加するだけです。

+0

ありがとうございました!それはすごい説明だったし、その道の約90%を私に手に入れました。元の質問にもう少しイメージを追加して残りの問題を強調しました。私は、テキストラベルを各円の上に置くことを目指しています。 – MattDionis

+0

昨日、私の2番目の問題に関する答えを見ましたが、今は消えたようです。私はまだこれに取り組んでいます。カーブしたリンクを直線に変更しようとしているのであれば、これは単純な設計上の決定だったので解決しやすくなります。 – MattDionis

+0

@MattDionisまあ、テキストが曲がっているのを気にしていないと言ってうれしいことです。なぜなら、その要件は解決策を達成するのが難しくなったからです。テキストが真っ直ぐになるようにすると、コードは単純になります。回転が不要なため、上記の最初の解決方法よりも簡単です。 'delta'ベクトルが左(' delta.x <0')に向かうときにテキストを反転させるだけです。私はできる限りコードを書くつもりです。 – jrsala

関連する問題