小程序canvas绘图

程序小白从0开始的canvas踩坑

逻辑:循环将多条留言绘制在图片上,形成海报
下面代码中 this.data.selectMessage 为图片的二维数组,包括头像、背景图、留言背景图、微信昵称、留言内容、权重等字段
踩坑1、image.onload为异步执行,每个数组中包含微信头像、留言背景图两个图片,还要递归循环。因为异步所以导致图片缺失、递归无法正常执行。所以将数组从[a,b,c]整合成[a,a,b,b,c,c]在图片下载回调中循环嵌套绘制留言背景图和头像
踩坑2、头像为圆形设计所以需要裁剪一下代码为完整代码。有效避免裁剪的各种缺失、或者头像无法正常绘制

	ctx.save();   //当前区域保存
    ctx.beginPath();   //开始新的区域
    ctx.arc(x+9+8, y+12+top+8, 8, 0, 2 * Math.PI, false) //画一个圆形裁剪区域
    ctx.clip() //画了圆 再剪切  原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内
    ctx.drawImage(image, x+9, y+12+top,16,16);   //在留言背景图上绘制头像
    ctx.restore();   //恢复状态

踩坑3、

整理后完整代码如下、变量会有缺失、自己按照逻辑调整自己的变量

<canvas type="2d" id="mycanvas" style="width: 375px;height: 812px;"></canvas>
//将canvas转换为图片保存到本地,然后将图片路径传给image图片的src
createNewImg: function () {
  var that = this;
  // 根据Index进行排序确定层级
  this.data.selectMessage.sort((a, b) => {
    return a.index > b.index ? 1 : -1;
    })
  var data_list = this.data.selectMessage
  wx.createSelectorQuery()
  .select('#mycanvas') // 在 WXML 中填入的 id
  .fields({ node: true, size: true })
  .exec((res) => {
      // Canvas 对象
      const canvas = res[0].node
      // 渲染上下文
      const ctx = canvas.getContext('2d')

      // Canvas 画布的实际绘制宽高
      const width = 375
      const height = 812
    
      // 初始化画布大小   调整IOS不同倍数的高清屏 
      const dpr = wx.getWindowInfo().pixelRatio
      canvas.width = width * dpr
      canvas.height = height * dpr
      const top = height  * 0.256
      ctx.scale(dpr, dpr)
      //画入图片
      const image = canvas.createImage()
      // 设置图片src
      image.src = this.data.bgimg
      // 图片加载完成回调
      image.onload = () => {
      // 将图片绘制到 canvas 上
      ctx.drawImage(image, 0, 0,width,height)
      if(data_list.length > 0){
        var all_image = [];
        var key_count = 0;
        for (let index = 0; index < data_list.length; index++) {
            all_image[key_count] = data_list[index];
            key_count++;
            all_image[key_count] = data_list[index];
            key_count++;
        }
        this.onload_list(ctx,image,all_image,0,canvas,top);
      }
      }
  })

},

onload_list:function (ctx,image,data_list,all_count,canvas,top) {
  all_count++;
  //取出数组第一个元素并删除第一个元素
  const image_data = data_list.shift();
  const content = image_data['name'];
  let x = parseFloat(image_data['xxx']) * 812 / this.data.view_height;
  let y = parseFloat(image_data['yyy']) * 812 / this.data.view_height;
  let user_name = image_data['user_name'];
  const user_image = image_data['user_image'];
  const img_url = image_data['image'];

  //判断x y值。防止出界
  if(x > 258){
    x = 258;
  }
  if(y > 304){
    y = 304
  }

  if(user_name.length > 9){
    user_name = user_name.substr(0,9)+'...';
  }

  if(all_count%2 == 1){
    //绘制留言背景图
    image.src = img_url;
    image.onload = () => {
        ctx.drawImage(image, x, y+top,120,117);
        //执行递归程序,如果数量大于0 那么继续执行。如果小于0  则不递归
        if(data_list.length > 0){
            this.onload_list(ctx,image,data_list,all_count,canvas,top);    //递归调用
        }
    }
}else{
    ctx.fillStyle= "#000";
    ctx.font = "8px PingFangSC-Medium";
    ctx.fillText(user_name,x+27,y+top+23);    //绘制微信昵称
    this.drawTextOn(ctx,content,x+18,y+top+30,80)    //绘制留言内容
    //绘制头像
    image.src = user_image;
    image.onload = () => {
        ctx.save();   //当前区域保存
        ctx.beginPath();   //开始新的区域
        ctx.arc(x+9+8, y+12+top+8, 8, 0, 2 * Math.PI, false) //画一个圆形裁剪区域
        ctx.clip() //画了圆 再剪切  原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内
        ctx.drawImage(image, x+9, y+12+top,16,16);   //在留言背景图上绘制头像
        ctx.restore();   //恢复状态
        //执行递归程序,如果数量大于0 那么继续执行。如果小于0  则不递归
        if(data_list.length > 0){
            this.onload_list(ctx,image,data_list,all_count,canvas,top);    //递归调用
        }else{
          wx.canvasToTempFilePath({
            canvas,
            success: function (res) {
              var tempFilePath = res.tempFilePath;
              var image_list = [];
              image_list.push(tempFilePath);
              wx.previewImage({
                current: tempFilePath, // 当前显示图片的http链接
                urls: image_list // 需要预览的图片http链接列表
              });
              wx.hideLoading()
            },
            fail: function (res) {
              console.log(res);
            }
          }, this);
        }
    }  
}
},
 // canvas填充文字自动换行
drawTextOn(ctx,t,x,y,w){
    var chr = t.split("");
    var temp = "";              
    var row = [];
    var line_spacing = 20;
    
    ctx.font = "14px PingFangSC-Medium";
    ctx.fillStyle = "#000";
    if(chr.length <= 6){
        y = y+25;
    }else if(chr.length > 6 && chr.length <= 12){
        y = y+15;
    }else if(chr.length > 12 && chr.length <= 18){
        y = y+5;
    }else if(chr.length > 18 && chr.length <= 24){
    }else if(chr.length > 24 && chr.length <= 30){
        y = y+12;
        ctx.font = "8px PingFangSC-Medium";
        line_spacing = 15;
    }else if(chr.length > 30 && chr.length <= 40){
        y = y+5;
        ctx.font = "8px PingFangSC-Medium";
        line_spacing = 15;
    }else{
        ctx.font = "8px PingFangSC-Medium";
        line_spacing = 15;
    }
    for(var a = 0; a < chr.length; a++){
        if( ctx.measureText(temp).width < w ){
            ;
        }
        else{
            row.push(temp);
            temp = "";
        }
        temp += chr[a];
    }
    row.push(temp);
    for(var b = 0; b < row.length; b++){
        ctx.fillText(row[b],x,y+(b+1)*line_spacing);
    }
  },

//点击生成
saveImg: function (e) {
  
  var that = this;
  this.setData({
    maskHidden: false
  });
  wx.showLoading({
    title: '海报生成中...',
    icon: 'loading',

  });
    that.createNewImg();
},

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值