思路:
手勢密碼思路:
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:
關閉彈框
密碼錯誤
密碼正確
圓與圓之間的間距