我正在构建图形,我想添加一个注释层,该注释层既可以包装文本,还可以合并HTML标签。
例如,我想输入:
vis.append('text')
.attr("text-anchor", "left")
.text('left side <b>left side</b> left side left side')
.call(wrap, 100);
它是根据MBostock的generic text wrapper建模而成的,并且
wrap()
足够聪明,既可以包装此文本,又可以逐个单词地加粗(甚至跨多行)。换句话说,我希望它能够在必要时进行标记:
左侧左侧
左侧
左侧左侧...
MBostock的文本包装程序可以解决此问题,因为:
它调用
words.reverse()
,从而混淆了自然的开放标签/关闭标签它依赖于
<text>
和<tspan>
元素,据我所知,它们不支持嵌入式<b>
或<em>
标记。 (它们确实支持font-weight
和font-style
之类的CSS样式,但是我不确定如何在逐字基础上(仅在tspan的基础上)做到这一点。而且我不愿意使用,因为它似乎没有广泛的浏览器支持。)我不确定最好的解决方法是什么。有没有人处理这个问题?
谢谢,
亚历克斯
最佳答案
好的,我有一个粗略的解决方案。可能有一种更干净,更优雅的方法,但是总体思路如下:
保留Mike的<tspan>
方法来测量文本的长度以确定何时换行。
但是,在每行较大的<tspan>
中为每个单词附加一个<tspan>
然后,要设置粗体和斜体样式,请跟踪到目前为止的文本状态(如果打开了<b>
或<em>
标记),并相应地使用font-style
和font-weight
CSS属性。
以下代码可以做到这一点,并且还可以处理多个滞后或单独的<br>
(而不是前导<br>
):
function wrap(text, width, block_id) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
x = text.attr("x"),
dy = 0
tspan = text.text(null)
.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dy", dy + "em");
word_id_counter = 0
bold_state = false
italic_state = false
while (word = words.pop()) {
// change state to bold
if (word.split('<b>').length > 1){
bold_state = true
word = word.replace('<b>','')
}
//change state to italic
if (word.split('<em>').length > 1){
italic_state = true
word = word.replace('<em>','')
}
tspan.append('tspan')
.attr('id', 'word' + '_' + word_id_counter + '_' + block_id)
.attr('font-weight', bold_state ? 'bold' : 'normal')
.attr('font-style', italic_state ? 'italic' : 'normal')
.text(
word.replace('</b>','').replace('</em>','').replace(new RegExp('<br>', 'g'), '')
+ " "
);
// handle overflow
if (tspan.node().getComputedTextLength() >= width) {
d3.select("#" + 'word' + '_' + word_id_counter + '_' + block_id).remove();
// handle edge case where line break and overflow occur at same time
word = word.replace('<br>','')
tspan = text.append("tspan")
.attr("x", x)
.attr("y", y)
.attr('id', 'wrap-text')
.attr("dy", ++lineNumber * lineHeight + dy + "em")
tspan.append('tspan')
.attr('id', 'word' + '_' + word_id_counter + '_' + block_id)
.attr('font-weight', bold_state ? 'bold' : 'normal')
.attr('font-style', italic_state ? 'italic' : 'normal')
.text(word.replace('</em>','').replace('</b>','').replace(new RegExp('<br>', 'g'), '') + " ");
}
// handle newline (can handle multiple)
if ((total_br = word.split('<br>').length - 1) > 0){
lineNumber = lineNumber + total_br
tspan = text.append("tspan")
.attr("x", x)
.attr("y", y)
.attr('id', 'wrap-text')
.attr("dy", lineNumber * lineHeight + dy + "em")
}
//handle close bold: change bold_state back to normal
if (word.split('</b>').length > 1){
bold_state = false
}
//handle close italics: change state back to normal
if (word.split('</em>').length > 1){
italic_state = false
}
word_id_counter = word_id_counter + 1
}
});
}
样品:
在此上运行时:
this.vis.append('text')
.attr("text-anchor", "left")
.text('left1 side1 left2 side2 <b>left3 side3 left4 side4 <em>left5 side5</b> left6<br><br> side6 left7</em> side7 left8 side8 left9 side9 left10 side10 left11 side11 left12 side12')
.call(wrap, 100, 1);
输出是这样的:
关于javascript - d3 textwrap合并<b>和<em>标签,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37421900/