Javascript D3力布局:根据节点半径沿链接移动箭头
在此Javascript D3力布局:根据节点半径沿链接移动箭头,javascript,svg,d3.js,force-layout,Javascript,Svg,D3.js,Force Layout,在此D3中: 节点具有可变半径。我设法移动节点标签,使它们总是紧挨着圆 但是,如何移动箭头?(你可以看到,对于微软、苹果等公司来说,他们几乎被圆圈所覆盖) 相关问题: 要根据节点半径调整箭头的位置,可以调整路径的端点。更新 我在网上搜索,没有一个答案有效,所以我自己做了: 代码如下: //arrows svg.append("defs").selectAll("marker") .data(["suit", "licensing", "resolved"]) .en
D3
中:
节点具有可变半径。我设法移动节点标签,使它们总是紧挨着圆
但是,如何移动箭头?(你可以看到,对于微软、苹果等公司来说,他们几乎被圆圈所覆盖)
相关问题:
要根据节点半径调整箭头的位置,可以调整路径的端点。更新
我在网上搜索,没有一个答案有效,所以我自己做了: 代码如下:
//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
}
//箭头
svg.append(“defs”).selectAll(“marker”)
.数据([“诉讼”、“许可”、“已解决”])
.enter().append(“标记”)
.attr(“id”,函数(d){return d;})
.attr(“视图框”,“0-5 10”)
.attr(“参考文献”,第9页)
.attr(“参考文献”,0)
.attr(“markerWidth”,10)
.attr(“markerHeight”,10)
.attr(“方向”、“自动”)
.append(“路径”)
.attr(“d”,“M0,-5L10,0L0,5L10,0L0,-5”)
.style(“笔划”,“#4679BD”)
.样式(“不透明度”、“0.6”);
//创建所有直线SVG,但尚未创建位置
var link=svg.selectAll(“.link”)
.data(forceData.links)
.enter().append(“行”)
.attr(“类”、“链接”)
.style(“标记结束”、“url(#suit)”);
//设置部队布局
var-force=d3.layout.force()
.nodes(forceData.nodes)
.links(forceData.links)
。收费(-120)
.linkDistance(200)
.尺寸([宽度、高度])
.on(“滴答”,滴答)
.start();
函数tick(){
attr(“x1”,函数(d){返回d.source.x;})
.attr(“y1”,函数(d){返回d.source.y;})
.attr(“x2”,函数(d){
返回calculateX(d.target.x,d.target.y,d.source.x,d.source.y,d.target.radius);
})
.attr(“y2”,函数(d){
返回calculateY(d.target.x,d.target.y,d.source.x,d.source.y,d.target.radius);
});
d3.选择全部(“圆圈”)
.attr(“cx”,函数(d){return d.x;})
.attr(“cy”,函数(d){返回d.y;});
d3.选择(“强制布局图”)。选择全部(“文本”)
.attr(“x”,函数(d){return d.x;})
.attr(“y”,函数(d){返回d.y;});
}
函数计算器(tx、ty、sx、sy、半径){
if(tx==sx)返回tx;//如果目标x==source x,则无需更改目标x。
var xLength=Math.abs(tx-sx);//计算x的差值
var-yllength=Math.abs(ty-sy);//计算y的差
//使用三角函数计算比率
变压比=半径/数学sqrt(X长度*X长度+Y长度*Y长度);
如果(tx>sx)返回tx-xLength*比率;//如果目标x>源x返回目标x-半径
if(txsy)返回ty-yllength*比值;//if target y>source y返回target x-radius
if(tysource y返回target x-半径
}
通过将参考点(相对于标记绘制到每条路径中的参考点)从0,0移开来偏移箭头。这是通过.attr(“refX”,15)完成的。增加该数字会将箭头移开。请注意,此技术并不完善:首先,它将相同的refX应用于所有标记。由于需要它取决于节点半径,因此必须进行额外的工作创建并为每个圆创建一个标记。其次,箭头移动得越远,其旋转与路径切线的匹配程度就越低。使链接保持直线可以避免此问题。+1它可以工作!我在找你做的算法。这和我以前为了另一个目的做的一样。
//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
}