svg / d3-force 中如何给link的label文字加底色
上篇介绍的使用滤镜给force中的节点文字加底色,但是同样的方法并不适合link上文字的底色。因为link是可以360度旋转的。而滤镜中的宽高一般是跟着文字的,svg中文字的宽高并没有伴随角度,(这里我没有找到给滤镜加角度的方法,如果有可以告诉我呀!)因此我使用了另外一种给文字加底色的方法,使用rect的方法,然后计算出文字旋转的角度,给rect加转动属性实现。【转载本文请说明出处,谢谢!】
效果演示
方法
// 1、添加一个rect
lines.call(links => {
links.each(function (link) {
if (link.relName) {
d3.select(this).append('rect')
.attr('class', 'link-line-rect')
.attr('fill', '#fff')
.attr('rx', '2')
.attr('ry', '2')
}
})
})
// 2、tick的时候随之转动
lines.selectAll('.link-line-rect')
.attr('x', d => d.point.x)
.attr('y', d => d.point.y)
.attr('width', d => d.point.width)
.attr('height', d => d.point.height)
.attr('transform', d => {
// 获取转动的角度,给加上rotate属性
let { angle } = that.getAngel(d)
return `rotate(${angle}, ${d.point.x}, ${d.point.y}) translate(-${d.point.width / 2}, -${d.point.height / 2})`
})
d.point
:指的是对应link的label文字的信息,获取方法如下:
// 获取label相关信息
let lineNode = d3.select(`#line${d.objPropId}${d.source.id}${d.target.id}`).node()
if (lineNode) {
// 获取中间点
d.point = lineNode.getPointAtLength(lineNode.getTotalLength() / 2);
}
let textNode = d3.select(`#lineText${d.objPropId}${d.source.id}${d.target.id}`).node()
if (textNode) {
d.point.width = textNode.getBoundingClientRect().width
d.point.height = 15 // 高度不变,直接写可以
}
getAngel
:获取link转动的角度
// 获取角度等信息
getAngel (d) {
let dsx = d.source.x;
let dsy = d.source.y;
let tsx = d.target.x;
let tsy = d.target.y;
let disX = tsx - dsx;
let disY = tsy - dsy;
let disZ = Math.sqrt(Math.pow(disY, 2) + Math.pow(disX, 2));
let sin = disY / disZ;
let cos = disX / disZ;
// 根据弧度算角度
let angle = Math.asin(sin) * 180 / Math.PI
if (tsx < dsx) {
angle = -angle
}
return {
sin,
cos,
angle
}
}
图文并茂解释下:
小结
关于这方面的文档其实是比较少的,只能自己一边研究一边记录,分享下来,希望能帮到同样要用的人。