[英]Why the text in canvas can't be centered vertically
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 function 的配置是:
{
text: "測試名稱測試名稱測試名稱測試名稱",
height: 40,
fontSize: "24px",
textAlign: "center",
textBaseline: "middle",
color: "#F9A403",
backgroundColor: "white",
lineColor: "transparent",
rounded: 25,
padding: 10,
}
為什么上面的function生成的圖片中的文字沒有垂直居中? roundRect 是一個自定義的 function 實現了使用 canvas 繪制圓角矩形。請各位大神幫忙看看這個問題。
textBaseline
的"middle"
值基於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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.