如何用`italic`字体样式测量文本宽度?

时间:2018-03-25 11:40:38

标签: javascript html5-canvas html2canvas

我正在使用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样式的文本宽度?

以下是convas上italic字体的两个屏幕截图。第一个是没有斜体的文本,而第二个是斜体。你可以看到第二个有一点偏离边界。

enter image description here

enter image description here

3 个答案:

答案 0 :(得分: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>

答案 1 :(得分:0)

首先设置ctx.fontctx.measureText的结果基于上下文的当前字体,与您在绘图时看到的字体相同。执行ctx.fillText检查是否正确设置了字体,我发现语法很容易出错。

答案 2 :(得分:0)

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