zoukankan      html  css  js  c++  java
  • vue中canvas 实现手势密码

    思路:

    手势密码思路:
    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

  • 相关阅读:
    [置顶] windows player,wzplayerV2 for windows
    wzplayer 近期将会支持BlackBerry和WinPhone8
    wzplayerEx for android(真正硬解接口,支持加密的 player)
    ffmpeg for ios 交叉编译 (支持i686 armv7 armv7s) 包含lame支持
    ffmpeg for ios 交叉编译 (支持i686 armv7 armv7s) 包含lame支持
    编译cegcc 0.59.1
    wzplayer 近期将会支持BlackBerry和WinPhone8
    wzplayerEx for android(真正硬解接口,支持加密的 player)
    windows player,wzplayerV2 for windows(20140416)更新
    编译cegcc 0.59.1
  • 原文地址:https://www.cnblogs.com/xiaofenguo/p/12858785.html
Copyright © 2011-2022 走看看