获得箭头指向D3中节点的外边缘 [英] Get arrowheads to point at outer edge of node in D3

查看:146
本文介绍了获得箭头指向D3中节点的外边缘的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是D3的新手,我正在尝试创建一个交互式网络可视化。我已复制示例的大部分内容,但我已将曲线更改为直线使用SVG线而不是路径,我还根据它们表示的数据缩放节点。问题是,我的箭头(用SVG标记创建)在行的末尾。由于一些节点很大,箭头隐藏在它们后面。

I'm new to D3 and I'm trying to create an interactive network visualization. I've copied large parts of this example, but I have changed the curved lines to straight ones by using SVG "lines" rather than "paths", and I've also scaled the nodes according to the data they represent. The problem is that my arrowheads (created with SVG markers) are at the ends of the lines. Since some of the nodes are large, the arrows get hidden behind them. I'd like my arrowheads to show up right at the outside edge of the node they point to.

这里是我创建标记和链接的方法:

Here is how I'm creating the markers and links:

svg.append("svg:defs").selectAll("marker")
    .data(["prereq", "coreq"])
    .enter().append("svg:marker")
    .attr("id", String)
    .attr("viewBox", "0 -5 10 10")
    .attr("refX", 15)
    .attr("markerWidth", 6)
    .attr("markerHeight", 6)
    .attr("orient", "auto")
    .append("svg:path")
    .attr("d", "M0,-5L10,0L0,5");

var link = svg.selectAll(".link")
    .data(force.links())
    .enter().append("line")
    .attr("class", "link")
    .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });

我注意到refX属性指定箭头应该显示向上。我如何使这取决于它指向的节点的半径?如果我不能这样做,我可以改变线本身的端点吗?我想我会这样做在这个函数,它重置线的终点,因为一切移动:

I noticed that the "refX" attribute specifies how far from the end of the line the arrowhead should show up. How can I make this dependent on the radius of the node it's pointing to? If I can't do that, could I instead change the endpoints of the lines themselves? I'm guessing I would do that in this function, which resets the endpoints of the lines as everything moves:

function tick() {
        link
            .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; });

        circle.attr("transform", function(d) {
            return "translate(" + d.x + "," + d.y + ")";
        });

        text.attr("transform", function(d) {
            return "translate(" + d.x + "," + d.y + ")";
        });
    }

哪种方法更有意义,我将如何实现? >

Which approach makes more sense, and how would I implement it?

推荐答案

感谢Lars Kotthoff,我得到这个工作遵循另一个问题的建议!首先我从使用线切换到路径。我不认为我实际上不得不这样做,但它使我更容易跟随其他例子,因为他们使用路径。

Thanks Lars Kotthoff, I got this to work following the advice from the other question! First I switched from using lines to paths. I don't think I actually had to do that, but it made it easier to follow the other examples I was looking at because they used paths.

然后,我添加一个半径字段到我的节点。我只是这样做,当我设置radius属性,通过添加它作为一个实际字段,而不是立即返回值:

Then, I added a "radius" field to my nodes. I just did this when I set the radius attribute, by adding it as an actual field rather than returning the value immediately:

var circle = svg.append("svg:g").selectAll("circle")
                    .data(force.nodes())
                    .enter().append("svg:circle")
                    .attr("r", function(d) {
                        if (d.logic != null) {
                            d.radius = 5;
                        } else {
                            d.radius = node_scale(d.classSize);
                        }
                        return d.radius;


$ b b

然后我编辑了我的tick()函数考虑这个半径,这需要一些简单的几何形状...

I then edited my tick() function to take this radius into account. This required a bit of simple geometry...

function tick(e) {

        path.attr("d", function(d) {
            // Total difference in x and y from source to target
            diffX = d.target.x - d.source.x;
            diffY = d.target.y - d.source.y;

            // Length of path from center of source node to center of target node
            pathLength = Math.sqrt((diffX * diffX) + (diffY * diffY));

            // x and y distances from center to outside edge of target node
            offsetX = (diffX * d.target.radius) / pathLength;
            offsetY = (diffY * d.target.radius) / pathLength;

            return "M" + d.source.x + "," + d.source.y + "L" + (d.target.x - offsetX) + "," + (d.target.y - offsetY);
        });

基本上,由路径形成的三角形,它的总x变化(diffX)变化(diffY)是与由目标节点内部的路径(即节点半径),目标节点内部的x变化(offsetX)和目标节点内部的y变化(offsetY)形成的类似的三角形。 。这意味着目标节点半径与总路径长度的比率等于offsetX与diffX的比率以及offsetY与diffY的比率。

Basically, the triangle formed by the path, it's total x change (diffX), and it's total y change (diffY) is a similar triangle to that formed by the segment of the path inside the target node (i.e. the node radius), the x change inside the target node (offsetX), and the y change inside the target node (offsetY). This means that the ratio of the target node radius to the total path length is equal to the ratio of offsetX to diffX and to the ratio of offsetY to diffY.

refX 值更改为10。我不知道为什么这是必要的,但现在它似乎工作!

I also changed the refX value to 10 for the arrows. I'm not sure why that was necessary but now it seems to work!

这篇关于获得箭头指向D3中节点的外边缘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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