合理的文字
此示例呈现对齐文本。它通过扩展原型或作为全局对象 justifiedText
为 CanvasRenderingContext2D
增加了额外的功能(可选参见注释 A)。
示例渲染
用于呈现此图像的代码位于底部的用法示例中。
这个例子
该函数作为匿名立即调用函数。
(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);