合理的文字

此示例呈現對齊文字。它通過擴充套件原型或作為全域性物件 justifiedTextCanvasRenderingContext2D 增加了額外的功能(可選參見注釋 A)。

示例渲染

StackOverflow 文件
用於呈現此影象的程式碼位於底部的用法示例中

這個例子

該函式作為匿名立即呼叫函式。

(function(){
    const FILL = 0;        // const to indicate filltext render
    const STROKE = 1;
    const MEASURE = 2;
    var renderType = FILL; // used internal to set fill or stroke text
    
    var maxSpaceSize = 3; // Multiplier for max space size. If greater then no justificatoin applied
    var minSpaceSize = 0.5; // Multiplier for minimum space size
    var renderTextJustified = function(ctx,text,x,y,width){
        var words, wordsWidth, count, spaces, spaceWidth, adjSpace, renderer, i, textAlign, useSize, totalWidth;
        textAlign = ctx.textAlign; // get current align settings
        ctx.textAlign = "left";
        wordsWidth = 0;
        words = text.split(" ").map(word => {
            var w = ctx.measureText(word).width;                
            wordsWidth += w;
            return {
                width : w,
                word : word,
            };
        });
        // count = num words, spaces = number spaces, spaceWidth normal space size
        // adjSpace new space size >= min size. useSize Resulting space size used to render
        count = words.length;
        spaces = count - 1;
        spaceWidth = ctx.measureText(" ").width;
        adjSpace = Math.max(spaceWidth * minSpaceSize, (width - wordsWidth) / spaces);
        useSize = adjSpace > spaceWidth * maxSpaceSize ? spaceWidth : adjSpace;
        totalWidth = wordsWidth + useSize * spaces
        if(renderType === MEASURE){ // if measuring return size
            ctx.textAlign = textAlign;
            return totalWidth;
        }
        renderer = renderType === FILL ? ctx.fillText.bind(ctx) : ctx.strokeText.bind(ctx); // fill or stroke
        switch(textAlign){
            case "right":
                x -= totalWidth;
                break;
            case "end":
                x += width - totalWidth;
                break;
            case "center": // intentional fall through to default
                x -= totalWidth / 2;                     
            default:
        }
        if(useSize === spaceWidth){ // if space size unchanged
            renderer(text,x,y);
        } else {
            for(i = 0; i < count; i += 1){
                renderer(words[i].word,x,y);
                x += words[i].width;
                x += useSize;
            }
        }
        ctx.textAlign = textAlign;
    }
    // Parse vet and set settings object.
    var justifiedTextSettings = function(settings){
        var min,max;
        var vetNumber = (num, defaultNum) => {
            num = num !== null && num !== null && !isNaN(num) ? num : defaultNum;
            if(num < 0){
                num = defaultNum;
            }
            return num;
        }
        if(settings === undefined || settings === null){
            return;
        }
        max = vetNumber(settings.maxSpaceSize, maxSpaceSize);
        min = vetNumber(settings.minSpaceSize, minSpaceSize);
        if(min > max){
            return;
        }
        minSpaceSize = min;
        maxSpaceSize = max;
    }
    // define fill text
    var fillJustifyText = function(text, x, y, width, settings){
        justifiedTextSettings(settings);
        renderType = FILL;
        renderTextJustified(this, text, x, y, width);
    }
    // define stroke text
    var strokeJustifyText = function(text, x, y, width, settings){
        justifiedTextSettings(settings);
        renderType = STROKE;
        renderTextJustified(this, text, x, y, width);
    }
    // define measure text
    var measureJustifiedText = function(text, width, settings){
        justifiedTextSettings(settings);
        renderType = MEASURE;
        return renderTextJustified(this, text, 0, 0, width);
    }
    // code point A
    // set the prototypes
    CanvasRenderingContext2D.prototype.fillJustifyText = fillJustifyText;
    CanvasRenderingContext2D.prototype.strokeJustifyText = strokeJustifyText;
    CanvasRenderingContext2D.prototype.measureJustifiedText = measureJustifiedText;  
    // code point B
    
    // optional code if you do not wish to extend the CanvasRenderingContext2D prototype
    /* Uncomment from here to the closing comment
    window.justifiedText = {
        fill : function(ctx, text, x, y, width, settings){
            justifiedTextSettings(settings);
            renderType = FILL;
            renderTextJustified(ctx, text, x, y, width);
        },
        stroke : function(ctx, text, x, y, width, settings){
            justifiedTextSettings(settings);
            renderType = STROKE;
            renderTextJustified(ctx, text, x, y, width);
        },
        measure : function(ctx, text, width, settings){
            justifiedTextSettings(settings);
            renderType = MEASURE;
            return renderTextJustified(ctx, text, 0, 0, width);
        }
    }
    to here*/
})();

注意 - 答: 如果你不想擴充套件 CanvasRenderingContext2D 原型從示例中刪除// code point A// code point B 之間的所有程式碼並取消註釋標記為/* Uncomment from here to the closing comment 的程式碼

如何使用

CanvasRenderingContext2D 中新增了三個函式,可用於建立的所有 2D 上下文物件。

  • ctx.fillJustifyText(text,x,y,width,[settings]);
  • ctx.strokeJustifyText(text,x,y,width,[settings]);
  • ctx.measureJustifiedText(text,width,[settings]);

填充和描邊文字功能填充或描邊文字並使用相同的引數。measureJustifiedText 將返回文字將呈現的實際寬度。根據當前設定,這可能等於,小於或大於引數 width

注意: [] 中的引數是可選的。

函式引數

  • text: 包含要呈現的文字的字串。

  • x,y: 用於渲染文字的座標。

  • width: 對齊文字的寬度。文字將增加/減少單詞之間的空格以適合寬度。如果單詞之間的空格大於 maxSpaceSize(預設值= 6),則將使用正常間距,文字將不會填充所需的寬度。如果間距小於 minSpaceSize(預設值= 0.5)時間正常間距,則使用最小空間大小,文字將超出請求的寬度

  • 設定: 可選。包含最小和最大空間大小的物件。

settings 引數是可選的,如果不包括在內,文字渲染將使用最後定義的設定或預設值(如下所示)。

min 和 max 都是分隔單詞的[space]字元的最小和最大尺寸。預設的 maxSpaceSize = 6 表示當字元之間的空格大於 63 * ctx.measureText(“”)時 .with text 文字將不合理。如果要對齊的文字的空格小於 minSpaceSize = 0.5(預設值 0.5)* ctx.measureText(" ").width,則間距將設定為 minSpaceSize * ctx.measureText(" ").width,結果文字將超出對齊寬度。

應用以下規則,min 和 max 必須是數字。如果不是,則不會更改關聯值。如果 minSpaceSize 大於 maxSpaceSize,則兩個輸入設定均無效,最大最大值不會改變。

具有預設值的示例設定物件

settings = { 
    maxSpaceSize : 6;   // Multiplier for max space size. 
    minSpaceSize : 0.5; // Multiplier for minimum space size
};

注意: 這些文字函式為 2D 上下文的 textAlign 屬性引入了微妙的行為更改。 ’left’,‘right’,‘center’和’start’表現得像預期的那樣,但’end’不會從函式引數 x 的右邊開始,而是從 x + width 的右邊開始對齊

注意: 設定(最小和最大空間大小)對所有 2D 上下文物件都是全域性的。

用法示例

var i = 0;
text[i++] = "This text is aligned from the left of the canvas."; 
text[i++] = "This text is near the max spacing size"; 
text[i++] = "This text is way too short."; 
text[i++] = "This text is too long for the space provied and will overflow#";
text[i++] = "This text is aligned using 'end' and starts at x + width"; 
text[i++] = "This text is near the max spacing size"; 
text[i++] = "This text is way too short."; 
text[i++] = "#This text is too long for the space provied and will overflow";
text[i++] = "This is aligned with 'center' and is placed from the center"; 
text[i++] = "This text is near the max spacing size"; 
text[i++] = "This text is way too short."; 
text[i++] = "This text is just too long for the space provied and will overflow";

// ctx is the 2d context
// canvas is the canvas

ctx.clearRect(0,0,w,h);
ctx.font = "25px arial";
ctx.textAlign = "center"
var left = 20;
var center = canvas.width / 2;
var width = canvas.width-left*2;
var y = 40;
var size = 16;
var i = 0;
ctx.fillText("Justified text examples.",center,y);
y+= 40;
ctx.font = "14px arial";
ctx.textAlign = "left"
var ww = ctx.measureJustifiedText(text[0], width);
var setting = {
    maxSpaceSize : 6,
    minSpaceSize : 0.5
}
ctx.strokeStyle = "red"
ctx.beginPath();
ctx.moveTo(left,y - size * 2);
ctx.lineTo(left, y + size * 15);
ctx.moveTo(canvas.width - left,y - size * 2);
ctx.lineTo(canvas.width - left, y + size * 15);
ctx.stroke();
ctx.textAlign = "left";
ctx.fillStyle = "red";
ctx.fillText("< 'left' aligned",left,y - size)
ctx.fillStyle = "black";
ctx.fillJustifyText(text[i++], left, y, width, setting);  // settings is remembered
ctx.fillJustifyText(text[i++], left, y+=size, width);
ctx.fillJustifyText(text[i++], left, y+=size, width);
ctx.fillJustifyText(text[i++], left, y+=size, width);
y += 2.3*size;
ctx.fillStyle = "red";
ctx.fillText("< 'end' aligned from x plus the width -------------------->",left,y - size)
ctx.fillStyle = "black";
ctx.textAlign = "end";
ctx.fillJustifyText(text[i++], left, y, width);
ctx.fillJustifyText(text[i++], left, y+=size, width);
ctx.fillJustifyText(text[i++], left, y+=size, width);
ctx.fillJustifyText(text[i++], left, y+=size, width);

y += 40;
ctx.strokeStyle = "red"
ctx.beginPath();
ctx.moveTo(center,y - size * 2);
ctx.lineTo(center, y + size * 5);
ctx.stroke();
ctx.textAlign = "center";
ctx.fillStyle = "red";
ctx.fillText("'center' aligned",center,y - size)
ctx.fillStyle = "black";
ctx.fillJustifyText(text[i++], center, y, width);
ctx.fillJustifyText(text[i++], center, y+=size, width);
ctx.fillJustifyText(text[i++], center, y+=size, width);
ctx.fillJustifyText(text[i++], center, y+=size, width);