上一篇结合在canvas原理中,绘制了手势解锁的初始界面,我们也知道,手势解锁的难点不在于初始界面的绘制,而在于手势移动过程中界面的一系列变化,包括触摸到的点的颜色变化,以及添加的线条路径,这些都是得通过JS交互来实现的,在这个应用中,主要涉及的是JS HTML5事件中的触摸事件。
回顾一下,(一)里面的JS事件机制和触摸事件:
touchstart: 开始触摸时触发
touchend: 在触摸结束时触发
touchmove: 在触发移动过程中触发。注意:在移动设备上触摸移动时会默认触发滚动事件,因此利用perventDefalut()将其默认行为取消。
每个触发事件都对应的事件对象。对于touchstart和touchmove事件,事件对象中有一个touches数组,这里面包括触摸的clientX,clientY,target等属性信息。
在各个触摸事件都了解的情况下,我们应该思考各个事件处理程序应该如何写,也就是一开始按下某点的时候如何操作,结束触摸时如何响应,以及在触摸移动过程中又该有什么样的操作。下面我们一个一个来解决。
- touchstart事件
在一开始触摸移动设备时,应该对于触摸到的点进行填充。
如何确定触摸到的点是哪一个?(利用触摸点与9个点圆心之间的距离,小于半径r就认为是哪个点)
for(var num = 0; num< pointArr.length; num++)
{
var CurrX = e.touches[0].clientX - pointArr[num].x;
var CurrY = e.touches[0].clientY - pointArr[num].y;
var dis = Math.pow((Math.pow(CurrX, 2) + Math.pow( CurrY, 2)), 0.5);
if(dis <= r)
{
//console.log(pointArr[num].id);
//对这个点着色
DrawColor(pointArr[num].x, pointArr[num].y);
//LineArr.push(pointArr[num]);
break;
}
}
当第二次开始触摸时,又应该将之前的绘制路径清空。然后再对触摸点进行颜色填充表示该点已选。
if(Count >= 2)
{
ctx.clearRect(0, 0, 1200, 1200);
//把颜色都设为white,然后去填充和描边;
DrawCirclePanel(pointArr);
for(var i = 0; i < pointArr.length; i++)
{
pointArr[i].visited = false;
}
}
2.touchmove事件
由于在touchmove事件触发时,H5默认会触发滚动事件,因此首先要取消事件的默认行为。
var handlerMove = function(e){
e.preventDefault();
另外,在触摸移动过程中,需要把选择的点进行填充,再根据选择的点画出一条路径,我们可以考虑用绘制路径的lineTo(x,y)来实现。不难想到,要画线,必须知道点的圆心坐标才可以画出点到点的线。因此,引入一个数组LineArr来保存已选中的那些点是必要的。
CurrX = e.touches[0].clientX - pointArr[num].x;
CurrY = e.touches[0].clientY - pointArr[num].y;
dis = Math.pow((Math.pow(CurrX, 2) + Math.pow( CurrY, 2)), 0.5);
/*console.log(dis);*/
if(dis <= r)
{
pointArr[num].visited = true;
//对这个点着色
DrawColor(pointArr[num].x, pointArr[num].y);
//还要划线;需要知道前后的点的坐标;可以考虑这样来做:
//即把划到的那些点都push进一个数组里,然后只需沿着数组中这些点的坐标画线就可以
LineArr.push(pointArr[num]);
}
//接下来对LineArr中的点连线
if(LineArr.length > 1)
{
var len = LineArr.length;
ctx.strokeStyle = "rgba(255,255,10, 0.8)";
DrawLine(LineArr[len - 2], LineArr[len - 1]);
}
这样,在触摸过程中的基本处理就结束了。
3. touchend事件
在触摸结束之后,我们该如何处理呢?
一种就是该过程是设置手势密码的过程:
该情况下的事件处理程序主要做的就是将绘制的密码存到LocalStorage中。
注意:LocalStoarge只能存储字符串,因存储时要将object对象转换为字符串(调用JSON.stringify)
var localS = window.localStorage;
localS.setItem('result', JSON.stringify(LineArr)); //localStorage 只能保存字符串
setLock = false; //将全局变量setLock设为false,表示下一次将是解锁过程
另一种是解锁过程:
该情况下的事件处理程序主要做这几件事:
先将得到缓存中的密码;
将取到的密码与本次绘制的密码相比较。
var getStorage = localS.getItem("result"); //localStorage 只能保存字符串,因此取出来也只能是字符串格式,因此将其转换为JSON格式
var res = JSON.parse(getStorage);
if(res.length != LineArr.length)
{
alert('两次输入的密码长度不一致,请重新解锁!');
setLock = false;
}
else
{
for(var i = 0; i < LineArr.length; i++)
{
if(res[i].id != LineArr[i].id)
{
alert("两次输入的密码不一致,请重新解锁!");
break;
setLock = false;
}
}
if(i == LineArr.length)
{
alert("解锁成功!");
setLock = true;
}
}
下面说说H5缓存的Localstorage和SessionStorage吧。
两者都是在客户端进行存储的,但是也有区别。
LocalStorage必须手动清除才会消失,不然,一旦保存就不会消失;
而sessionStorage属于会话级别的,当浏览器窗口关闭之后保存的这个信息就不在了。
至此,本次手势解锁过程结束。当然,还存在有两个问题,后面还会改进。至于源代码,可以访问我的Github地址:https://github.com/DangDangHellen/GestureLock