> 脚本语言 > >
canvas文本绘制自动换行、字间距、竖排等实现 2018-02-05 12:05 出处:清屏网 人气:
一、canvas对文字排版的支持很弱
和CSS相比,SVG以及canvas对文字排版的支持很弱。
在CSS中天然支持的文本自动换行,其他 letter-sapcing 字间距, writing-mode 竖排等都是一个CSS属性就可以实现。但是在canvas中,全部都不支持。
canvas绘制文本API为:
CanvasRenderingContext2D.fillText(text, x, y [, maxWidth]);y 是文本绘制的垂直参考点坐标。随着 CanvasRenderingContext2D.textBaseline 的设置不同, y 的坐标位置也不同。支持多种基线类型(CSS中也有对应概念), MDN
上有一张图可以很好地表示文本基线和文本垂直位置的关系。
maxWidth 表示文本内容占据的最大宽度。这里的 maxWidth 概念和CSS中的 max-width 差别很大,其最终的文本表现是:当文本占据宽度超过 maxWidth
的后,所有的文本自动变窄以适应这个最大宽度限制。表现类似这样:
您可以狠狠地点击这里: maxWidth参数让文字变窄demo
相关测试代码如下:
var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); context.font = '32px sans-serif'; context.fillText('我是一段被maxWidth限制的文本', 0, 50, 200如果没有 maxWidth 限制,则文本会一行走到底,直到超出画布尺寸,有点类似CSS中设置容器 white-space:nowrap + overflow:hidden 的表现。
text text 是需要绘制的文本。 x x 是文本绘制的水平参考点坐标。随着 CanvasRenderingContext2D.textAlign 的设置不同, x 的坐标位置也不同。可以表示这段文字内容左侧坐标,或水平中心坐标,或右侧坐标。 y maxWidth 二、如何让canvas支持自动换行?如何让canvas支持自动换行?
首先有一点可以肯定,就是到目前为止,canvas中并没有任何可以让文本自动换行的现成的API。
因此注定这个看上去简单的事情实践起来并没有那么容易。
通常比较好的实现方法有下面两种:
1. canvas计算与逐行绘制实现原理的核心是 CanvasRenderingContext2D.measureText(text) 这个API,可以返回一个TextMetrics对象,其中包含了当前上下文环境下 text double 精度的占据宽度,于是我们就可以通过每个字符宽度的不断累加,精确计算哪个位置应该可以换行。
下面就是我扩展的文本自动换行方法JS代码:
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); };API如下:
CanvasRenderingContext2D.wrapText(text, x, y, maxWidth, lineHeight)其中 text , x , y 3个参数和 fillText() 方法中的这3个参数含义是一样的,不赘述。
而 maxWidth 表示的含义可就不一样了,表示最大需要换行的宽度,此参数可缺省,默认会使用canvas画布的 width 宽度作为 maxWidth ; lineHeight 表示行高,同样可缺省,默认会使用 <canvas> 元素在DOM中继承的 line-height 作为行高。
使用示例如下:
var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); context.font = '16px sans-serif'; context.textBaseline = 'top'; context.wrapText('我是一段会换行的文字啦啦啦', 0, 0);用法很简单,使用 wrapText 代替原生的 fillText 即可!
您可以狠狠的点击这里: 自动换行扩展API wrapText演示demo
下面截图就是demo页面绘制效果(截自IE9浏览器):
可以看到上方绘制的文字在核实位置自动换行了,您可以修改 <textarea> 中的文字内容,点击“绘制”按钮体验下其他文本内容的自动换行绘制效果。
2. 借助SVG <foreignObject>直接把CSS效果绘制上去关于SVG <foreignObject> 让HTML转换成canvas图片的原理和细节可以参见我之前写的“ SVG <foreignObject<简介与截图等应用 ”这篇文章。
基本上,本文后面会介绍到的字符间距,文字竖排等实现都可以使用这个方法实现,因此,为了避免不必要的啰嗦,仅本效果会具体演示代码细节,后面效果大家自行拷贝改改就好了。
我们先看实例,您可以狠狠地点击这里: canvas借助SVG foreignObject实现文本自动换行demo
结果Chrome浏览器下: