【问题标题】:How to measure text width with `italic` font style?如何使用“斜体”字体样式测量文本宽度?
【发布时间】:2018-03-26 11:45:01
【问题描述】:

我正在使用 convas context measureText 来获取画布上文本的宽度。下面是代码:

    ctx.fillStyle = color;
    ctx.fontWeight = FONT_WEIGHT;
    ctx.font = `bolder italic ${fontsize}px`;

    const textWidth = ctx.measureText(text).width;

问题是如果字体样式是italic,文本的右边会超出边界。那是因为measureText 没有考虑italic。如何计算italic 样式的文本宽度?

下面是 italic 字体在 convas 上的两个屏幕截图。第一个是没有斜体的文本,而第二个是斜体。您可以看到第二个有点超出界限。

【问题讨论】:

标签: javascript html5-canvas html2canvas


【解决方案1】:

这是字体及其容器框的斜体渲染所固有的问题。
我不是专家,不会扩展这个主题,这已经在Q/A 关于 DOM + CSS 中进行了处理。只需注意 2DCanvas measureText 也会遇到同样的问题。

我能想到的唯一解决方法是使用 svg 元素,它通过其getBBox 方法提供更好的图形边界框表示。

// Calculate the BBox of a text through an svg Element
function getTextBox(txt, x, y) {
  var svg = document.createElementNS("http://www.w3.org/2000/svg", 'svg');
  var text = document.createElementNS("http://www.w3.org/2000/svg", 'text');
  // so we don't see the svg element in page
  svg.style = 'position: absolute; z-index:-1; width:0; height: 0';
  text.setAttribute('x', x || 0);
  text.setAttribute('y', y || 0);
  text.setAttribute('text-anchor', getAlignment(this.textAlign));
  text.setAttribute('alignment-baseline', this.textBaseline);
  text.style.font = this.font;
  text.textContent = txt;
  svg.appendChild(text);
  document.body.appendChild(svg);
  var box = text.getBBox();
  document.body.removeChild(svg);
  return box;

  // convert CSS text-align notation to correpsonding SVG text-anchor
  function getAlignment(css) {
    return {
      'left': 'start',
      'right': 'end',
      'center': 'middle'
    }[css] || '';

  }
}
// attach it to the proto so it's easier to grab context's current status
Object.defineProperty(CanvasRenderingContext2D.prototype, 'getTextBox', {get: function() {return getTextBox;}});


var x = 20,
  y = 100;
var ctx = canvas.getContext('2d');
ctx.font = 'bolder italic 100px serif';
var txt = 'Right';
ctx.fillText(txt, x, y);
// red => ctx.measureText
var m_width = ctx.measureText(txt).width;
ctx.strokeStyle = 'red';
ctx.strokeRect(x, 0, m_width, y);
ctx.strokeStyle = 'green';
// green => svg.getBBox
var box = ctx.getTextBox(txt, x, y);
ctx.strokeRect(box.x, box.y, box.width, box.height);
<canvas id="canvas"></canvas>

【讨论】:

  • 这真的很酷,它在很多浏览器中都能很好地工作。我已经使用它很长时间了,但是我真的很不幸找到了一个不起作用的平台:(。它在 Webview 中的 iOS 13+ 上不起作用(它在以前版本的 iOS 中起作用)。任何知道为什么它不再工作或我能做什么?
【解决方案2】:

首先设置ctx.font。 ctx.measureText 的结果基于上下文的当前字体,如果您正在绘图,您会看到相同的字体。做一个ctx.fillText 来检查你的字体设置是否正确,我发现语法很容易出错。

【讨论】:

  • 在致电ctx.measureText 之前,我已经完成了ctx.font 并且我已经更新了我的答案。
【解决方案3】:

您需要将文本加载到隐藏的 HTML div 中并获得计算出的宽度。

【讨论】:

  • DOM 在这里受到同样的限制
猜你喜欢
  • 2011-01-31
  • 2010-12-13
  • 1970-01-01
  • 1970-01-01
  • 2020-06-02
  • 2011-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多