canvas画布各种问题解析(已做兼容,实时更新)

wxml:

<view class='warp_'>
 <view class='box_'>
	<view style=''>
  	<canvas canvas-id="myCanvas" style="width:{{266 * rpx}}px;height:{{393 * rpx}}px;" />
  	<view style='padding-bottom: 0;box-sizing: border-box;'>
   	 	<view class='note'>* 图片将保存到相册 *</view>
    	<view bindtap='saveImg' class='btn'>保存图片</view>
  	</view>
	</view>
</view>
</view>

wxss:

page{background: #f2f2f2;}
.btn{width: 250rpx;height: 88rpx;line-height: 88rpx;font-size: 28rpx;border-radius: 88rpx;background: #fff;text-align: center;color: #333;margin: 		auto;box-shadow: 0 2px 20px 0 #FFC800;font-weight: bold;}
image{border-radius: 0 !important;}
.note{text-align: center;color: #753300;margin-bottom: 28rpx;font-size: 26rpx;margin-top: 60rpx;opacity: 0.52;}
.warp_{width: 100vw;height: 100vh;display: flex;justify-content: center;align-items: flex-start;padding-top: 40rpx;box-sizing: border-box;line-height: 1.5;}
.warp_ .box_{background: #FFC800;padding: 30rpx;}

js:

Page({
 data: {
 img: "/image/brandBg.png",
 code: "/image/erweima.jpg",
 image: {
  	src: "/image/none.png",
  	width: 46,
  	heigth: 46
	},
	rpx: ''
},

onLoad: function (options) {
 this.canvasImg();
},

//制作画布

canvasImg() {
let that = this;
var res = wx.getSystemInfoSync()       //获取屏幕宽度
var rpx = res.windowWidth / 375			//计算比例,做兼容

that.setData({
  rpx: res.windowWidth / 375
})

const ctx = wx.createCanvasContext('myCanvas');    //声明页面中的画布id

ctx.setFillStyle('#fff');                             //为创建的canvans上下文添充颜色  如果没有设置 fillStyle,默认颜色为 black。若写成透明,可能会导致画布中的图片出不来
ctx.fillRect(0, 0, 266 * rpx, 393 * rpx)   //设置画布的大小

ctx.save(); // 下面要制作原型图片,需要先保存状态,已便于画完圆再用

//先画个圆  
ctx.arc(35 * rpx, 35 * rpx, 23 * rpx, 0, Math.PI * 2, false);  //false代表顺时针    参数值(圆心的X值,圆心的Y值,圆的半径,圆的七点,圆的终点,顺时针)
ctx.setStrokeStyle('#fff');   //给圆添加个边框,不然会导致圆形不生效   
ctx.stroke();			//结束边框的绘制
ctx.clip();//画了圆 再剪切  原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内
ctx.drawImage(that.data.image.src, 12 * rpx, 12 * rpx, that.data.image.width * rpx, that.data.image.heigth * rpx); // 推进去图片,注意:这里的X,Y值为图片本身的左上角的位置,需通过圆的位置计算出准确的图片的位置
ctx.restore(); //恢复之前保存的绘图上下文 恢复之前保存的绘图上下文即状态 可以继续绘制

// 制作圆角矩形
this.roundRect(ctx, 50 * rpx, 80 * rpx, 100 * rpx, 100 * rpx, 10 * rpx);     //参数值(X,Y,width,hieght,r)

//向画布中添加文字,如果需要加粗的文字,可以放到画布的最后,不然会使下面的文字也加粗,以下文字不一一叙述

ctx.setFillStyle("#333");
ctx.setTextAlign('left');                        //是否居中显示,参考点画布中线
ctx.font = 'normal normal 12px PingFang SC';
ctx.fillText('分享给你一个商品', 70 * rpx, 50 * rpx);

//向画布中添加图片
ctx.drawImage(this.data.code, 186 * rpx, 295 * rpx, 70 * rpx, 70 * rpx);

ctx.setFillStyle("#999");
ctx.setFontSize(14 * rpx);                               //字大小
ctx.setTextAlign('left');                        //是否居中显示,参考点画布中线
ctx.fillText('长按图片识别二维码', 10 * rpx, 352 * rpx);


ctx.drawImage(this.data.img, 10 * rpx, 90 * rpx, 246 * rpx, 113 * rpx);

//多行文字
ctx.setFillStyle("#000");
ctx.setTextAlign('left');                        
ctx.font = 'normal bold 16px PingFang SC';
var name = '之前一直在做肉制品供应商,给国内十大火锅连锁店其中的几家在供货,开始不好做,因为那时进口货和假货横行,老百姓都找便宜货,所以横空出现了鸭肉装羊肉的行业悲剧';
this.dealWords({
  ctx: ctx,//画布上下文
  fontSize: 14,//字体大小
  word: name,//需要处理的文字
  maxWidth: 246 * rpx,//一行文字最大宽度
  x: 10 * rpx,//文字在x轴要显示的位置
  y: 218 * rpx,//文字在y轴要显示的位置
  maxLine: 2//文字最多显示的行数
})

//在画布中制作一条线
ctx.setFillStyle('#f2f2f2');
ctx.fillRect(0 * rpx, 276 * rpx, 266 * rpx, 1 * rpx);

//从这开始加粗,以下出现的文字均会加粗
ctx.setFillStyle("#000");
ctx.setTextAlign('left');                        //是否居中显示,参考点画布中线
ctx.font = 'normal bold 16px PingFang SC';
ctx.fillText('王富贵', 70 * rpx, 31 * rpx);

ctx.setFillStyle("#F03523");
ctx.setTextAlign('left');                        //是否居中显示,参考点画布中线
ctx.font = 'normal bold 15px PingFang SC';
ctx.fillText('¥', 10 * rpx, 325 * rpx);

ctx.setFillStyle("#F03523");
ctx.setTextAlign('left');                        //是否居中显示,参考点画布中线
ctx.font = 'normal bold 28px PingFang SC';
ctx.fillText('19.99', 25 * rpx, 325 * rpx);

ctx.draw();    //画布闭合
},

// 多行文本

 dealWords: function (options) {
	options.ctx.setFontSize(options.fontSize);//设置字体大小
	var allRow = Math.ceil(options.ctx.measureText(options.word).width / options.maxWidth);//实际总共能分多少行
	 var count = allRow >= options.maxLine ? options.maxLine : allRow;//实际能分多少行与设置的最大显示行数比,谁小就用谁做循环次数
 var endPos = 0;//当前字符串的截断点
 for (var j = 0; j < count; j++) {
  var nowStr = options.word.slice(endPos);//当前剩余的字符串
  var rowWid = 0;//每一行当前宽度  
  if (options.ctx.measureText(nowStr).width > options.maxWidth) {//如果当前的字符串宽度大于最大宽度,然后开始截取
    for (var m = 0; m < nowStr.length; m++) {
      rowWid += options.ctx.measureText(nowStr[m]).width;//当前字符串总宽度
      if (rowWid > options.maxWidth) {
        if (j === options.maxLine - 1) { //如果是最后一行
          options.ctx.fillText(nowStr.slice(0, m - 1) + '...', options.x, options.y + (j + 1) * 18);  //(j+1)*18这是每一行的高度    
        } else {
          options.ctx.fillText(nowStr.slice(0, m), options.x, options.y + (j + 1) * 18);
        }
        endPos += m;//下次截断点
        break;
      }
    }
  } else {//如果当前的字符串宽度小于最大宽度就直接输出
    options.ctx.fillText(nowStr.slice(0), options.x, options.y + (j + 1) * 18);
  }
}
 },

/**

  • 制作圆角
    
  • @param {CanvasContext} ctx canvas上下文

  • @param {number} x 圆角矩形选区的左上角 x坐标

  • @param {number} y 圆角矩形选区的左上角 y坐标

  • @param {number} w 圆角矩形选区的宽度

  • @param {number} h 圆角矩形选区的高度

  • @param {number} r 圆角的半径
    */

    // 圆角引用 this.roundRect(ctx, 50 * rpx, 80 * rpx, 100 * rpx, 100 * rpx, 10 * rpx);

      roundRect(ctx, x, y, w, h, r) {
      	ctx.save();
      	// 开始绘制
      	ctx.beginPath()
      	 // 因为边缘描边存在锯齿,最好指定使用 transparent 填充
      	// 这里是使用 fill 还是 stroke都可以,二选一即可
       ctx.setFillStyle('red')
      // 左上角
      ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)
      // border-top
      ctx.moveTo(x + r, y)
      ctx.lineTo(x + w - r, y)
      ctx.lineTo(x + w, y + r)
      // 右上角
      ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)
      // border-right
      ctx.lineTo(x + w, y + h - r)
      ctx.lineTo(x + w - r, y + h)
      // 右下角
      ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)
      // border-bottom
      ctx.lineTo(x + r, y + h)
      ctx.lineTo(x, y + h - r)
      // 左下角
      ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)
      // border-left
      ctx.lineTo(x, y + r)
      ctx.lineTo(x + r, y)
       // 这里是使用 fill 还是 stroke都可以,二选一即可,但是需要与上面对应
      ctx.fill()
      // ctx.stroke()
      ctx.closePath()
      // 剪切
      ctx.clip()
      ctx.restore();
      },
    

    //保存图片的点击事件

      saveImg() {
       let that = this;
      var res = wx.getSystemInfoSync()
      var rpx = res.windowWidth / 375
      that.setData({
    		rpx: res.windowWidth / 375
       })
      wx.canvasToTempFilePath({
       x: 0,
    	y: 0,
       width: 266 * rpx,                     //画布宽高
    	height: 393 * rpx,
       destWidth: 798 * rpx,                 //画布宽高*dpr 以iphone6为准
    	destHeight: 1179 * rpx,                //放大2倍以上,解决保存的图片模糊的问题
    	canvasId: 'myCanvas',
    	success: function (res) {
      	console.log(res.tempFilePath) //生成的临时图片路径
      	wx.saveImageToPhotosAlbum({
       	 filePath: res.tempFilePath,
        	success: function (res) {
         		 console.log(res);
          	wx.showToast({
            	title: '保存成功',
         	 })
       	 },
        	fail: function () {
          	console.log('a')
            }
     	 })
    	}
      })
      }
      })
    

案例:
在这里插入图片描述

附加信息,希望对您有帮助:

  1. 若画布中出现多行文字时,可能需要判断文字显示一行还是两行,可通过判断文字的宽度来判断,不建议通过字数来判断,若出现英文,可能导致字符串宽度错误;

    var name = '假装这里有一大段文字'
    const width = ctx.measureText(name).width
    console.log(width)
    
    //让文字的宽度与上面多行文本的宽度相比,可用判断设置文字单行和多行时的位置
    
  2. 当图片上方需要放置文字时,图片是加载的网络图片,可能会出现图片加载慢,盖住图片上方的文字现象;
    解决答案:只需将文字放置在图片加载事件成功的函数内即可,让图片加载成功之后再执行绘制图片上面的文字;

  3. 当需要给画布判断显示隐藏时,不能用wx:if=’‘来判断显示隐藏,因为会出现第一次加载没有问题,但是再次点击没有内容的现象,建议用css的定位将画布设置在屏幕外,点击返回应该出现的区域即可,也可使用 hidden=’’ 属性判断显示隐藏;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值