浅谈Canvas

最近接手个关于小程序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);

本文纯属不才的一点小小见解 如有错误 还望指正 互相学习

你可能感兴趣的:(浅谈Canvas)