小程序制作海报的话,不得不提的是canvas的操作,相信不少人都做过关于分享图片,然后带一个自己的二维码之类的海报,做起来感觉还是相当简单的,但是如果想做一款自由度高的并且百分百还原的海报小程序并不是想象中那么简单。
如果说我们是做H5项目的话,完全不用担心,使用html2Canvas完全可以实现将DOM元素转换为画布,但是在小程序中,DOM的操作并不一样,HTML2canvas的功能我们无法使用,也就只能通过canvas提供的一些文字的方法去进行,然而终会遇上下面几种问题。
1.关于文字换行的问题
在canvas中提供了这个方法让我们绘制文字,定位问题暂时不考虑,就这个最大宽度而言,完全是没有任何用处可言,当你所绘制的文字超出了这个最大宽度之后会出新什么样的问题呢?
在w3c的在线编辑器里面试了一下,是这个效果,整个文本内容被压缩至你定义的最大宽度,这样肯定是不行的,但是在真正的项目中,我们的文本框是可以自由设置宽度的,通过宽度来改变文字换行的效果,
既然这样子,我们就要想办法去判断文本要在什么时候换行,计算出来换行之后的X Y的值。
如果你想用fontsize来表示文字的宽度,或者是加上字间距,通过这个来计算文字的宽度的话就大错特错了。
如果是遇到了数字呢?数字里面的1和数字8的宽度是不一样的,如果是遇到了特殊符号呢?
canvas提供了对应的用于测量文字宽度的方法
context.measureText(‘这里是需要测试的文字’).width
当然,在测量肢体宽度之前,我们还需要设置文字的字号,以及加粗,斜体,字体等属性。
function drawTxt({context, scale, text, fillStyle, broken, ...rest}) {
if (!context) throw Error('请传入绘制上下文环境context')
// 默认设置
// let origin = {x: 0, y: 0, lineHeight: 30, maxWidth: 630 , fontSize: 28}
// 比例计算正确的尺寸
for (let item in rest) {
rest[item] *= scale
}
// 获取计算后的值
let {x, y, lineHeight, maxWidth, fontSize} = {...rest}
// 设置字体样式
context.setTextAlign('left')
context.setTextBaseline('top')
context.setFillStyle(fillStyle)
// context.setFontSize(fontSize)
console.log(ctx)
// broken: true 如果不考虑英文单词的完整性 适用于所有情况
// broken: false 考虑英文单词的完整性 仅适用于纯英文
//【TODO: 中英混排且考虑单词截断...】
let splitChar = broken ? '' : ' '
let arrText = text.split(splitChar)
let line = ''
let linesCount = 0
for (let n = 0; n < arrText.length; n++) {
let testLine = line + arrText[n] + splitChar
let testWidth = context.measureText(testLine).width
if (testWidth > maxWidth && n > 0) {
// 一行已经绘制完成
linesCount++
context.fillText(line, x, y)
line = arrText[n] + splitChar
y += lineHeight
} else {
// 一行还未绘制完成
line = testLine
// console.log("换行",testWidth,maxWidth,line)
}
}
linesCount++
context.fillText(line, x, y)
}
drawTxt({
context:ctx,
scale:1,
text:txt.text,
fillStyle:txt.textColor,
broken: true,
x:txt.left,
y:txt.top,
lineHeight:txt.fontSize * txt.lineHeight,
maxWidth:txt.width,
fontSize:txt.fontSize
})
这里有一个完整的处理文字换行的方法,但是处理过后的文字与实际的DOM所展示出来的还是会有几个像素的差距,但是这个目前找了很多资料,还是没有一个好的解决办法,好像canvas里面所生成的文字和DOM里面生成的文字的大小有一些不一样。
之前也采取过将所有的字创建一个对象,然后记录他的left 值和top值,但就是因为这样细微的差距,随着字数越来越多,这个差距也会越来越大。所以就只能将文字这样一行一行的画,对每一行进行定位。
如果谁有好的办法,能够在小程序中达到对DOM里面的元素克隆在画布上的高精度的还原的话,可以讨论一下。