本文共 9732 字,大约阅读时间需要 32 分钟。
letter-sapcing
字间距, writing-mode
竖排等都是一个CSS属性就可以实现。但是在canvas中,全部都不支持。 text
text
是需要绘制的文本。
x
x
是文本绘制的水平参考点坐标。随着CanvasRenderingContext2D.textAlign
的设置不同,x
的坐标位置也不同。可以表示这段文字内容左侧坐标,或水平中心坐标,或右侧坐标。
y
y
是文本绘制的垂直参考点坐标。随着CanvasRenderingContext2D.textBaseline
的设置不同,y
的坐标位置也不同。支持多种基线类型(CSS中也有对应概念),MDN上有一张图可以很好地表示文本基线和文本垂直位置的关系。
maxWidth
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
的表现。CanvasRenderingContext2D.measureText(text)
这个API,可以返回一个TextMetrics对象,其中包含了当前上下文环境下 text
double
精度的占据宽度,于是我们就可以通过每个字符宽度的不断累加,精确计算哪个位置应该可以换行。 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); };
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
即可! <textarea>
中的文字内容,点击“绘制”按钮体验下其他文本内容的自动换行绘制效果。 <foreignObject>
让HTML转换成canvas图片的原理和细节可以参见我之前写的“SVG <foreignObject<简介与截图等应用”这篇文章。 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, ';
style
样式的HTML代码即可! <foreignObject>
,最新的Firefox浏览器虽然支持 <foreignObject>
,但是只能以 <img<
形式呈现,无法绘制到canvas画布上(若谁知道原因欢迎不吝赐教)。 <canvas>
元素,这个特性让人非常感动。 canvas { letter-pacing: 5px; }
5px
。 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();
font
属性值的时候,把 letter-spacing
等信息一起算作上下文中了。所以,虽然看上去 context.font = '32px sans-serif'
一直都没变,但却不能放在 draw()
方法之外,否则,还是按照老的 letter-spacing
渲染而看不到字符间距变化。 CanvasRenderingContext2D.measureText(text)
这个API。 /** * @author zhangxinxu(.com) * @licence MIT * @description http://www.zhangxinxu.com/wordpress/?p=7362 */ 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; };
CanvasRenderingContext2D.letterSpacingText(text, x, y, letterSpacing);
text
, x
, y
3个参数和 fillText()
方法中的这3个参数含义是一样的,不赘述。 letterSpacing
表示字符间距大小,数值。可缺省,默认会拿 <canvas>
元素在DOM环境下的 letter-spacing
大小作为计算值。 var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); context.font = '32px sans-serif'; context.textAlign = 'center'; // 字符间隙5px context.letterSpacingText('我是一段文本', canvas.width / 2, 50, 5);
context.rotate()
旋转 90deg
实现,但是对于中文等中亚文字,却是完全不适合的。因为两种语言的竖直排版规则是不一样的。 writing-mode
改变文档流的方向,从而实现文字竖排,相关文章可以参见我之前的文章:“改变CSS世界纵横规则的writing-mode属性”,或者购买我的《CSS世界》,其中有详细介绍。 /* @author zhangxinxu(.com)@licence MIT@description http://www.zhangxinxu.com/wordpress/?p=7362*/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;};
fillTextVertical
,语法如下: CanvasRenderingContext2D.fillTextVertical(text, x, y)
text
, x
, y
3个参数和 fillText()
方法中的这3个参数含义是一样的,不赘述。 textAlign
和 textBaseline
等基本设置。 var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); context.font = '24px STKaiti, sans-serif'; context.textAlign = 'center'; context.textBaseline = 'top'; context.fillTextVertical('anglebaby和黄晓明', canvas.width / 2, 0);
转载地址:http://jyfpi.baihongyu.com/