我正在构建一个图形,我想添加一个注释图层,它既包装文本也包含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()
足够聪明,可以包装此文本,并逐字加粗,甚至可能跨多行。 / p>
换句话说,我希望它能够在必要时进行标记:
左侧左侧
侧面左侧
左侧左侧......
MBostock的文本包装器将其搞砸了,因为:
words.reverse()
,从而混淆了自然的open-tag / close-tag <text>
和<tspan>
元素,据我所知,这些元素不支持内联<b>
或<em>
标记。 (他们确实支持像font-weight
和font-style
这样的CSS样式,但我不确定如何逐字逐句地进行,只是在tspan的基础上。而且我不愿意使用foreignObject
,因为它似乎没有广泛的浏览器支持。)我不确定最好的解决方法是什么。有没有人处理过这个问题?
谢谢,
亚历
答案 0 :(得分:4)
好的,我有一个粗略的解决方案。这可能是一种更清洁,更优雅的方式,但总体思路如下:
<tspan>
方法来测量文本的长度,以确定何时断行。 <tspan>
每行<tspan>
更大<b>
或<em>
标记已打开)并使用font-style
和{ {1}}相应的CSS属性。以下代码执行此操作,并处理多个滞后或单独的font-weight
(不是前导<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
}
});
}
输出是这样的: