canvas有text的measureText方法可以获取TextMetrics对象中包含了text的文字信息。通过TextMetrics我们可以直接获得文字的width值,但是却不能直接获得height值。
一、TextMetrics
double 类型,使用 CSS 像素计算的内联字符串的宽度。基于当前上下文字体考虑。
TextMetrics.actualBoundingBoxLeft (en-US) 只读
double 类型,平行于基线,从CanvasRenderingContext2D.textAlign 属性确定的对齐点到文本矩形边界左侧的距离,使用 CSS 像素计算;正值表示文本矩形边界左侧在该对齐点的左侧。
TextMetrics.actualBoundingBoxRight (en-US) 只读
double 类型,平行于基线,从CanvasRenderingContext2D.textAlign 属性确定的对齐点到文本矩形边界右侧的距离,使用 CSS 像素计算。
TextMetrics.fontBoundingBoxAscent (en-US) 只读
double 类型,从CanvasRenderingContext2D.textBaseline 属性标明的水平线到渲染文本的所有字体的矩形最高边界顶部的距离,使用 CSS 像素计算。
TextMetrics.fontBoundingBoxDescent (en-US) 只读
double 类型,从CanvasRenderingContext2D.textBaseline 属性标明的水平线到渲染文本的所有字体的矩形边界最底部的距离,使用 CSS 像素计算。
TextMetrics.actualBoundingBoxAscent (en-US) 只读
double 类型,从CanvasRenderingContext2D.textBaseline 属性标明的水平线到渲染文本的矩形边界顶部的距离,使用 CSS 像素计算。
TextMetrics.actualBoundingBoxDescent (en-US) 只读
double 类型,从CanvasRenderingContext2D.textBaseline 属性标明的水平线到渲染文本的矩形边界底部的距离,使用 CSS 像素计算。
参考:https://developer.mozilla.org/zh-CN/docs/Web/API/TextMetrics
二、计算宽高
<canvas id="canvas" width="550" height="500"></canvas>
1、测量文本宽度
当测量一段文本的水平宽度时,由于字母倾斜/斜体导致字符的宽度可能超出其预定的宽度,因此 actualBoundingBoxLeft
和 actualBoundingBoxRight
的总和可能会比内联盒子的宽度(width
)更大。
因此,计算 actualBoundingBoxLeft
和 actualBoundingBoxRight
的总和是一种更准确地获取文本绝对宽度的方法:
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、测量文本高度
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;
三、实例应用
1、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标签计算文本宽高
注意:字体大小最小只能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}`)