小程序canvas 口罩头像生成器开发

823 阅读4分钟

小程序canvas 口罩头像生成器开发

一、预览

预览地址
预览地址

代码 github.com/AnChunLi/sm…

二、代码细节

1.canvas事件绑定和业务实现

在canvas画布中,图像是实时绘制的,和SVG的区别是没有结构化,因此在给canva中绑定事件时,需要对整个canvas元素绑定对应事件,在小程序中支持touchstart、touchmove、touchend、touchcancel、longtap、error这几个事件。

在本demo中,口罩头像生成过程中需要对口罩进行拖动,放大、缩小、旋转等操作,就需要对口罩进行事件绑定,在canvas中对canvas元素绑定touchstart、touchmove、touchend等事件,然后根据事件返回坐标参数来判定是否作用于对应元素或者区域。
move(e) {
    let x = e.touches[0].x,
      y = e.touches[0].y,
      dis = 30;
    if (x < this.data.x + rectW -20 && x >= this.data.x+20 && y < this.data.y + rectW-20&& y >= this.data.y+20){
      if (disX == 0) {
        disX = x - this.data.x
      }
      if (disY == 0) {
        disY = y - this.data.y
      }
      console.log('move');
      this.setData({
        x: x - disX,
        y: y - disY
      })
      // ctx.requestAnimationFrame(this.drawMove);
      this.drawMove();
    } else if (x < this.data.x + rectW + dis && x >= this.data.x + rectW - dis && y < this.data.y + rectH + dis && y >= this.data.y + rectH - dis){
      console.log("scale");
      this.drawScale(x - this.data.x, y - this.data.y);
    }
  },
  • 移动 监听touchmove事件,取得触控坐标与矩形区域原点的坐标差,然后实时计算得到矩形原点坐标,并进行绘制。

  • 放大、缩小 传入手指触控坐标与矩形原点的坐标差 this.drawScale(x - this.data.x, y - this.data.y); 改变矩形长和宽,并实时绘制
drawScale(W, H) {
    rectW = W;
    rectH = H;
    this.drawMove();
  },

  • 旋转 这是处理的最不优雅的部分,由于一开始的事件监听依赖矩形原点坐标,这就导致在旋转过程中,不能很好的绑定旋转控件,因此采用了一个笨办法,在canvas画布右上角设置了旋转控件,由于它是固定的对于绑定事件非常方便,没点击一次就会按顺时针方向整体旋转,对应旋转角度也会记录。
drawRotate(){
    rotate = rotate + 0.08;
    ctx.drawImage(this.data.headImg, 0, 0, this.data.windowW * 0.9, this.data.windowW * 0.9);
    ctx.drawImage('img/rotate.png', this.data.windowW * 0.9 - 40, 0, 40, 40);
    ctx.translate(this.data.x + rectW / 2, this.data.y + rectH / 2);
    ctx.rotate(rotate);
    ctx.drawImage(this.data.kouzhaoImg, - rectW / 2 + rectW * 0.25 / 2, - rectH / 2 + rectH / 6 / 2, rectW * 0.75, rectH * 5 / 6);
    ctx.setLineDash([5, 5]);
    ctx.setStrokeStyle('#fff');
    ctx.setLineWidth(3);
    ctx.strokeRect(- rectW / 2, - rectH / 2, rectW, rectH);
    ctx.drawImage('img/cancel.png', - rectW / 2 - 20, - rectH / 2 - 20, 40, 40);
    ctx.drawImage('img/move.png', - rectW / 2 + rectW - 20, - rectH / 2 + rectH - 20, 40, 40);
    ctx.draw();
  },

2.canvas图片圆角实现

在css中,实现图片圆角极其简单,但在canvas中实现起来并不是一行代码所能解决的问题,因此在这里也说下其实现。

// 绘制圆角
        shareCtx.beginPath();
        shareCtx.arc(x+dis, y + dis, radius, Math.PI, 1.5* Math.PI);
        shareCtx.moveTo(x + dis, y);
        shareCtx.lineTo(x + a - dis, y);
        shareCtx.arc(x + a - dis, y + dis, radius, 1.5*Math.PI, 2 * Math.PI,);
        shareCtx.lineTo(x + a, y + dis);
        shareCtx.lineTo(x + a, y + a - dis);
        shareCtx.arc(x + a - dis, y + a - dis, radius, 0, 0.5 * Math.PI, false);
        shareCtx.lineTo(x + a - dis, y + a);
        shareCtx.lineTo(x + dis, y + a);
        shareCtx.arc(x + dis, y + a - dis, radius, 0.5 * Math.PI, 1 * Math.PI);
        shareCtx.lineTo(x, y + a - dis);
        shareCtx.lineTo(x, y + dis);
        shareCtx.closePath();
        shareCtx.clip();
        shareCtx.drawImage(headImg, x, y, a, a);
        shareCtx.draw(); 
首先在小程序中通过Context.beginPath()接口创建一个绘制路径,然后需要绘制一个圆角矩形,一个圆角矩形由上下左右四条边和四个角的四个圆角组成,所以在绘制的时候需要精确计算出每个圆角的坐标和边的坐标。
由于在绘制图片的时候,图片的定位是根据图片左上角的坐标,因此通过其坐标和矩形长宽和圆角半径可得到四个圆角对应圆心的坐标和四条线段起始坐标,通过Context.arc()接口绘制圆弧,对应参数可在微信小程序官方文档查到。
通过Context.moveTo(x0,y0)(起始坐标)和Context.lineTo(x1,y1) 绘制一条线,注意:在整个封闭图形的绘制中,只需要一次moveTo,经过的顶点都可通过lineTo进行绘制。
在封闭图形绘制完成之后,需要通过Context.closePath()来结束路径。然后使用裁剪方法Context.clip()就可以开始绘制圆角图片了。

总结:本次开发由于一开始设计的问题,导致没有对事件绑定依赖坐标进行设定,因此在体验上存在诸多不足,我将开发过程中遇到的认为需要注意的细节罗列了一下,对于canvas基础的使用和其他小程序相关API没有做陈述。希望能够得到大家的优化建议和大家一起成长。