The method of calculating the width and height of text in canvas

Canvas has the measureText method of text to get the text information contained in the TextMetrics object. Through TextMetrics, we can directly obtain the width value of the text, but we cannot directly obtain the height value.

一、TextMetrics

TextMetrics.width  read-only

Double  type, the width of the inline string in CSS pixels. Based on current context font considerations.

TextMetrics.actualBoundingBoxLeft (en-US)  read-only

double  type, parallel to the baseline, the distance from  the alignment point determined by the CanvasRenderingContext2D.textAlign property to the left side of the text rectangle boundary , calculated using CSS pixels; a positive value indicates that the left side of the text rectangle boundary is on the left side of the alignment point.

TextMetrics.actualBoundingBoxRight (en-US)  read-only

double  type, parallel to the baseline, the distance from  the alignment point determined by the CanvasRenderingContext2D.textAlign property to the right side of the border of the text rectangle , calculated in CSS pixels.

TextMetrics.fontBoundingBoxAscent (en-US) 只读

Double  type, the distance from  the horizontal line indicated by the CanvasRenderingContext2D.textBaseline property to the top of the rectangle's highest border of all fonts used to render the text , calculated in CSS pixels.

TextMetrics.fontBoundingBoxDescent (en-US) 只读

Double type, the distance  from  the horizontal line indicated by the CanvasRenderingContext2D.textBaseline property to the bottommost rectangle boundary of all fonts used to render the text, calculated using CSS pixels.

TextMetrics.actualBoundingBoxAscent (en-US)  read-only

Double  type, the distance from  the horizontal line indicated by the CanvasRenderingContext2D.textBaseline property to the top of the rectangle bounding the rendered text , calculated in CSS pixels.

TextMetrics.actualBoundingBoxDescent (en-US)  read-only

Double  type, the distance from  the horizontal line indicated by the CanvasRenderingContext2D.textBaseline property to the bottom of the rectangle bounding the rendered text , calculated in CSS pixels.

Reference: https://developer.mozilla.org/zh-CN/docs/Web/API/TextMetrics

Second, calculate the width and height

<canvas id="canvas" width="550" height="500"></canvas>

 1. Measure text width

 When measuring the horizontal width of a piece of text, the sum of the sum may be larger than the width of the inline box ( ) due to slanted/italic letters that cause characters to be wider than their intended width  actualBoundingBoxLeft . actualBoundingBoxRightwidth

So computing  actualBoundingBoxLeft the  actualBoundingBoxRight sum of the sum is a more accurate way to get the absolute width of the text:

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const text = "Abcdefghijklmnop";
ctx.font = "italic 50px serif";

const textMetrics = ctx.measureText(text);

console.log(textMetrics.width);
// 459.8833312988281

console.log(
  textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft,
);
// 462.8833333333333

2. Measure text height

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const text = "Abcdefghijklmnop";
ctx.font = "italic 50px serif";

const textMetrics = ctx.measureText(text);

// 所有字在这个字体下的高度
let fontHeight = textMetrics.fontBoundingBoxAscent + textMetrics.fontBoundingBoxDescent; 

// 当前文本字符串在这个字体下用的实际高度
let actualHeight = textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent; 

3. Example application

1. Implement multi-line text in canvas

// canvas多行文本

; (function (global) {
  "use strict";

  /**
   * 
   * @param {*} showStroke 是否显示描边
   * @param {*} text 文本
   * @param {*} x 中心点x坐标
   * @param {*} y 中心点y坐标
   * @param {*} maxWidth 最大宽度
   * @param {*} lineHeight 行高
   * @returns 
   */
  global.CanvasRenderingContext2D.prototype.wrapText = function (showStroke, text, x, y, maxWidth, lineHeight) {
    if (typeof text != 'string' || typeof x != 'number' || typeof y != 'number') {
      return;
    }

    var context = this;
    var canvas = context.canvas;

    if (typeof maxWidth == 'undefined') {
      maxWidth = (canvas && canvas.width) || 300;
    }
    
    if (typeof lineHeight == 'undefined') {
      lineHeight = (canvas && parseInt(window.getComputedStyle(canvas).lineHeight)) || parseInt(window.getComputedStyle(document.body).lineHeight);
    }

    // 字符分隔为数组
    var arrText = text.split('');
    var line = '';

    for (let n = 0; n < arrText.length; n++) {

      let testLine = line;
     
      // 换行符
      if(arrText[n] === '\n') {
        showStroke && context.strokeText(line, x, y);
        context.fillText(line, x, y);

        line = '';
        y += lineHeight; // 行高
      } else {
        testLine = line + arrText[n];
        let metrics = context.measureText(testLine, context.font);
        // 计算文本宽度
        let testWidth = metrics.actualBoundingBoxRight + metrics.actualBoundingBoxLeft;

        if (testWidth > maxWidth && n > 0) {
          
          showStroke && context.strokeText(line, x, y);
          context.fillText(line, x, y);

          line = arrText[n];
          y += lineHeight;
        } else {
          line = testLine;
        }
      }
    }
    showStroke && context.strokeText(line, x, y);
    context.fillText(line, x, y);
  };

})(window);
this.ctx.wrapText(true, '文本', 20, 20, 100, 20)

 

2. HTML tags calculate text width and height

Note: The minimum font size can only be 12px

/*
 * html计算文本宽高
 */
; (function (global) {
  "use strict";
 
  global.TextNode = function () {
 
    /**
   * 
   * @param {*} text 文本
   * @param {*} font 字体样式
   * @param {*} width 标签宽度
   * @param {*} height 标签高度
   * @returns 
   */
    const _getTextWH = function (text, font, width, height) {
      const $span = global.document.createElement("span");
      $span.innerHTML = text

      // const spanTextNode = global.document.createTextNode(text);
      // $span.appendChild(spanTextNode);
      $span.setAttribute("style", `font: ${font}; white-space: pre-wrap; position: fixed; top: 0; left: 0; display: block; line-height: 1; width: ${width ? width : 'auto'}; height: ${height ? height : 'auto'}`);
 
 
      const $body = global.document.getElementsByTagName("body")[0];
      $body.appendChild($span);

      const spanRect = $span.getBoundingClientRect();
 
      $body.removeChild($span);

      // console.log(spanRect.width, spanRect.height)
 
      return {
        width: spanRect.width,
        height: spanRect.height
      }

    }.bind(this);
 
    let _txt = _getTextWH(...arguments);
    
    // console.log('_txt', _txt)

    return {
      width: _txt.width,
      height: _txt.height
    };
  };
 
})(window);
let _txt = TextNode('智能字幕', `${data.fontSize}px ${data.fontFamily}`)

Guess you like

Origin blog.csdn.net/qq_31851435/article/details/132478478