canvas实现手机的手势解锁步骤详细

按照国际惯例,先放效果

1、js动态初始化Dom结构

首先在index.html中添加基本样式

body{background:pink;text-align: center;}

加个移动端Meta

<Meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">

引入index.js脚本

script src="index.js"></script>

index.js

// 匿名函数自执行
(function(){
     canvasLock是全局对象
    window.canvasLock=(obj){
        this.width=obj.width;
        this.height=obj.height;
    }
    动态生成DOM
    canvasLock.prototype.initDom=(){
        创建一个div
        var div=document.createElement("div");
        var h4="<h4 id='title' class='title'>绘制解锁图案</h4>";
        div.innerHTML=h4;
        div.setAttribute("style","position:absolute;top:0;left:0;right:0;bottom:0;");

        创建canvas
        var canvas=document.createElement("canvas");
        canvas.setAttribute("id","canvas"csstext 的本质就是设置 HTML 元素的 style 属性
        canvas.style.csstext="background:pink;display:inine-block;margin-top:15px;";

        div.appendChild(canvas);
        document.body.appendChild(div);

        设置canvas认宽高
        var width=this.width||300;
        var height=this.height||300;

        canvas.style.width=width+"px";
        canvas.style.height=height+"px";

        canvas.width=width;
        canvas.height=height;

    }

    
    init代表初始化,程序的入口
    canvasLock.prototype.init=动态生成DOM
        this.initDom();

        创建画布
        this.canvas=document.getElementById("canvas"this.ctx=this.canvas.getContext("2d");

    }
})();

在index.html中创建实例并初始化

new canvasLock({}).init();

效果

 

 

2、 画圆函数

需要补充一下画布宽度与圆的半径的关系

如果一行3个圆,则有4个间距,间距的宽度与圆的直径相同,相当于7个直径,即14个半径

如果一行4个圆,则有5个间距,间距的宽度与圆的直径相同,相当于9个直径,即18个半径

如果一行n个圆,则有n+1个间距,间距的宽度与圆的直径相同,相当于2n+1个直径,即4n+2个半径

 

 

补充两个方法

以给定坐标点为圆心画出单个圆
    canvasLock.prototype.drawCircle=(x,y){
        this.ctx.strokeStyle="#abcdef"this.ctx.linewidth=2.ctx.beginPath();
        this.ctx.arc(x,y,this.r,2*Math.PI,1)">true.ctx.closePath();
        .ctx.stroke();
    }
    
    绘制出所有的圆
    canvasLock.prototype.createCircle=var n=this.circleNum;一行几个圆
        var count=0this.r=this.canvas.width/(4*n+2);//公式计算出每个圆的半径
        this.lastPoint=[];储存点击过的圆的信息
        this.arr=[];储存所有圆的信息
        this.restPoint=[];储存未被点击的圆的信息
        var r=.r;

        for(var i=0;i<n;i++){
            var j=0;j<n;j++){
                count++;
                var obj={
                    x:(4*j+3)*r,y:(4*i+3)*给每个圆标记索引
                };
                .arr.push(obj);
                this.restPoint.push(obj);初始化时为所有点
            }
        }

        清屏
        this.ctx.clearRect(0,1)">this.canvas.width,1)">.canvas.height);

        以给定坐标点为圆心画出所有圆
        var i=0;i<this.arr.length;i++循环调用画单个圆的方法
            this.drawCircle(this.arr[i].x,1)">.arr[i].y);
        }

    }

初始化的时候记得调用

canvasLock.prototype.init=绘制出所有的圆
        .createCircle();
    }

别忘了在index.html中实例化时传入参数(一行定义几个圆)

new canvasLock({circleNum:3}).init();

效果

 

 

3、canvas事件操作——实现画圆和画线

getPosition方法用来得到鼠标触摸点离canvas的距离(左边和上边)

canvasLock.prototype.getPosition=(e){
        var rect=e.currentTarget.getBoundingClientRect();获得canvas距离屏幕的上下左右距离
        var po={
            鼠标与视口的左距离 - canvas距离视口的左距离 = 鼠标与canvas的左距离
            x:(e.touches[0].clientX-rect.left),鼠标与视口的上距离 - canvas距离视口的上距离 = 鼠标距离canvas的上距离
            y:(e.touches[0].clientY-rect.top)
        };
        return po;
    }

给canvas添加 touchstart 事件,判断触摸点是否在圆内

触摸点在圆内则允许拖拽,并将该圆添加到 lastPoint 中,从 restPoint 中剔除

this.canvas.addEventListener("touchstart",1)">(e){
            var po=self.getPosition(e);鼠标距离canvas的距离

            判断是否在圆内
            var i=0;i<self.arr.lenth;i++){
                if(Math.abs(po.x-self.arr[i].x)<self.r && Math.abs(po.y-self.arr[i].y)<self.r){
                    self.touchFlag=true;允许拖拽
                    self.lastPoint.push(self.arr[i]);点击过的点
                    self.restPoint.splice(i,1);剩下的点剔除这个被点击的点
                    break;
                }
            }
        },1)">false);

 

