D3 SVG 路径上的定位箭头
D3 SVG positioning arrowhead on path
我正在用 D3 可视化一个力布局网络,但我在沿着我的节点之间的边缘定位箭头时遇到了问题。正如您在图片中看到的,我正在根据每个节点的 属性 值缩放节点的大小。基本上我需要某种方法来动态 caculate/change 我的箭头在边缘上的位置(根据用于缩放节点的相同值)以使它们可见并防止它们与节点重叠。实际上我希望我的箭头 "touch" 我的节点的外边缘。有没有人有办法做到这一点?这些代码片段展示了我如何创建箭头。也许我应该使用其他方式?
p.s。我知道我可以更改绘图顺序以在节点顶部绘制箭头,但这不是我想要的。
...
svg.append("defs").append("marker")
.attr("id", "arrowhead")
.attr("refX", 5) /*must be smarter way to calculate shift*/
.attr("refY", 2)
.attr("markerWidth", 6)
.attr("markerHeight", 4)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0,0 V 4 L6,2 Z");
...
path.enter()
.append("svg:path")
.attr("class", function (d) {
return "link " + d.type;
})
.attr("id", function (d) {
return "path_" + d.id;
})
.attr("marker-end", "url(#arrowhead)")
.transition().duration(8000)
.style("stroke-width", stylePathStrokeWidth)
...
我根据马克对这个问题的回答解决了这个问题。这是我在 tick 函数中的代码:
function tick() {
// fit path like you've been doing
path.attr("d", function (d, i) {
dr = 550 / d.linknum;
var result = "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
return result;
});
// recalculate and back off the distance
path.attr("d", function (d, i) {
var pl = this.getTotalLength();
//this is the magic
var r = d.target.size + 3 * d.size; // Multiply the marker size (3) with the size of the edge (d.size) because the markers are scaling with the edge which they are attached to!!
var m = this.getPointAtLength(pl - r);
dr = 550 / d.linknum;
var result = "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + m.x + "," + m.y;
return result;
});
我正在用 D3 可视化一个力布局网络,但我在沿着我的节点之间的边缘定位箭头时遇到了问题。正如您在图片中看到的,我正在根据每个节点的 属性 值缩放节点的大小。基本上我需要某种方法来动态 caculate/change 我的箭头在边缘上的位置(根据用于缩放节点的相同值)以使它们可见并防止它们与节点重叠。实际上我希望我的箭头 "touch" 我的节点的外边缘。有没有人有办法做到这一点?这些代码片段展示了我如何创建箭头。也许我应该使用其他方式?
p.s。我知道我可以更改绘图顺序以在节点顶部绘制箭头,但这不是我想要的。
...
svg.append("defs").append("marker")
.attr("id", "arrowhead")
.attr("refX", 5) /*must be smarter way to calculate shift*/
.attr("refY", 2)
.attr("markerWidth", 6)
.attr("markerHeight", 4)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0,0 V 4 L6,2 Z");
...
path.enter()
.append("svg:path")
.attr("class", function (d) {
return "link " + d.type;
})
.attr("id", function (d) {
return "path_" + d.id;
})
.attr("marker-end", "url(#arrowhead)")
.transition().duration(8000)
.style("stroke-width", stylePathStrokeWidth)
...
我根据马克对这个问题的回答解决了这个问题
function tick() {
// fit path like you've been doing
path.attr("d", function (d, i) {
dr = 550 / d.linknum;
var result = "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
return result;
});
// recalculate and back off the distance
path.attr("d", function (d, i) {
var pl = this.getTotalLength();
//this is the magic
var r = d.target.size + 3 * d.size; // Multiply the marker size (3) with the size of the edge (d.size) because the markers are scaling with the edge which they are attached to!!
var m = this.getPointAtLength(pl - r);
dr = 550 / d.linknum;
var result = "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + m.x + "," + m.y;
return result;
});