您绘制的弧线使得它们在中间的切线恰好是文本基线的方向,并且它也与分隔两个树节点的向量共线。
我们可以用它来解决问题。
需要一点数学知识。首先,让我们定义一个函数,它返回向量v 相对于水平轴的角度:
function xAngle(v) {
return Math.atan(v.y/v.x) + (v.x < 0 ? Math.PI : 0);
}
然后,在每个刻度处,让我们将文本原位旋转减去其基线的角度。首先,一些实用函数:
function isFiniteNumber(x) {
return typeof x === 'number' && (Math.abs(x) < Infinity);
}
function isVector(v) {
return isFiniteNumber(v.x) && isFiniteNumber(v.y);
}
然后,在您的 tick 函数中,添加
linkText.attr('transform', function (d) {
// Checks just in case, especially useful at the start of the sim
if (!(isVector(d.source) && isVector(d.target))) {
return '';
}
// Get the geometric center of the text element
var box = this.getBBox();
var center = {
x: box.x + box.width/2,
y: box.y + box.height/2
};
// Get the tangent vector
var delta = {
x: d.target.x - d.source.x,
y: d.target.y - d.source.y
};
// Rotate about the center
return 'rotate('
+ (-180/Math.PI*xAngle(delta))
+ ' ' + center.x
+ ' ' + center.y
+ ')';
});
});
编辑:添加图片:
edit 2 用直线代替弧线(只需<text> 代替<textPath> 在<text> 内),您可以替换tick 函数中与@ 相关的部分987654336@ 这个:
linkText.attr('transform', function(d) {
if (!(isVector(d.source) && isVector(d.target))) {
return '';
}
// Get the geometric center of this element
var box = this.getBBox();
var center = {
x: box.x + box.width / 2,
y: box.y + box.height / 2
};
// Get the direction of the link along the X axis
var dx = d.target.x - d.source.x;
// Flip the text if the link goes towards the left
return dx < 0
? ('rotate(180 '
+ center.x
+ ' ' + center.y
+ ')')
: '';
});
这就是你得到的:
请注意,当链接从更多指向右侧变为更多指向左侧时,文本是如何翻转的。
这样做的问题是文本在链接下方结束。可以按如下方式修复:
linkText.attr('transform', function(d) {
if (!(isVector(d.source) && isVector(d.target))) {
return '';
}
// Get the geometric center of this element
var box = this.getBBox();
var center = {
x: box.x + box.width / 2,
y: box.y + box.height / 2
};
// Get the vector of the link
var delta = {
x: d.target.x - d.source.x,
y: d.target.y - d.source.y
};
// Get a unitary vector orthogonal to delta
var norm = Math.sqrt(delta.x * delta.x + delta.y * delta.y);
var orth = {
x: delta.y/norm,
y: -delta.x/norm
};
// Replace this with your ACTUAL font size
var fontSize = 14;
// Flip the text and translate it beyond the link line
// if the link goes towards the left
return delta.x < 0
? ('rotate(180 '
+ center.x
+ ' ' + center.y
+ ') translate('
+ (orth.x * fontSize) + ' '
+ (orth.y * fontSize) + ')')
: '';
});
现在结果如下所示:
如您所见,文本很好地位于行的顶部,即使链接指向左侧。
最后,为了解决问题,同时保持弧形和文本右侧向上沿弧形弯曲,我认为您需要构建两个 <textPath> 元素。一个用于从source 到target,一个用于相反的方向。当链接向右(delta.x >= 0)时,您将使用第一个,而当链接向左(delta.x < 0)时,您将使用第二个,我认为结果会更好,代码不一定会更多比原来复杂,只是增加了一点逻辑。