如何在定向d3.js力布局上动态改变方向箭头的位置和大小? [英] How can I dynamically change the position and the size of direction arrows on a directed d3.js force layout?

查看:1394
本文介绍了如何在定向d3.js力布局上动态改变方向箭头的位置和大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前在我的强制布局中实现箭头,就像本示例中所做的那样( http:// bl。 ocks.org/mbostock/1153292 )和完美的作品。但是,人们很快就会意识到箭头的位置和大小在这里是硬编码的,因为节点从不改变大小。

I am currently implementing arrows in my force layout as is done in this example (http://bl.ocks.org/mbostock/1153292) and that works perfectly. However, one will quickly realize that the location and size of the arrows are hard-coded here since the nodes never change size.

我有一个图,我动态改变节点尺寸,因此我想要箭头更新相应,否则它们被节点覆盖或覆盖节点,或者只是没有附加到节点。

I have a graph were I dynamically change node sizes, and as such I would like the arrows to update accordingly since otherwise they are covered by the node or cover the node or are just not attached to the node.

只有一个我发现(可变半径的链接节点与箭头)。然而,它没有回答,一个海报给出的答案有边缘结束在节点的半径而不是中心不是我想做的事情。这将需要不断重新计算边缘位置,给定的边缘数量是不实际的。

There is only one post I have found (linking nodes of variable radius with arrows) that talks about this issue. However, it was not answered, and the answer that one poster gives of having the edges end at the radius of the node rather than the center is not something I want to do. It would require constantly recomputing edge positions, which given the number of edges I have is not practical.

我认为这将是相对简单,但不能够出来。我目前工作的变化是移动标记创建下面的节点生成,因为否则没有能力获取节点大小数据,除非我想运行我使用的大小方法,这将是一个巨大的浪费处理能力(我有几百个节点)。

I thought this would be relatively simple but haven't been able to figure it out. The change that I a currently working on is moving the marker creation below the generation of the nodes, since otherwise there is no ability to get node size data unless I want to run the size method I am using, which would be a massive waste of processing power (I have hundreds of nodes).

我想要的(粗略的例子,我的代码有点复杂)

What I am trying (rough example, my code is a bit more complex)

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 + ")"; })
});

有没有人知道最好的办法?提前感谢!

Does anyone have an idea about the best way to go about this? Thanks in advance!

更新:根据请求,我创建了一个jsfiddle( http://jsfiddle.net/herbstmb/j5wJ7/ )。这是一个基本的力布局,我试图获得动态箭头的大小工作。

Update: per request, I have created a jsfiddle (http://jsfiddle.net/herbstmb/j5wJ7/). This is a basic force layout that I am trying to get the dynamic arrow sizes to work on.

推荐答案

是一个老问题,但这里是我的解决方案。想法是绘制连接节点的路径,使得端点在节点的边缘而不是在节点的中心。从移动专利诉讼案例( http://bl.ocks.org/mbostock/1153292 )开始),我替换了linkArc方法:

This is an old question, but here is my solution. The idea is to draw the path connecting the nodes such that the end points are on the nodes' edges rather than at the nodes' centers. Starting from the Mobile Patent Suits example (http://bl.ocks.org/mbostock/1153292), I replaced the linkArc method with:

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属性。如果你想以直线绘制链接,你可以返回这个字符串:

Note that this code expects an "r," or radius, attribute to be in the node data. This would be equivalent to the size attribute in your jsfiddle. If you want to draw links as straight lines, you can return this string instead:

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

为了将箭头的点放在正确的位置,我改变了refX和refY属性箭头的点在节点的边缘:

To place the points of the arrows at the correct positions, I changed the refX and refY attributes so that the point of the arrow is at the edge of the node:

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");

这篇关于如何在定向d3.js力布局上动态改变方向箭头的位置和大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