10

リンクのサイズとそれに関連する矢印のサイズを値 (1 ~ 3) に基づいて変更しようとしている d3 強制有向グラフに次のコードがあります。ストロークの太さは値によって変化しますが、矢印は正しい位置に留まりません。ストロークの太さが 1 から 3 に変わると、端から後ろに移動する傾向があります。ストロークの値を変更するときに矢印 (マーカー) を適切に整列させる方法についてのアイデアはありますか? どうもありがとう!

      var link = vis.selectAll("line.link")
      .data(json.links)
    .enter().append("svg:line")
      .attr("class", "link")
      .style("stroke-width", function(d) { return Math.sqrt(d.value); })
      .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; })
      .attr("marker-end", "url(#arrowGray)")
      .on("click", function(d) {
            link.style("stroke","#dddddd");
            node.style("stroke","#FFFFFF");
            d3.select(this).style("stroke","red");
            link.attr("marker-end", null);
            link.attr("marker-end", "url(#arrowGray)");
            d3.select(this).attr("marker-end", null);
            d3.select(this).attr("marker-end", "url(#arrowRed)");
            clickLink(d);
            });

    defs.append("svg:marker")
            .attr("id", "arrowGray")
            .attr("viewBox","0 0 10 10")
            .attr("refX","20")
            .attr("refY","5")
            .attr("markerUnits","strokeWidth")
            .attr("markerWidth","9")
            .attr("markerHeight","5")
            .attr("orient","auto")
            .append("svg:path")
            .attr("d","M 0 0 L 10 5 L 0 10 z")
            .attr("fill", "#BBBBBB");
4

2 に答える 2

9

問題

このjsFiddleは、問題の問題を示しています。マーカー def の値は、それが取り付けられている要素 (この場合はリンク線) のストローク幅に関連しています。markerUnitsの仕様を参照してください。属性に使用strokeWidthするmarkerUnitsことで、異なるサイズの矢印の座標がわずかに異なります。つまり、あるサイズの矢印の適切な値は、他のサイズに正しく変換されません。

解決策 1: 複数のマーカー

コメントで述べたように、1 つの解決策は、strokeWidth必要なそれぞれに異なるマーカーを作成することです。これは、必要なサイズを事前に知っている場合にのみ機能します。

解決策 2: 線を変更する

もう 1 つのオプションは、線の終点を変更することです。線がノードの中央で終了するのではなく、ノードの外側の端で終了します。このjsFiddleはこれを示しています。これにより、線の最後に矢印を描画できるようになったため、矢印の先端を移動する必要がなくなりました。

x2このソリューションには、とy2の値がどうあるべきかを理解するための数学が含まれlineます。したがって、多数のエッジを持つシステムには理想的ではない場合があります。

var nodeRadius = 10;
var lineX2 = function (d) {
    var length = Math.sqrt(Math.pow(d.target.y - d.source.y, 2) + Math.pow(d.target.x - d.source.x, 2));
    var scale = (length - nodeRadius) / length;
    var offset = (d.target.x - d.source.x) - (d.target.x - d.source.x) * scale;
    return d.target.x - offset;
};
var lineY2 = function (d) {
    var length = Math.sqrt(Math.pow(d.target.y - d.source.y, 2) + Math.pow(d.target.x - d.source.x, 2));
    var scale = (length - nodeRadius) / length;
    var offset = (d.target.y - d.source.y) - (d.target.y - d.source.y) * scale;
    return d.target.y - offset;
};

var link = svg.selectAll("line.link")
    .data(graph.links)
    .enter().append("svg:line")
    .attr("class", "link")
    .style("stroke-width", function (d) {
      return Math.sqrt(d.value);
    })
    .attr("x1", function (d) {
       return d.source.x;
    })
    .attr("y1", function (d) {
        return d.source.y;
    })
    .attr("x2", lineX2)
    .attr("y2", lineY2)
    .attr("marker-end", "url(#arrowGray)")
    .on("click", function (d) {
        link.style("stroke", "#dddddd");
        node.style("stroke", "#FFFFFF");
        d3.select(this).style("stroke", "red");
        link.attr("marker-end", null);
        link.attr("marker-end", "url(#arrowGray)");
        d3.select(this).attr("marker-end", null);
        d3.select(this).attr("marker-end", "url(#arrowRed)");
    });

var defs = svg.append('defs');
defs.append("svg:marker")
    .attr("id", "arrowGray")
    .attr("viewBox", "0 0 10 10")
    .attr("refX", "10")
    .attr("refY", "5")
    .attr("markerUnits", "strokeWidth")
    .attr("markerWidth", "10")
    .attr("markerHeight", "5")
    .attr("orient", "auto")
    .append("svg:path")
    .attr("d", "M 0 0 L 10 5 L 0 10 z")
    .attr("fill", "#000");

var node = svg.selectAll(".node")
    .data(graph.nodes)
    .enter().append("circle")
    .attr("class", "node")
    .attr("r", nodeRadius)
    .style("fill", function (d) {
        return color(d.group);
    })
    .call(force.drag);

node.append("title")
    .text(function (d) {
        return d.name;
    });

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

    node.attr("cx", function (d) {
        return d.x;
    })
    .attr("cy", function (d) {
        return d.y;
    });
});
于 2014-03-04T18:35:07.673 に答える
1

あなたrefXはおそらく大きすぎます。1前後に設定してみてください。

于 2013-03-19T01:33:30.353 に答える