javascript - 为什么画布中的文本不能垂直居中
问题描述
CanvasRenderingContext2D.prototype.roundRect = function (
x,
y,
width,
height,
radius
) {
if (width < 2 * radius) radius = width / 2;
if (height < 2 * radius) radius = height / 2;
this.beginPath();
this.moveTo(x + radius, y);
this.arcTo(x + width, y, x + width, y + height, radius);
this.arcTo(x + width, y + height, x, y + height, radius);
this.arcTo(x, y + height, x, y, radius);
this.arcTo(x, y, x + width, y, radius);
this.closePath();
return this;
};
let generateCanvas = function (config) {
var tmpCanvas = document.createElement("canvas");
var tmpContext = tmpCanvas.getContext("2d");
tmpContext.font = tmpContext.font.replace(/\d+px/, config.fontSize);
var textWidth = tmpContext.measureText(config.text).width || 10;
tmpCanvas = null;
var textCanvas = document.createElement("canvas");
var textContext = textCanvas.getContext("2d");
textCanvas.height = config.height;
textCanvas.width = textWidth;
textCanvas.width = textWidth + 2 * config.padding;
textContext.lineWidth = config.lineWidth;
textContext.strokeStyle = config.lineColor;
textContext.fillStyle = config.backgroundColor;
textContext.roundRect(
0,
0,
textCanvas.width,
textCanvas.height,
config.rounded
);
textContext.stroke();
textContext.fill();
textContext.fillStyle = config.color;
textContext.font = textContext.font.replace(/\d+px/, config.fontSize);
textContext.textAlign = config.textAlign;
textContext.textBaseline = config.textBaseline;
textContext.fillText(
config.text,
textCanvas.width / 2,
config.height / 2
);
return textCanvas;
};
我传递给 generateCanvas 函数的配置是:
{
text: "测试名称测试名称测试名称测试名称",
height: 40,
fontSize: "24px",
textAlign: "center",
textBaseline: "middle",
color: "#F9A403",
backgroundColor: "white",
lineColor: "transparent",
rounded: 25,
padding: 10,
}
为什么上述函数生成的图像中的文字没有垂直居中?roundRect 是一个自定义函数,实现了使用canvas绘制圆角矩形,有大神帮忙看看这个问题。
解决方案
的"middle"
值textBaseline
基于em-square。这意味着它适用于拉丁字形,但不适用于表意字形,它需要一个以表意为中心的基线值,而 Canvas API 还没有。
这是规格中的图形表示:
但所有的希望都没有落空,在过去的几年里,所有的浏览器在TextMetrics接口的实现上都取得了一些进展,我们终于可以从所有主流浏览器获得足够的信息来测量被测量文本的高度。
这意味着我们可以根据正在渲染的字形实现真正居中的垂直对齐:
const text_input = document.querySelector("input[type='text']");
const padding_input = document.querySelector("input[type='range']");
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");;
const font = "60px sans-serif";
let padding_x = 10;
let padding_y = 10;
text_input.oninput = padding_input.oninput =
(evt) => drawText(text_input.value);
drawText(text_input.value);
// returns an easier to use BBox like object
// from a TextMetrics object
function getTextBBox( ctx, text ) {
const metrics = ctx.measureText( text );
const left = metrics.actualBoundingBoxLeft * -1;
const top = metrics.actualBoundingBoxAscent * -1;
const right = metrics.actualBoundingBoxRight;
const bottom = metrics.actualBoundingBoxDescent;
const width = right - left;
const height = bottom - top;
return { left, top, right, bottom, width, height };
}
function drawText( text ) {
// we set only the font
// other values like textBaseline and textAlign
// are left to their default
ctx.font = font;
const bbox = getTextBBox(ctx, text);
const padding = +padding_input.value;
canvas.width = bbox.width + padding;
canvas.height = bbox.height + padding;
ctx.font = font;
ctx.fillStyle = "#F9A403";
const middle_x = bbox.left + (bbox.width / 2);
const middle_y = bbox.top + (bbox.height / 2);
const left = canvas.width / 2 - middle_x;
const top = canvas.height / 2 - middle_y;
ctx.fillText(text, left, top);
// draw the middle line for reference
ctx.fillStyle = "red";
ctx.fillRect(0, canvas.height/2-1, canvas.width, 2);
}
canvas { border: 1px solid; }
<label>Text content: <input type="text" value="测试名称测试名称测试名称测试名称"></label><br>
<label>Padding: <input type="range" min="0" max="100"></label><br>
<canvas></canvas>
推荐阅读
- python - 从 GLCM 中提取 Haralick 特征。为什么我会为每个功能获得多个值?
- javascript - 为什么 Alert 函数的执行速度比 javascript 中的任何其他函数都快?
- jquery - AJAX 发布不向控制器发送数据
- google-apps-script - Switch tab [active sheet] by script
- google-cloud-platform - Run dataflow job from Compute Engine
- android - 应用启动器图标更改为奥利奥上的默认图标
- javascript - 数字格式问题
- python - 当递归非常深入时,理解中的递归调用有什么特别之处?
- linux - 以低延迟访问 PCI 内存条 (Linux)
- android - Restarting service after reboot by using Broadcastreceiver is not working