判断是否在圆内的原理:

 

 圆心的x轴偏移和鼠标点的x轴偏移的距离的绝对值小于半径

并且

 圆心的y轴偏移和鼠标点的y轴偏移的距离的绝对值小于半径

则可以判断鼠标位于圆内

 

给touchmove绑定事件,在触摸点移动时给点击过的圆画上实心圆,并画线

触摸点移动时的动画
    canvasLock.prototype.update=(po){
        清屏,canvas动画前必须清空原来的内容
        .arr[i].y);
        }

        this.drawPoint();点击过的圆画实心圆
        this.drawLine(po);画线

    }

    画实心圆
    canvasLock.prototype.drawPoint=this.lastPoint.length;i++this.ctx.fillStyle="#abcdef";
            .ctx.beginPath();
            this.ctx.arc(this.lastPoint[i].x,1)">this.lastPoint[i].y,1)">this.r/2,true);
            .ctx.closePath();
            .ctx.fill();
        }
    }

    画线
    canvasLock.prototype.drawLine=this.linewidth=3this.ctx.moveto(this.lastPoint[0].x,1)">this.lastPoint[0].y);线条起点
        var i=1;i<this.ctx.lineto(.lastPoint[i].y);
        }
        this.ctx.lineto(po.x,po.y);触摸点
        .ctx.stroke();
        .ctx.closePath();
    }

效果

 

 

4、canvas手势链接操作实现

在touchmove中补充当碰到下一个目标圆时的操作

碰到下一个圆时只需要push到lastPoint当中去
        this.restPoint.length;i++if((Math.abs(po.x-this.restPoint[i].x)<this.r) && (Math.abs(po.y-this.restPoint[i].y)<.r)){
                this.lastPoint.push(this.restPoint[i]);将这个新点击到的点存入lastPoint
                this.restPoint.splice(i,1)">从restPoint中剔除这个新点击到的点
                ;
            }
        }

效果

 

 

5、解锁成功与否的判断

 

设置密码
    canvasLock.prototype.storePass=if(.checkPass()){
            document.getElementById("title").innerHTML="解锁成功"this.drawStatusPoint("lightgreen");
        }else{
            document.getElementById("title").innerHTML="解锁失败"this.drawStatusPoint("orange");
        }
    }

    判断输入的密码
    canvasLock.prototype.checkPass=var p1="123",1)">成功的密码
            p2=""){
            p2+=.lastPoint[i].index;
        }
        return p1===p2;
    }

    绘制判断结束后的状态
    canvasLock.prototype.drawStatusPoint=(type){
        this.ctx.strokeStyle=type;
            );
            .ctx.stroke();
        }
    }

    程序全部结束后重置
    canvasLock.prototype.reset=.createCircle();
    }

 

大功告成!!下面晒出所有代码

index.html

<!DOCTYPE html>
html lang="en"head>
    charset="UTF-8"title>手势解锁</<!-- 移动端Meta-->
    style>
           body{background:pink;text-align center}
    body>

    >
        // circleNum:3 表示一行3个圆
        new canvasLock({circleNum:3}).init();
    >
  
htmlobj.height;
        this.circleNum=obj.circleNum;
    }
    height;

    }

    .arr[i].y);
        }

    }

    添加事件
    canvasLock.prototype.bindEvent=var self=;

        var i=0;i<self.arr.length;i++if((Math.abs(po.x-self.arr[i].x)<self.r) && (Math.abs(po.y-self.arr[i].y)<self.r)){
                    self.touchFlag=falsethis.canvas.addEventListener("touchmove",1)">if(self.touchFlag){
                触摸点移动时的动画
                self.update(self.getPosition(e));
            }
        },1)">触摸离开时
        this.canvas.addEventListener("touchend",1)">(self.touchFlag){
                self.storePass(self.lastPoint);
                setTimeout((){
                    self.reset();
                },300);
            }
        },1)">);

    }

    .createCircle();
    }
    
    获取鼠标点击处离canvas的距离
    canvasLock.prototype.getPosition= po;
    }

     鼠标每移动一下都会重绘canvas,update操作相当于每一个move事件都会触发
        画线

        ;
            }
        }
    }

    .ctx.closePath();
    }

    认不允许拖拽
        this.touchFlag=.createCircle();

        添加事件
        .bindEvent();
    }
})();

 

相关文章

vue阻止冒泡事件 阻止点击事件的执行 &lt;div @click=&a...
尝试过使用网友说的API接口获取 找到的都是失效了 暂时就使用...
后台我拿的数据是这样的格式: [ {id:1 , parentId: 0, name:...
JAVA下载文件防重复点击,防止多次下载请求,Cookie方式快速简...
Mip是什么意思以及作用有哪些