vue中canvas 实现手势密码

北战南征 提交于 2020-08-05 13:31:39

思路:

手势密码思路:
1 使用canvas 画圆和线条
2 使用canvas画一个画布 设置画布的宽高 CW CH,获取画布距离页面的位置信息canvas.getBoundingClientRect()

3 设置画板距离canvas两边和顶部的距离 offetX offsetY
4 九宫格每个圆是一样大小的,设置圆的半径R
5 获取圆左右之间的间距 (CW-offsetX*2-3*2*R)/2 diffX
6 获取圆上下之间的间距(CH-offsetY*2-3*2*R)/2 diffY
7 画圆
7.1 带蓝色边框的空心圆,原理是先画一个蓝色的实心圆,再在同一个圆心处画一个实心的白色圆圈(半径比蓝色的圆小,两个圆之间的差距就是边框的大小)
7.2 获取每个圆圆心的位置信息数组:Re=[],3*3的九宫格,双层循环“
for(var row=0; row<3;row++){
for(var col=0; col<3;col++){
var point={
x:offsetX+(1+col*2)*R+diffX*col
y:offsetY+(1+row*2)*R+diffY*row
}
}
Re.push(point);
}
7.3 画外围蓝色实心的圆,再画实心白色圆,实现带蓝色边框的圆
8 监听touch事件 touchstart touchmove touchend
9 在touchstart判断起点是否在圆中,如果在把圆心的位置信息放在pointline数组中,touchesmove中开始画线(判断touch点是否在圆点内部,如果在,开始画线,从连线的第一点开始,画线完成之后开始重新画圆(重复7 的步骤),画圆中判断其中的点是否在手势路线中,如果在就画圆心,最后一步,把最后一个点与当前的手势所在的位置连在一起;

















10 touchesend中,判断密码长度是否大于4,与原始密码进行对比,如果不对就改变颜色,重新画九宫格,到最后一个点就可以了,不需要连接最后一个点与结束时手势所在的位置

demo:

<template>
<canvas ref='myCanvas'></canvas>
</template>
<script>
export default{
  data(){
    return{
      c:'',
      cPosition:{},
      cxt:'',
      CW:600,
      CH:320,
      Radius:25,
      offsetX:40,
      offsetY:30,
      password:[0,1,2,3,4],
      successColor:'#627eed',
      errorColor:'red',
      innerColor:'',
      successInnerColor:'#ffffff',
      errorInnerColor:'#ffffff',
      selectColor:'',
      Re:[],
      borderWidth:1,
      pointLine:[],
      pointWidth:8,//圆心的半径大小
      lineWidth:3//连线的大小
    }
  },
  mounted(){
    let _this=this;
    this.selectColor=this.successColor;
    this.innerColor=this.successInnerColor;
     this.$nextTick(function(){
      _this.init();
      _this.initEvent();
     });
  },
  methods:{
    init(){
      this.initCas();
      this.getPointLocationArr();
      this.draw();
    },
    initCas(){//初始化画布
       this.c=this.$refs.myCanvas;
        this.CW=document.body.offsetWidth;
        this.c.width=this.CW;
        this.c.height=this.CH;
        this.cPosition=this.c.getBoundingClientRect();
        this.cxt=this.c.getContext('2d');
    },
    getPointLocationArr(){//获取九宫格圆心位置信息
      //获取圆点之间的间距
      let diffX=(this.CW-this.offsetX*2-this.Radius*2*3)/2;
      let diffY=(this.CH-this.offsetY*2-this.Radius*2*3)/2;
      for(let row=0;row<3;row++){
        for(let col=0; col<3;col++){
          let point={
            x:this.offsetX+col*diffX+(col*2+1)*this.Radius,
            y:this.offsetY+row*diffY+(row*2+1)*this.Radius
          }
          this.Re.push(point);
        }
      }
    },
    drawPoint(touches,touchPoint){//选中的圆画圆心并连接起来
    let pointLine=this.pointLine;
    this.cxt.beginPath();
      for(let i=0; i<pointLine.length;i++){
        let point=this.Re[pointLine[i]];//根据存储的圆点的下标找到圆点的圆心位置
        //连接选中的点begin
        this.cxt.lineTo(point.x,point.y);
      }
       this.cxt.strokeStyle=this.selectColor;
        this.cxt.lineWidth=this.lineWidth;
        this.cxt.stroke();
        this.cxt.closePath();
        if(touchPoint){
          let lastPoint=this.Re[this.pointLine[this.pointLine.length-1]];
          this.cxt.beginPath();
          this.cxt.moveTo(lastPoint.x,lastPoint.y);
          this.cxt.lineTo(touches.pageX-this.cPosition.left,touches.pageY-this.cPosition.top);
         this.cxt.strokeStyle=this.selectColor;
        this.cxt.lineWidth=this.lineWidth;
        this.cxt.stroke();
        this.cxt.closePath();
        }

    },
    isPointSelect(touchs){//圆点是否被选中
    let Re=this.Re;
      for(let i=0;i<Re.length;i++){
        let currentPonit=Re[i];
        let xdiff=Math.abs(touchs.pageX-currentPonit.x-this.cPosition.left);
         let ydiff=Math.abs(touchs.pageY-currentPonit.y-this.cPosition.top);
         let dir=Math.pow(xdiff*xdiff+ydiff*ydiff,0.5);//当前鼠标的位置与圆心之间的距离两边和的开方
         if(dir<=this.Radius){
           if(this.pointLine.indexOf(i)==-1){
           this.pointLine.push(i);
         }
         break;
      }
      }

    },
    initEvent(){
      let _this=this;
      this.c.addEventListener('touchstart',function(e){
        _this.isPointSelect(e.touches[0]);
      });
      this.c.addEventListener('touchmove',function(e){
         _this.isPointSelect(e.touches[0]);
         //清空画布
         _this.cxt.clearRect(0,0,_this.CW,_this.CH);
         _this.draw(e.touches[0],true);

      });
      this.c.addEventListener('touchend',function(e){
        if(_this.pointLine.length<4){
          alert('密码长度不能小于4!');
          _this.selectColor=_this.errorColor;
          _this.innerColor=_this.errorInnerColor;
        }
        _this.checkIsRight();
         //清空画布
         _this.cxt.clearRect(0,0,_this.CW,_this.CH);
         _this.draw(e.touches[0],false);
        _this.resetCxt(e.touches[0]);
        
      });
    },
    resetCxt(touches){
      let _this=this;
      setTimeout(()=>{
          this.pointLine=[];
          this.selectColor=this.successColor;
          this.innerColor=this.successInnerColor;
          this.cxt.clearRect(0,0,_this.CW,_this.CH);
          this.draw(touches,false);
      },3000);
    },
    checkIsRight(){
      if(this.password.toString()!=this.pointLine.toString()){
         this.selectColor=this.errorColor;
        this.innerColor=this.errorInnerColor;
      }
    },
    draw(touches,touchPonit){
      //画九宫格
      if(this.pointLine.length>0)
      this.drawPoint(touches,touchPonit);
      let Re=this.Re;
      for(let i=0; i<Re.length;i++){
        let point=Re[i];
        //画外层蓝色的圆
        this.cxt.fillStyle=this.selectColor;
        this.cxt.beginPath();
        this.cxt.arc(point.x,point.y,this.Radius,0,2*Math.PI,true);//圆心x坐标,y坐标,圆的半径,从0 画到360,逆时针画图
        this.cxt.fill();
        this.cxt.closePath();
        //画内部白色的圆
        this.cxt.fillStyle=this.innerColor;
        this.cxt.beginPath();
        this.cxt.arc(point.x,point.y,this.Radius-this.borderWidth,0,2*Math.PI,true);
         this.cxt.fill();
        this.cxt.closePath();
        //画选中圆点的圆心
      if(this.pointLine.indexOf(i)!=-1){
        //画选中的点begin
        this.cxt.fillStyle=this.selectColor;
        this.cxt.beginPath();
        this.cxt.arc(point.x,point.y,this.pointWidth,0,2*Math.PI,true);
        this.cxt.fill();
        this.cxt.closePath();
        //画选中的点end
      }

      }

    }

  }
}
</script>

1 初始画布:

 

 密码长度小于4:

 

 关闭弹框

 

 密码错误

 

 密码正确

 

 圆与圆之间的间距

 

 

 

 

 

参考:https://www.cnblogs.com/wuyufei/p/11996831.html

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!