canvas——绘制解锁图案

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>手机解锁</title>
        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no" />
        <style>
            body{
                text-align: center;
                background: #305066;
            }
            h4{
                color: #22c3aa;
            }
        </style>
    </head>
    <body>
        <script type="text/javascript" src="js/index.js"></script>
        <script>
            //1.生成背景
            //2.动态title生成
            //3.用js动态生成canvas标签
            //4.js动态生成h3标签和canvas标签
            new canvasLock({chooseType:3}).init();
            
        </script>
    </body>
</html>
(function(){
    /*
      实现画圆和划线:
      1.添加事件touchstart、touchmove、touchend
      2.touchstart判断是否点击的位置处于园内getPosition,处于则初始化lastpoint、restPoint
      3.touchmove做的就是:画圆drawPoint和划线drawLine
    */
    /*
      实现自动画圆的效果
      1.检测手势移动的位置是否处于圆内。
      2.圆内的话则画圆 drawPoint
      3.已经画过实心圆的圆,无需重复检测
    */
   /*
      实现解锁成功:
      1.检测路径是否是对的
      2.如果是对的就重置,圆圈变绿
      3.不对也重置,圆圈变红
      4.重置
   */
    window.canvasLock = function(obj){
        this.height = obj.height;
        this.width = obj.width;
        this.chooseType = obj.chooseType;
        
    };
    
    //js方式动态生成dom
    canvasLock.prototype.initDom = function(){
        var wrap = document.createElement('div');
        var str = '<h4 id="title" class="title">绘制解锁图案</h4>';
        wrap.setAttribute('style','position:absolute;top:0;left:0;right:0;bottom:0');
        
        var canvas = document.createElement('canvas');
        canvas.setAttribute('id','canvas');
        canvas.style.cssText = "background-color:#305066;display:inline-block;margin-top=15px";
        
        wrap.innerHTML = str;
        wrap.appendChild(canvas);
        
        var width = this.width || 300;
        var height = this.height || 300;
        
        document.body.appendChild(wrap);
        
        //高清屏锁放
        canvas.style.width = width +"px";
        canvas.style.height = height + "px";
        //修改默认宽高
        canvas.width = width;
        canvas.height = height;
    }
    canvasLock.prototype.drawCle = function(x,y){  //初始化解锁密码面板,即画圆
        this.ctx.strokeStyle = '#cfe6ef';
        this.ctx.lineWidth = 2;
        this.ctx.beginPath();
        this.ctx.arc(x,y,this.r,0,Math.PI*2,true);
        this.ctx.closePath();
        this.ctx.stroke();
        
    }
    
    canvasLock.prototype.createCircle = function(){  //创建点的坐标,根据c
        var n = this.chooseType;  //n是指有几行圆
        var count = 0;
        this.r = this.ctx.canvas.width / (2+4*n);
        //圆心坐标
        this.lastPoint = [];  
        this.arr = [];   //9个圆的中心点坐标
        this.restPoint = [];  //还未选中的圆的个数
        var r = this.r;
        for(var i = 0;i < n;i++){
            for(var j = 0;j < n; j++){
                count++;
                var obj = {
                    x: j*4*r + 3*r,
                    y: i*4*r + 3*r,
                    index: count
                };
                this.arr.push(obj);
                this.restPoint.push(obj);
            }
        }
        this.ctx.clearRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);
        for(var i = 0;i<this.arr.length;i++){
            this.drawCle(this.arr[i].x,this.arr[i].y);
        }
    }
    
    //程序初始化
    canvasLock.prototype.init = function(){
        this.initDom();
        this.canvas = document.getElementById('canvas');
        this.ctx = this.canvas.getContext('2d');
        this.touchFlag = false;
        //1.确定半径 2.确定每一个圆的中心坐标点
        //3.一行3个圆有14个半径,一行4个圆有18个半径
        this.createCircle();
        this.bindEvent();
    }
    //绑定事件
    canvasLock.prototype.bindEvent = function(){
        var self = this;  //一个是canvas对象,一个是window.canvasLock对象
        console.log(this);  //如果直接使用this,那么this指向的就是当前时间调用的对象,也就是this.canvas,
        console.log(self);  //但是在代码中想要使用的是window.canvasLock对象,所以在事件外面提前将this赋值给self变量,确保this的指向问题。
        this.canvas.addEventListener('touchstart',function(e){
            //2.touchstart判断是否点击的位置处于园内getPosition,处于则初始化lastpoint、restPoint
            var po = self.getPosition(e);
            //判断是否在圆内的原理:多出来的这条 x/y < r 在圆内
            for(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 = true;
                    self.lastPoint.push(self.arr[i]);  //把点击的圆心的x轴y轴坐标放入lastPoint数组
                    console.log(self.lastPoint);
                    self.restPoint.splice(i,1);
                    break;
                }
            }
            
        },false);
        this.canvas.addEventListener('touchmove',function(e){
            //  3.touchmove做的就是:画圆drawPoint和划线drawLine
            if(self.touchFlag){
                self.update(self.getPosition(e));
            }
        },false);
        this.canvas.addEventListener('touchend',function(e){
            if(self.touchFlag){
                self.storePass(self.lastPoint);
                setTimeout(function(){
                    self.reset();
                },300);
            }
        },false);
    }
    canvasLock.prototype.getPosition = function(e){  //获取touch点相对于canvas
        //获取canvas上下左右离屏幕的距离
        var rect = e.currentTarget.getBoundingClientRect();  // Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置。
        //po有x和y,并且使相较于canvas边距
        var po = {
            x: (e.touches[0].clientX - rect.left),
            y: (e.touches[0].clientY - rect.top)
        };
        return po;
    }
        
    
    canvasLock.prototype.update = function(po){  
        // 核心变换方法在touchmove时调用
        //清空画布
        this.ctx.clearRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);
        //重画9个圆
        for(var i = 0;i < this.arr.length; i++){
            this.drawCle(this.arr[i].x, this.arr[i].y);
        }
        this.drawPoint();  //画圆
        this.drawLine(po);  //画线
        
        //1.检测手势移动的位置是否处于下一圆的圆内。
        //2.圆内的话则画实心圆 drawPoint
        //3.已经画过实心圆的圆,无需重复检测
        for(var i = 0;i < this.restPoint.length;i++){
            if(Math.abs(po.x - this.restPoint[i].x) < this.r && Math.abs(po.y - this.restPoint[i].y) < this.r){
                this.drawPoint();
                this.lastPoint.push(this.restPoint[i]);
                this.restPoint.splice(i,1);  //画完一个圆就将该圆从restPoint数组中去掉
                break;
            }
        }
    }  
    canvasLock.prototype.drawLine = function(po){  //解锁轨迹
        this.ctx.beginPath();
        this.ctx.lineWidth = 3;
        this.ctx.moveTo(this.lastPoint[0].x, this.lastPoint[0].y);
        for(var i = 1; i < this.lastPoint.length; i++){
            this.ctx.lineTo(this.lastPoint[i].x, this.lastPoint[i].y);
        }
        this.ctx.lineTo(po.x, po.y);
        this.ctx.stroke();
        this.ctx.closePath();
    }
    canvasLock.prototype.drawPoint = function(){  //初始化圆心
        for(var i = 0; i < this.lastPoint.length;i++){
            this.ctx.fillStyle = '#cfe6fe';
            this.ctx.beginPath();
            this.ctx.arc(this.lastPoint[i].x, this.lastPoint[i].y, this.r/2, 0, Math.PI*2, true);
            this.ctx.closePath();
            this.ctx.fill();
        }
    }
    
    canvasLock.prototype.storePass = function(){
        
        if(this.checkPass()){
            document.getElementById('title').innerHTML = '解锁成功';
            this.drawStatusPoint('#2cff26');
        }else{
            document.getElementById('title').innerHTML = '解锁失败';
            this.drawStatusPoint('red');
        }
    }
    canvasLock.prototype.checkPass = function(){
        var p1 = '123';
        p2 = '';
        for(var i = 0; i < this.lastPoint.length; i++){
            p2 += this.lastPoint[i].index;
        }
        return p1 === p2;
    }
    canvasLock.prototype.drawStatusPoint = function(type){
        for(var i = 0; i < this.lastPoint.length; i++){
            this.ctx.strokeStyle = type;
            this.ctx.beginPath();
            this.ctx.arc(this.lastPoint[i].x, this.lastPoint[i].y, this.r, 0, Math.PI*2, true);
            this.ctx.closePath();
            this.ctx.stroke();
        }
    }
    canvasLock.prototype.reset = function(){
        this.createCircle();
    }
})();
原文地址:https://www.cnblogs.com/rickdiculous/p/11509709.html