我正在构建图形,我想添加一个注释层,该注释层既可以包装文本,还可以合并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-weightfont-style之类的CSS样式,但是我不确定如何在逐字基础上(仅在tspan的基础上)做到这一点。而且我不愿意使用,因为它似乎没有广泛的浏览器支持。)


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

谢谢,

亚历克斯

最佳答案

好的,我有一个粗略的解决方案。可能有一种更干净,更优雅的方法,但是总体思路如下:


保留Mike的<tspan>方法来测量文本的长度以确定何时换行。
但是,在每行较大的<tspan>中为每个单词附加一个<tspan>
然后,要设置粗体和斜体样式,请跟踪到目前为止的文本状态(如果打开了<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);


输出是这样的:

javascript - d3 textwrap合并&lt;b&gt;和&lt;em&gt;标签-LMLPHP

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

10-12 13:46