思路:
手势密码思路:
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
来源:oschina
链接:https://my.oschina.net/u/4259099/blog/4273368