Javascript 在力定向图形中,将文本居中放置在曲线链接上

Javascript 在力定向图形中,将文本居中放置在曲线链接上,javascript,d3.js,svg,force-layout,Javascript,D3.js,Svg,Force Layout,这是第二个问题,建立在我之前的问题基础上——关于如何缩短d3力图的弯曲连杆 我最近的斗争涉及将文本置于链接顶部的中心位置,实际上是在链接上方。下面是一个可复制的示例,显示了我的问题(抱歉代码太长。创建一个可复制的示例需要很多,尽管我目前只处理一小部分): const svg=d3.选择(“#mySVG”) const nodesG=svg.select(“g.nodesG”) const linksG=svg.select(“g.links”) 变量图={ “节点”:[{ “姓名”:“彼得”,

这是第二个问题,建立在我之前的问题基础上——关于如何缩短d3力图的弯曲连杆

我最近的斗争涉及将文本置于链接顶部的中心位置,实际上是在链接上方。下面是一个可复制的示例,显示了我的问题(抱歉代码太长。创建一个可复制的示例需要很多,尽管我目前只处理一小部分):

const svg=d3.选择(“#mySVG”)
const nodesG=svg.select(“g.nodesG”)
const linksG=svg.select(“g.links”)
变量图={
“节点”:[{
“姓名”:“彼得”,
“标签”:“人”,
“id”:1
},
{
“姓名”:“迈克尔”,
“标签”:“人”,
“id”:2
},
{
“名称”:“Neo4j”,
“标签”:“数据库”,
“id”:3
},
{
“名称”:“图形数据库”,
“标签”:“数据库”,
“id”:4
}
],
“链接”:[{
“来源”:1,
"目标":二,,
“类型”:“知道”,
“自”:2010年
},
{
“来源”:1,
"目标":三,,
“类型”:“已建立”
},
{
“来源”:2,
"目标":三,,
“类型”:“工作于”
},
{
“来源”:3,
“目标”:4,
“类型”:“是A”
}
]
}
svg.append('defs').append('marker'))
.attr('id','arrowhead')
.attr('viewBox','-0-5100')
.attr('refX',0)
.attr('refY',0)
.attr('orient'、'auto')
.attr('markerWidth',13)
.attr('markerHeight',13)
.attr('xoverflow','visible')
.append('svg:path')
.attr('d','m0,-5l10,0l0,5')
.attr('fill','#999')
.style('stroke','none');
常量模拟=d3.forceSimulation()
.force(“link”,d3.forceLink().id(d=>d.id))
.force(“电荷”,d3.forceManyBody())
.力(“中心”,d3.力中心(100100));
让linksData=graphs.links.map(link=>{
var obj=链路;
obj.source=link.source;
obj.target=link.target;
返回obj;
})
const links=linksG
.全选(“g”)
.数据(图表.链接)
.enter().append(“g”)
.attr(“光标”、“指针”)
常量链接线=链接
.append(“路径”)
.attr('stroke','000000')
.attr('opacity',0.75)
.attr(“笔划宽度”,1)
.attr(“填充”、“透明”)
.attr('marker-end','url(#箭头)');
const linkText=链接
.append(“文本”)
.attr(“x”,d=>(d.source.x+(d.target.x-d.source.x)*0.5))
.attr(“y”,d=>(d.source.y+(d.target.y-d.source.y)*0.5))
.attr('stroke','000000')
.attr(“文本锚定”、“中间”)
.attr('opacity',1)
.text((d,i)=>“${i}”);
const nodes=nodesG
.全选(“g”)
.数据(图.节点)
.enter().append(“g”)
.attr(“光标”、“指针”)
.call(d3.drag()
.on(“开始”,拖动开始)
.打开(“拖动”,拖动)
。在(“结束”,dragended));
常量圆=节点。追加(“圆”)
.attr(“r”,12)
.attr(“填充”、“000000”)
nodes.append(“title”)
.文本(功能(d){
返回d.id;
});
模拟
.节点(图.节点)
。在(勾选)上;
simulation.force(“link”,d3.forceLink().links(linksData)
.id((d,i)=>d.id)
.距离(150);
函数勾选(){
linkLines.attr(“d”,函数(d){
var dx=(d.target.x-d.source.x),
dy=(d.target.y-d.source.y),
dr=Math.sqrt(dx*dx+dy*dy);
返回“M”+d.source.x+”、“+d.source.y+”A“+dr+”、“+dr+”0,1“+d.target.x+”、“+d.target.y”;
});
//重新计算并后退距离
linkLines.attr(“d”,函数(d){
//当前路径的长度
var pl=this.getTotalLength(),
//圆半径加后退
r=(12)+30,
//靠近路径截取圆的位置
m=这个.getPointAtLength(pl-r);
var dx=m.x-d.source.x,
dy=m.y-d.source.y,
dr=Math.sqrt(dx*dx+dy*dy);
返回“M”+d.source.x+”、“+d.source.y+”A“+dr+”、“+dr+”0,1“+M.x+”、“+M.y”;
});
链接文本
.attr(“x”,函数(d){return(d.source.x+(d.target.x-d.source.x)*0.5);}
.attr(“y”,函数(d){return(d.source.y+(d.target.y-d.source.y)*0.5);}
节点
.attr(“transform”,d=>`translate(${d.x},${d.y})`);
}
函数dragstarted(d){
如果(!d3.event.active)simulation.alphaTarget(0.3.restart();
d、 fx=d.x;
d、 fy=d.y;
}
函数(d){
d、 fx=d3.event.x;
d、 fy=d3.event.y;
}
函数d(d){
如果(!d3.event.active)simulation.alphaTarget(0);
d、 fx=null;
d、 fy=null;
}

有几种不同的方法可以解决此问题。最明显的两个是:

  • 使用
    getPointAtLength()
    获取
    的中间部分,并将文本定位在那里
  • 使用
    元素
  • 在我的解决方案中,我会选择#2,主要是因为,使用文本路径,数字可以根据路径的方向翻转,其中一些会倒过来(我假设这是您想要的)

    因此,我们附加
    textPath
    s

    const linkText = links
        .append("text")
        .attr("dy", -4)
        .append("textPath")
        .attr("xlink:href", function(_, i) {
            return "#path" + i
        })
        .attr("startOffset", "50%")
        .text((d, i) => `${i}`);
    
    。。。已为路径指定唯一ID:

    .attr("id", function(_, i) {
        return "path" + i
    })
    
    这是包含这些更改的代码:

    const svg=d3.选择(“#mySVG”)
    const nodesG=svg.select(“g.nodesG”)
    const linksG=svg.select(“g.links”)
    变量图={
    “节点”:[{
    “姓名”:“彼得”,
    “标签”:“人”,
    “id”:1
    },
    {
    “姓名”:“迈克尔”,
    “标签”:“人”,
    “id”:2
    },
    {
    “名称”:“Neo4j”,
    “标签”:“数据库”,
    “id”:3
    },
    {
    “名称”:“图形数据库”,
    “标签”:“数据库”,
    “id”:4
    }
    ],
    “链接”:[{
    “来源”:1,
    "目标":二,,
    “类型”:“知道”,
    “自”:2010年
    },
    {
    “来源”:1,
    "目标":三,,
    “类型”:“已建立”
    },
    {
    “来源”:2,
    "目标":三,,
    “类型”:“工作于”
    },
    {
    “来源”:3,
    “目标”:4,
    “类型”:“是A”
    }
    ]
    }
    svg.append('defs').append('marker'))
    .attr('id','arrowhead')
    .attr('viewBox','-0-5100')
    .attr('refX',0)
    .attr('refY',0)
    .attr('orient'、'auto')
    在