gpt4 book ai didi

javascript - d3 textwrap 合并 标签

转载 作者:行者123 更新时间:2023-11-30 09:49:01 26 4
gpt4 key购买 nike

我正在构建一个图形,我想添加一个注释层,它既可以包装文本,也可以包含 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 的文本包装器搞砸了,因为:

  1. 它调用 words.reverse() ,从而混淆了自然的打开标签/关闭标签
  2. 它依赖于 <text><tspan> 元素,据我所知,它们不支持内联 <b><em> 标签。 (他们确实支持像 font-weightfont-style 这样的 CSS 样式,但我不确定如何逐字逐句地做到这一点,只是在 tspan 的基础上。而且我不愿意使用 foreignObject 因为它不似乎有广泛的浏览器支持。)

我不确定最好的解决方法是什么。有没有人处理过这个问题?

谢谢,

亚历克斯

最佳答案

好的,我有一个粗略的解决方案。可能有一种更简洁、更优雅的方法来执行此操作,但总体思路如下:

  1. 保护迈克的 <tspan>测量文本长度以确定何时换行的方法。
  2. 但是,附加一个 <tspan>对于 中的每个单词,较大的 <tspan>每行
  3. 然后,为了设置粗体和斜体的样式,我们跟踪到目前为止文本的状态(如果 <b><em> 标签打开)并使用 font-stylefont-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);

输出是这样的:

sample

关于javascript - d3 textwrap 合并 <b> 和 <em> 标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37421900/

26 4 0