思路:
手势密码思路:
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:
关闭弹框
密码错误
密码正确
圆与圆之间的间距