SVG text 自动换行算法

最近做的项目涉及到 web 绘图,采用 d3 操作 svg 实现。图中通常会用到文本,而 svg 里的 text 元素不像普通 DOM 元素那样能很好地处理文本换行,所以要用到一些技巧。

通常有两种做法。

  1. tspantext 拆成多行,重新计算每个tspany 坐标。

  
    较长文文本一行
    放不下就换行
  

  1. foreignObject 包裹 DOM 元素,利用 DOM 的文本布局能力自动处理换行。

  
      
        

较长文文本一行放不下就换行

两种方法各有千秋,方法1可以精确控制换行位置,但是需要计算具体的坐标。方法2无需计算内部坐标,但它是根据单词来分割的,针对长英文单词也无能为力。

笔者碰到的就是单个长英文单词也要换行显示,所以只能用方法1。产品需求是文本根据屏幕大小自动适配,如果宽度不够就换行显示。效果如下图所示:


雷达图

Outperformance 这个单词被截断。原理就是先在 text 元素下插入一个tspan,将单词里的字母逐个填进去,判断元素宽度是否达到限制。如果超过限制就再插入一个 tspan,同时计算新 tspany坐标。由于事先知道 text的具体位置,x保持一致就可以了。代码如下:

function wrapWord(text, width) {
  text.each(function() {
    var text = d3.select(this),
      words = text.text().split('').reverse(),
      word,
      line = [],
      lineNumber = 0,
      lineHeight = text.node().getBoundingClientRect().height,
      x = +text.attr('x'),
      y = +text.attr('y'),
      tspan = text.text(null).append('tspan').attr('x', x).attr('y', y);
    while (word = words.pop()) {
      line.push(word);
      const dash = lineNumber > 0 ? '-' : '';
      tspan.text(dash + line.join(''));
      if (tspan.node().getComputedTextLength() > width) {
        line.pop();
        tspan.text(line.join(''));
        line = [word];
        tspan = text.append('tspan').attr('x', x).attr('y', ++lineNumber * lineHeight + y).text(word);
      }
    }
  });
}

各位看官如果有更好的办法,欢迎评论,不吝赐教!

你可能感兴趣的:(SVG text 自动换行算法)