在我们通过 d3 操作的 SVG 中要求文本元素的情况并不少见,例如分类刻度标签。这有点不幸,因为 <text>
SVG 中的元素不是最好的...呈现的字体大小通常略大于人们认为字体应该占用的大小。例如,如果选择宽度/高度比为 0.6 的等宽字体(例如,如果字体大小为 12px,则字符的宽度应为 7.2px),元素的计算边界矩形可能为 14.2px by n*8px 其中 n 是字符数。
使问题进一步复杂化的事实是,人们经常使用非等宽字体。
chop “太长”的字符串很容易
string.slice(0, numChars-3)+'...'
但是知道适合固定宽度的正确字符数似乎并不简单。
function truncateText(t, text, space) {
// make sure it is a string
text = String(text)
// set text
t.text(text)
// get space it takes up
var rect = t.node().getBoundingClientRect()
while (Math.max(rect.width, rect.height) > space) {
text = text.slice(0, text.length - 1)
t.text(text + '...')
rect = t.node().getBoundingClientRect()
if (text.length == 0) break
}
}
上面的函数采用 d3.selection,文本和文本应该适合的空间。通过不断地操纵 DOM,我们可以获得完美的适合,但是这在计算上非常昂贵。
澄清一下,为了让文本适合固定空间,我的意思是如果我有一个字符串 var string = "this is my very long string"
,我希望呈现字符串的方向(从左到右,即我们正在查看字符串长度)适合固定空间(例如 var fixedSpace = 100 //px
)
上面的 chop 文本函数只适用于少数几个字符串,但如果有很多字符串调用这个函数,它就会变得迟钝。
当然,我们可以通过只选择最长的字符串进行优化,计算该字符串的 truncateText,并将字符数作为结果(尽管这仍然有些错误,因为并非所有字符都具有相同的宽度)。
有没有更有效的方法用d3将文本 chop 到固定空间
最佳答案
我同意您建议的方法计算量大,但这是我能想到的唯一方法。但是,如果您只是偶尔运行它(即仅在页面加载时,而不是在鼠标悬停时),那么它应该不会太糟糕,具体取决于您将它应用到多少文本元素。
您可能想尝试将您的方法的性能与 this example by Mike Bostock 中的方法进行比较,它使用 node().getComputedTextLength()
而不是 node().getBoundingClientRect()
并按单词拆分文本:
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
PS/有一个 CSS technique for truncating text with an ellipsis ,但不幸的是it doesn't work in SVG :(
关于javascript - D3.js v4+ : truncate text to fit in fixed space,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50579535/