2015-01-23 3 views
1

В этом D3example:D3 макет силы: Перемещение стрелки вдоль звенья в зависимости от радиуса узла

enter image description here

узлов имеет переменный радиус. Мне удалось переместить метки узлов так, чтобы они всегда были рядом с их кругами.

Однако, как перемещать стрелки? (Вы можете видеть, что для Microsoft, Apple и т.д., они почти покрыты кругом)

Похожие вопросы:

here

here

here

here

+1

Стрелки смещения путем перемещения опорной точки (относительно которого маркер втягивается в каждый путь) от 0,0. Это делается через .attr («refX», 15). Увеличение этого числа приведет к удалению стрелки. Обратите внимание, что этот метод несовершенен: Во-первых, он применяет тот же refX ко всем маркерам. Поскольку вам нужно, чтобы он зависел от радиуса узла, вам придется делать дополнительную работу, создавая и создавая по одной отметке на круг. Во-вторых, чем дальше вы перемещаете стрелку, тем меньше ее поворот соответствует тангенсу пути. Создание прямых линий позволяет избежать этой проблемы. – meetamit

ответ

1

Чтобы отрегулировать положение стрелки в зависимости от t радиус узла, вы можете настроить конечные точки путей. Обновлено jsFiddle

function linkArc(d) { 
    var targetX = d.target.x - d.target.started, 
     targetY = d.target.y - d.target.started, 
     dx = targetX - d.source.x, 
     dy = targetY - d.source.y, 
     dr = (d.straight == 0)?Math.sqrt(dx * dx + dy * dy):0; 
    return "M" + d.source.x + "," + d.source.y + 
     " L " + targetX + "," + targetY; 
} 
0

Я поиск в Интернете, ни один из ответа не работал, так что я сделал свой собственный:

Вот код:

//arrows 
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", 9) 
    .attr("refY", 0) 
    .attr("markerWidth", 10) 
    .attr("markerHeight", 10) 
    .attr("orient", "auto") 
    .append("path") 
    .attr("d", "M0,-5L10,0L0,5 L10,0 L0, -5") 
    .style("stroke", "#4679BD") 
    .style("opacity", "0.6"); 

    //Create all the line svgs but without locations yet 
var link = svg.selectAll(".link") 
    .data(forceData.links) 
    .enter().append("line") 
    .attr("class", "link") 
    .style("marker-end", "url(#suit)"); 

//Set up the force layout 
var force = d3.layout.force() 
    .nodes(forceData.nodes) 
    .links(forceData.links) 
    .charge(-120) 
    .linkDistance(200) 
    .size([width, height]) 
    .on("tick", tick) 
    .start(); 

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

    d3.selectAll("circle") 
     .attr("cx", function (d) { return d.x; }) 
     .attr("cy", function (d) { return d.y; }); 

    d3.select("#forcelayoutGraph").selectAll("text") 
     .attr("x", function (d) { return d.x; }) 
     .attr("y", function (d) { return d.y; }); 
} 
function calculateX(tx, ty, sx, sy, radius){ 
    if(tx == sx) return tx;     //if the target x == source x, no need to change the target x. 
    var xLength = Math.abs(tx - sx); //calculate the difference of x 
    var yLength = Math.abs(ty - sy); //calculate the difference of y 
    //calculate the ratio using the trigonometric function 
    var ratio = radius/Math.sqrt(xLength * xLength + yLength * yLength); 
    if(tx > sx) return tx - xLength * ratio; //if target x > source x return target x - radius 
    if(tx < sx) return tx + xLength * ratio; //if target x < source x return target x + radius 
} 
function calculateY(tx, ty, sx, sy, radius){ 
    if(ty == sy) return ty;     //if the target y == source y, no need to change the target y. 
    var xLength = Math.abs(tx - sx); //calculate the difference of x 
    var yLength = Math.abs(ty - sy); //calculate the difference of y 
    //calculate the ratio using the trigonometric function 
    var ratio = radius/Math.sqrt(xLength * xLength + yLength * yLength); 
    if(ty > sy) return ty - yLength * ratio; //if target y > source y return target x - radius 
    if(ty < sy) return ty + yLength * ratio; //if target y > source y return target x - radius 
}