最近接手个关于小程序canvas的需求 对canvas的了解也较之前更加的深
在这里总结一下使用canvas的几点技巧(这里以小程序canvas为例子 html5canvas类同)
一、cnavas代码量问题
使用过canvas的朋友应该都被canvas那庞大的代码量吓到过
举个栗子 用canvas写出一段话 那我们至少要使用2段代码
const ctx = wx.createCanvasContext('myCanvas')
ctx.setFontSize(20)
ctx.fillText('PHP是世界上最好的语言', 20, 20)
ctx.draw()
当然拉 理想很美好 显示很残酷 正常使用情景下我们还要设置字体颜色,对齐方式。。。
那样子我们平均要5行代码左右
那一个canvas里面的内容很多的情况下 这个代码就很庞然大物了,那我们如何来收拾这么个臃肿的胖子呢?
//这里以小程序为例子 html5canvas直接let 一个对象也一样
data:{
canvasData:{
txt: `javascript`//字样
size: 6, //字体大小
color: "#fff", //字体颜色
x: 5, //距离左边的距离
y: 15, //距离顶部的距离
shadow: true //是否具有阴影
}
}
//绘制方法
const ctx = wx.createCanvasContext('myCanvas')
for (var i = 0; i < this.data.canvasData.length; i++) {
ctx.setFontSize(this.data.canvasData[j].size);
ctx.setFillStyle(this.data.canvasData[j].color);
ctx.fillText()
}
ctx.draw(true);
这么操作之后我们在绘制的时候就只需要在canvasData里面加上我们要追加的文字
那么 有的朋友就会问了 文字OK了 那大胸弟我要图片或者其他的咋整呢?
同样的道理我们在canvasData里面加上一个Imgae嘛
data: {
//图片数据
dataImage: [{
url: ``, //背景图片,空表示纯颜色填充区块
x: 0, //距离左边的距离
y: 0, //距离顶部边的距离
height: 100, //图片高度
width: 100, //图片宽度
isCircle: false, //是否圆形
isBackground: true //是否当作背景
}, {
url: '',
x: 5,
y: 45,
height: 35,
width: 90,
background: 'rgba(0,0,0,0.4)',
isCircle: false,
isBackground: false
}
}],
dataFont: [
txt: `PHP是世界上最好的语言`, //字样
size: 6, //字号
color: "#fff", //字体颜色
x: 5, //距离左边的距离
y: 15, //距离顶部的距离
shadow: true //是否具有阴影
}, {
txt: `楼上说的都对`,
size: 21,
color: "#fff",
x: 5,
y: 20,
shadow: true
}]
},
//绘制方法
const ctx = wx.createCanvasContext('myCanvas')
for (var i = 0; i < this.data.dataFont.length; i++) {
ctx.save()//要先保存当前画笔 不然最后draw的时候就只有最后一次状态的内容
ctx.setFontSize(this.data.canvasData[j].size);
ctx.setFillStyle(this.data.canvasData[j].color);
ctx.fillText()
ctx.restore();
}
for (var i = 0; i < this.data.dataImage.length; i++) {
if (this.data.dataImage[i].url == "") {
//纯颜色填充
ctx.save()
ctx.beginPath()
ctx.rect(this.data.dataImage[i].x, this.data.dataImage[i].y, this.data.dataImage[i].width, this.data.dataImage[i].height)
ctx.setFillStyle('rgba(0,0,0,.4)')
ctx.fill()
ctx.restore();
}else{
ctx.save()
ctx.drawImage(this.data.dataImage[i].url, this.data.dataImage[i].x, this.data.dataImage[i].y, this.data.dataImage[i].width, this.data.dataImage[i].height);
ctx.restore();
}
}
ctx.draw(true);
自此,canvas这头庞大的野兽我们只要通过新增dataImage和dataFont的内容也得乖乖给咱们驯服了
二、文字自动换行
用过canvas得小伙伴应该也很清楚canvas得文字呢 是无法自动换行的,这也导致了总总很坑的排版问题的出现,那么canvas这个不听话的熊孩子我们怎么让它乖乖的呢?
先来说下思路 同样的 我们在dataFonts里面新增一个属性autoBreak和breakLength分别代表是否自动换行以及满多少个字符就换行,然后使用字符串截取拼接操作来实现换行
data: {
dataFonts: [
txt: `PHP是世界上最好的语言`, //字样
size: 6, //字号
color: "#fff", //字体颜色
x: 5, //距离左边的距离
y: 15, //距离顶部的距离
shadow: true //是否具有阴影
autoBreak:true,
breakLength:4
}, {//换行容器
txt: ``,
size: 21,
color: "#fff",
x: 5,
y: 20,
shadow: true
}]
},
//绘制方法
const ctx = wx.createCanvasContext('myCanvas')
for (var j = 0; j < this.data.dataFonts.length; j++) {
if (this.data.dataFonts[j].autoBreak) {
let fontWidth = 0,//字符串长度
numberWidth = Math.floor(ctx.measureText("0").width),//一个数字字符的长度
chinaWidth = Math.floor(ctx.measureText("哈").width)//一个中文字符的长度
//换行可以提前换行所以这里使用floor地板函数向下取整而不用round和ceil
for (var z = 0; z < this.data.dataFonts[j].txt.length; z++) {
if (/^[\u2E80-\u9FFF]|[","]+$/.test(this.data.dataFonts[j].txt[z]) == true) {//正则表达式判断中文以及标点符号计算字符串总长度
fontWidth += chinaWidth
} else {
fontWidth += numberWidth
}
//当总长度大于breakLength的长度时,换行(通过字符串截取操作)
if (fontWidth > this.data.dataFonts[j].breakLength * chinaWidth) {
let cutFonts = dataFonts[j].txt.substring(z, dataFonts[j].txt.length)
dataFonts[j + 1].txt = cutFonts + dataFonts[j + 1].txt
dataFonts[j].txt = dataFonts[j].txt.substring(0, z)
break;
}
}
}
}
ctx.setFontSize(this.data.dataFonts[j].size);
ctx.setFillStyle(this.data.dataFonts[j].color);
ctx.fillText(this.data.dataFonts[j].txt, (this.data.dataFonts[j].x) + fontLong, this.data.dataFonts[j])
ctx.draw(true);
三、圆形图片的绘制
在使用canvas的时候 经常遇到的就是画出圆形图片,如:用户头像等
而在canvasAPI里面又没有圆形图片的方法,很显然我们也只能走封装的这条老路
那么咱们怎么实现一个圆形的图片呢
首先我们要先画出一张图片和一个圆 让它们重合 然后查阅一下API 有一个clip()的截取方法可以截取图片
data:{
dataImage: [{
url: ``, //图片路劲
x: 0,
y: 0,
height: 100,
width: 100,
isCircle: true, //是否圆形
}]
}
//绘制方法
for (var i = 0; i < this.data.dataImage.length; i++) {
if(this.data.dataImage[i].isCircle==true){
ctx.save()
ctx.drawImage(this.data.dataImage[i].url, this.data.dataImage[i].x , this.data.dataImage[i].y, this.data.dataImage[i].width, this.data.dataImage[i].height);
ctx.restore();
}
}
ctx.draw(true);
本文纯属不才的一点小小见解 如有错误 还望指正 互相学习