canvas 绘制文本自动换行

终于找到一个 canvas 自动换行的处理脚本,记录啊下来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
CanvasRenderingContext2D.prototype.wrapText = function (text, x, y, maxWidth, lineHeight) {
if (typeof text != 'string' || typeof x != 'number' || typeof y != 'number') {
return;
}

var context = this;
var canvas = context.canvas;

if (typeof maxWidth == 'undefined') {
maxWidth = (canvas && canvas.width) || 300;
}
if (typeof lineHeight == 'undefined') {
lineHeight = (canvas && parseInt(window.getComputedStyle(canvas).lineHeight)) || parseInt(window.getComputedStyle(document.body).lineHeight);
}

// 字符分隔为数组
var arrText = text.split('');
var line = '';

for (var n = 0; n < arrText.length; n++) {
var testLine = line + arrText[n];
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
context.fillText(line, x, y);
line = arrText[n];
y += lineHeight;
} else {
line = testLine;
}
}
context.fillText(line, x, y);
};

link: canvas文本绘制自动换行、字间距、竖排等实现
example :自动换行扩展API wrapText演示demo

在链接页面还带着一些特效

  1. 借助SVG 直接把CSS效果绘制上去

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var canvas = document.querySelector('canvas');
    var context = canvas.getContext('2d');
    context.font = '16px sans-serif';
    var width = canvas.width;
    var height = canvas.height;
    var tempImg = new Image();
    tempImg.width = width;
    tempImg.height = height;
    tempImg.onload = function () {
    // 把img绘制在canvas画布上
    context.drawImage(this, 0, 0, width, height);
    };
    tempImg.src = 'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg"><foreignObject width="'+ width +'" height="'+ height +'"><body xmlns="http://www.w3.org/1999/xhtml" style="margin:0;font:'+ context.font +';">我是一段需要换行的文字啦啦啦</body></foreignObject></svg>';
    link [canvas借助SVG foreignObject实现文本自动换行demo](http://www.zhangxinxu.com/study/201802/canvas-wraptext-foreignobject.html)
  2. canvas支持字符间距
    使用 cssletter-spacing 属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var canvas = document.querySelector('canvas');
    var context = canvas.getContext('2d');
    var range = document.querySelector('input[type=range]');
    // 绘制方法
    var draw = function () {
    // 清除之前的绘制
    context.clearRect(0, 0, canvas.width, canvas.height);
    // 字符间距设置
    canvas.style.letterSpacing = range.value + 'px';
    // 并绘制文本,font属性值设置一定要在这里
    context.font = '32px sans-serif';
    context.fillText('我是一段文本', 0, 50);
    };
    // 改变字符间距后重绘
    range.addEventListener('change', draw);
    // 一进来根据默认值绘制
    draw();

使用 canvas 计算逐字绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
CanvasRenderingContext2D.prototype.letterSpacingText = function (text, x, y, letterSpacing) {
var context = this;
var canvas = context.canvas;

if (!letterSpacing && canvas) {
letterSpacing = parseFloat(window.getComputedStyle(canvas).letterSpacing);
}
if (!letterSpacing) {
return this.fillText(text, x, y);
}

var arrText = text.split('');
var align = context.textAlign || 'left';

// 这里仅考虑水平排列
var originWidth = context.measureText(text).width;
// 应用letterSpacing占据宽度
var actualWidth = originWidth + letterSpacing * (arrText.length - 1);
// 根据水平对齐方式确定第一个字符的坐标
if (align == 'center') {
x = x - actualWidth / 2;
} else if (align == 'right') {
x = x - actualWidth;
}

// 临时修改为文本左对齐
context.textAlign = 'left';
// 开始逐字绘制
arrText.forEach(function (letter) {
var letterWidth = context.measureText(letter).width;
context.fillText(letter, x, y);
// 确定下一个字符的横坐标
x = x + letterWidth + letterSpacing;
});
// 对齐方式还原
context.textAlign = align;
};

  1. canvas支持竖直排列

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     CanvasRenderingContext2D.prototype.fillTextVertical = function (text, x, y) {
    var context = this;
    var canvas = context.canvas;

    var arrText = text.split('');
    var arrWidth = arrText.map(function (letter) {
    return context.measureText(letter).width;
    });

    var align = context.textAlign;
    var baseline = context.textBaseline;

    if (align == 'left') {
    x = x + Math.max.apply(null, arrWidth) / 2;
    } else if (align == 'right') {
    x = x - Math.max.apply(null, arrWidth) / 2;
    }
    if (baseline == 'bottom' || baseline == 'alphabetic' || baseline == 'ideographic') {
    y = y - arrWidth[0] / 2;
    } else if (baseline == 'top' || baseline == 'hanging') {
    y = y + arrWidth[0] / 2;
    }

    context.textAlign = 'center';
    context.textBaseline = 'middle';

    // 开始逐字绘制
    arrText.forEach(function (letter, index) {
    // 确定下一个字符的纵坐标位置
    var letterWidth = arrWidth[index];
    // 是否需要旋转判断
    var code = letter.charCodeAt(0);
    if (code <= 256) {
    context.translate(x, y);
    // 英文字符,旋转90°
    context.rotate(90 * Math.PI / 180);
    context.translate(-x, -y);
    } else if (index > 0 && text.charCodeAt(index - 1) < 256) {
    // y修正
    y = y + arrWidth[index - 1] / 2;
    }
    context.fillText(letter, x, y);
    // 旋转坐标系还原成初始态
    context.setTransform(1, 0, 0, 1, 0, 0);
    // 确定下一个字符的纵坐标位置
    var letterWidth = arrWidth[index];
    y = y + letterWidth;
    });
    // 水平垂直对齐方式还原
    context.textAlign = align;
    context.textBaseline = baseline;
    };
  • Post author: hainuo
  • Post link: canvas-text-auto-wrap
  • Copyright Notice: All articles in this blog are licensed under BY-NC-SA unless stating additionally.