Javascript 如何动态更改定向d3.js force布局上方向箭头的位置和大小?
我目前正在我的force布局中实现箭头,正如在本例()中所做的那样,这非常有效。然而,人们会很快意识到箭头的位置和大小在这里是硬编码的,因为节点的大小永远不会改变 如果我动态更改节点大小,我有一个图表,因此我希望箭头相应地更新,因为否则它们会被节点覆盖,或者覆盖节点,或者只是没有连接到节点 我发现只有一篇文章()谈到了这个问题。然而,它没有得到回答,一张海报给出的关于边缘端点位于节点半径而不是中心的答案并不是我想做的事情。这将需要不断地重新计算边缘位置,而考虑到我拥有的边缘数量,这是不实际的 我原以为这会相对简单,但一直没能弄明白。我目前正在进行的更改是将标记创建移到节点生成的下方,因为否则,除非我想运行我正在使用的size方法,否则无法获取节点大小数据,这将是对处理能力的巨大浪费(我有数百个节点) 我正在尝试的(粗略的例子,我的代码有点复杂) 有人知道最好的方法吗?提前谢谢Javascript 如何动态更改定向d3.js force布局上方向箭头的位置和大小?,javascript,svg,d3.js,force-layout,Javascript,Svg,D3.js,Force Layout,我目前正在我的force布局中实现箭头,正如在本例()中所做的那样,这非常有效。然而,人们会很快意识到箭头的位置和大小在这里是硬编码的,因为节点的大小永远不会改变 如果我动态更改节点大小,我有一个图表,因此我希望箭头相应地更新,因为否则它们会被节点覆盖,或者覆盖节点,或者只是没有连接到节点 我发现只有一篇文章()谈到了这个问题。然而,它没有得到回答,一张海报给出的关于边缘端点位于节点半径而不是中心的答案并不是我想做的事情。这将需要不断地重新计算边缘位置,而考虑到我拥有的边缘数量,这是不实际的 我
更新:根据请求,我创建了一个jsfiddle()。这是一个基本的力布局,我正在尝试使用动态箭头大小。这是一个老问题,但这里是我的解决方案。其思想是绘制连接节点的路径,使端点位于节点的边缘而不是节点的中心。从移动专利诉讼示例()开始,我将linkArc方法替换为:
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”属性。这相当于JSFIDLE中的size属性。如果要将链接绘制为直线,可以返回以下字符串:
return "M" + sourceX + "," + sourceY + "L" + targetX + "," + targetY;
为了将箭头的点放置在正确的位置,我更改了refX和refY属性,以便箭头的点位于节点的边缘:
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");
这是一个老问题,但我的解决方案是这样的。其思想是绘制连接节点的路径,使端点位于节点的边缘而不是节点的中心。从移动专利诉讼示例()开始,我将linkArc方法替换为:
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”属性。这相当于JSFIDLE中的size属性。如果要将链接绘制为直线,可以返回以下字符串:
return "M" + sourceX + "," + sourceY + "L" + targetX + "," + targetY;
为了将箭头的点放置在正确的位置,我更改了refX和refY属性,以便箭头的点位于节点的边缘:
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");
你能把这段代码变成一个有用的代码吗?看起来没有太多遗漏,这会让其他人更容易找到解决方案。我已经创建了一个。检查帖子中的更新。这是一个非常基本的强制布局,我只是尝试添加动态大小的箭头。控制台抱怨的语法错误出现在前一行,您用单引号打开一个字符串,然后用双引号关闭它。关于您的问题,我注意到您提出了一些关于放弃潜在解决方案的意见,因为在数百个节点上运行的潜在性能问题。您可能应该尝试一下最简单的解决方案,并在放弃它之前对其进行测试。你会惊讶地发现,在一瞬间,你能在几百分的情况下做多少。现在浏览器速度很快(相对而言,甚至是移动的)。谢谢你的发现。我非常喜欢尝试最简单的解决方案,而且我相信我正在尝试的(即使我不知道怎么做)就是那个解决方案。老实说,对我来说,可视化已经有点慢了,所以我一直在努力寻找提高速度的方法。我希望在中添加此新功能不会产生什么影响。不过我要试试看!你能把这段代码变成一个有用的代码吗?看起来没有太多遗漏,这会让其他人更容易找到解决方案。我已经创建了一个。检查帖子中的更新。这是一个非常基本的强制布局,我只是尝试添加动态大小的箭头。控制台抱怨的语法错误出现在前一行,您用单引号打开一个字符串,然后用双引号关闭它。关于您的问题,我注意到您提出了一些关于放弃潜在解决方案的意见,因为在数百个节点上运行的潜在性能问题。您可能应该尝试一下最简单的解决方案,并在放弃它之前对其进行测试。你会惊讶地发现,在一瞬间,你能在几百分的情况下做多少。现在浏览器速度很快(相对而言,甚至是移动的)。谢谢你的发现。我非常喜欢尝试最简单的解决方案,而且我相信我正在尝试的(即使我不知道怎么做)就是那个解决方案。老实说,对我来说,可视化已经有点慢了,所以我一直在努力寻找提高速度的方法。我希望在中添加此新功能不会产生什么影响。不过我要试试看!