簡體   English   中英

為什么canvas中的文字不能垂直居中

[英]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 還沒有。

這是規格中的圖形表示:

em 方格的頂部大致位於字體中字形的頂部,懸掛基線是一些像 आ 這樣的字形錨定的位置,中間是 em 方格頂部和 em 方格底部之間的中間位置, 字母基線是 Á、ÿ、f 和 Ω 等字符的錨定位置,表意下基線是諸如私和達之類的字形錨定的位置,而 em 正方形的底部大致位於一種字體。由於字形延伸到 em 方格之外,邊界框的頂部和底部可能遠離這些基線。

但是所有的希望都沒有失去,在過去的幾年里,所有的瀏覽器在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM