计算机教程

HTML5实现屏幕手势解锁

23 4月 , 2019  

3. 画折线

所谓的画折线,就是,将已经触摸到的点连起来,可以把它看作是画折线。

首先,要用两个数组,一个数组用于已经 touch 过的点,另一个数组用于存储未
touch 的点,然后在 move 监听时候,对 touch
的相对位置进行判断,如果触到点,就把该点从未 touch 移到 touch
中,然后,画折线,思路也很简单。

JavaScript

drawLine: function(p){ // 画折线 this.ctx.beginPath();
this.ctx.lineWidth = 3; this.ctx.moveTo(this.touchCircles[0].x,
this.touchCircles[0].y); for (var i = 1 ; i <
this.touchCircles.length ; i++) {
this.ctx.lineTo(this.touchCircles[i].x, this.touchCircles[i].y); }
this.ctx.lineTo(p.x, p.y); this.ctx.stroke(); this.ctx.closePath(); },

1
2
3
4
5
6
7
8
9
10
11
drawLine: function(p){ // 画折线
  this.ctx.beginPath();
  this.ctx.lineWidth = 3;
  this.ctx.moveTo(this.touchCircles[0].x, this.touchCircles[0].y);
  for (var i = 1 ; i < this.touchCircles.length ; i++) {
    this.ctx.lineTo(this.touchCircles[i].x, this.touchCircles[i].y);
  }
  this.ctx.lineTo(p.x, p.y);
  this.ctx.stroke();
  this.ctx.closePath();
},

JavaScript

judgePos: function(p){ // 判断 触点 是否在 circle 內 for(var i = 0; i
< this.restCircles.length; i++){ temp = this.restCircles[i];
if(Math.abs(p.x – temp.x) < r && Math.abs(p.y – temp.y) < r){
this.touchCircles.push(temp); this.restCircles.splice(i, 1);
this.touchFlag = true; break; } } }

1
2
3
4
5
6
7
8
9
10
11
judgePos: function(p){ // 判断 触点 是否在 circle 內
  for(var i = 0; i < this.restCircles.length; i++){
    temp = this.restCircles[i];
    if(Math.abs(p.x – temp.x) < r && Math.abs(p.y – temp.y) < r){
      this.touchCircles.push(temp);
      this.restCircles.splice(i, 1);
      this.touchFlag = true;
      break;
    }
  }
}

HTML5实现屏幕手势解锁

2015/07/18 · HTML5 · 1
评论
必赢娱乐棋牌, ·
手势解锁

原文出处:
AlloyTeam   

效果展示

必赢娱乐棋牌 1

实现原理 利用HTML5的canvas,将解锁的圈圈划出,利用touch事件解锁这些圈圈,直接看代码。

JavaScript

function createCircle() {//
创建解锁点的坐标,根据canvas的大小来平均分配半径 var n = chooseType;//
画出n*n的矩阵 lastPoint = []; arr = []; restPoint = []; r =
ctx.canvas.width / (2 + 4 * n);// 公式计算 半径和canvas的大小有关 for
(var i = 0 ; i < n ; i++) { for (var j = 0 ; j < n ; j++) {
arr.push({ x: j * 4 * r + 3 * r, y: i * 4 * r + 3 * r });
restPoint.push({ x: j * 4 * r + 3 * r, y: i * 4 * r + 3 * r }); }
} //return arr; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function createCircle() {// 创建解锁点的坐标,根据canvas的大小来平均分配半径
 
        var n = chooseType;// 画出n*n的矩阵
        lastPoint = [];
        arr = [];
        restPoint = [];
        r = ctx.canvas.width / (2 + 4 * n);// 公式计算 半径和canvas的大小有关
        for (var i = 0 ; i < n ; i++) {
            for (var j = 0 ; j < n ; j++) {
                arr.push({
                    x: j * 4 * r + 3 * r,
                    y: i * 4 * r + 3 * r
                });
                restPoint.push({
                    x: j * 4 * r + 3 * r,
                    y: i * 4 * r + 3 * r
                });
            }
        }
        //return arr;
    }

canvas里的圆圈画好之后可以进行事件绑定

JavaScript

function bindEvent() { can.addEventListener(“touchstart”, function (e) {
var po = getPosition(e); console.log(po); for (var i = 0 ; i <
arr.length ; i++) { if (Math.abs(po.x – arr[i].x) < r &&
Math.abs(po.y – arr[i].y) < r) { // 用来判断起始点是否在圈圈内部
touchFlag = true; drawPoint(arr[i].x,arr[i].y);
lastPoint.push(arr[i]); restPoint.splice(i,1); break; } } }, false);
can.addEventListener(“touchmove”, function (e) { if (touchFlag) {
update(getPosition(e)); } }, false); can.addEventListener(“touchend”,
function (e) { if (touchFlag) { touchFlag = false; storePass(lastPoint);
setTimeout(function(){ init(); }, 300); } }, false); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function bindEvent() {
        can.addEventListener("touchstart", function (e) {
             var po = getPosition(e);
             console.log(po);
             for (var i = 0 ; i < arr.length ; i++) {
                if (Math.abs(po.x – arr[i].x) < r && Math.abs(po.y – arr[i].y) < r) { // 用来判断起始点是否在圈圈内部
 
                    touchFlag = true;
                    drawPoint(arr[i].x,arr[i].y);
                    lastPoint.push(arr[i]);
                    restPoint.splice(i,1);
                    break;
                }
             }
         }, false);
         can.addEventListener("touchmove", function (e) {
            if (touchFlag) {
                update(getPosition(e));
            }
         }, false);
         can.addEventListener("touchend", function (e) {
             if (touchFlag) {
                 touchFlag = false;
                 storePass(lastPoint);
                 setTimeout(function(){
 
                    init();
                }, 300);
             }
 
         }, false);
    }

接着到了最关键的步骤绘制解锁路径逻辑,通过touchmove事件的不断触发,调用canvas的moveTo方法和lineTo方法来画出折现,同时判断是否达到我们所画的圈圈里面,其中lastPoint保存正确的圈圈路径,restPoint保存全部圈圈去除正确路径之后剩余的。
Update方法:

JavaScript

function update(po) {// 核心变换方法在touchmove时候调用 ctx.clearRect(0,
0, ctx.canvas.width, ctx.canvas.height); for (var i = 0 ; i <
arr.length ; i++) { // 每帧先把面板画出来 drawCle(arr[i].x,
arr[i].y); } drawPoint(lastPoint);// 每帧花轨迹 drawLine(po ,
lastPoint);// 每帧画圆心 for (var i = 0 ; i < restPoint.length ; i++)
{ if (Math.abs(po.x – restPoint[i].x) < r && Math.abs(po.y –
restPoint[i].y) < r) { drawPoint(restPoint[i].x,
restPoint[i].y); lastPoint.push(restPoint[i]); restPoint.splice(i,
1); break; } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function update(po) {// 核心变换方法在touchmove时候调用
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
 
        for (var i = 0 ; i < arr.length ; i++) { // 每帧先把面板画出来
            drawCle(arr[i].x, arr[i].y);
        }
 
        drawPoint(lastPoint);// 每帧花轨迹
        drawLine(po , lastPoint);// 每帧画圆心
 
        for (var i = 0 ; i < restPoint.length ; i++) {
            if (Math.abs(po.x – restPoint[i].x) < r && Math.abs(po.y – restPoint[i].y) < r) {
                drawPoint(restPoint[i].x, restPoint[i].y);
                lastPoint.push(restPoint[i]);
                restPoint.splice(i, 1);
                break;
            }
        }
 
    }

最后就是收尾工作,把路径里面的lastPoint保存的数组变成密码存在localstorage里面,之后就用来处理解锁验证逻辑了

JavaScript

function storePass(psw) {// touchend结束之后对密码和状态的处理 if
(pswObj.step == 1) { if (checkPass(pswObj.fpassword, psw)) { pswObj.step
= 2; pswObj.spassword = psw; document.getElementById(‘title’).innerHTML
= ‘密码保存成功’; drawStatusPoint(‘#2CFF26’);
window.localStorage.setItem(‘passwordx’,
JSON.stringify(pswObj.spassword));
window.localStorage.setItem(‘chooseType’, chooseType); } else {
document.getElementById(‘title’).innerHTML = ‘两次不一致,重新输入’;
drawStatusPoint(‘red’); delete pswObj.step; } } else if (pswObj.step ==
2) { if (checkPass(pswObj.spassword, psw)) {
document.getElementById(‘title’).innerHTML = ‘解锁成功’;
drawStatusPoint(‘#2CFF26’); } else { drawStatusPoint(‘red’);
document.getElementById(‘title’).innerHTML = ‘解锁失败’; } } else {
pswObj.step = 1; pswObj.fpassword = psw;
document.getElementById(‘title’).innerHTML = ‘再次输入’; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function storePass(psw) {// touchend结束之后对密码和状态的处理
        if (pswObj.step == 1) {
            if (checkPass(pswObj.fpassword, psw)) {
                pswObj.step = 2;
                pswObj.spassword = psw;
                document.getElementById(‘title’).innerHTML = ‘密码保存成功’;
                drawStatusPoint(‘#2CFF26’);
                window.localStorage.setItem(‘passwordx’, JSON.stringify(pswObj.spassword));
                window.localStorage.setItem(‘chooseType’, chooseType);
            } else {
                document.getElementById(‘title’).innerHTML = ‘两次不一致,重新输入’;
                drawStatusPoint(‘red’);
                delete pswObj.step;
            }
        } else if (pswObj.step == 2) {
            if (checkPass(pswObj.spassword, psw)) {
                document.getElementById(‘title’).innerHTML = ‘解锁成功’;
                drawStatusPoint(‘#2CFF26’);
            } else {
                drawStatusPoint(‘red’);
                document.getElementById(‘title’).innerHTML = ‘解锁失败’;
            }
        } else {
            pswObj.step = 1;
            pswObj.fpassword = psw;
            document.getElementById(‘title’).innerHTML = ‘再次输入’;
        }
 
    }

解锁组件

将这个HTML5解锁写成了一个组件,放在https://github.com/lvming6816077/H5lock

二维码体验: 必赢娱乐棋牌 2

 

参考资料:http://www.nihaoshijie.com.cn/index.php/archives/537

1 赞 4 收藏 1
评论

必赢娱乐棋牌 3

总结

大概花了三天左右的时间,将这个 H5
的手势解锁给完成,自己还是比较满意的,虽然可能达不到评委老师的认可,不过自己在做的过程中,学习到了很多新知识。

1. 添加 message 和 单选框

为了尽可能的使界面简洁(越丑越好),直接在 body 后面添加了:

XHTML

<div id=”select”> <div
class=”message”>请输入手势密码</div> <div class=”radio”>
<label><input type=”radio”
name=”pass”>设置手势密码</label> <label><input
type=”radio” name=”pass”>验证手势密码</label> </div>
</div>

1
2
3
4
5
6
7
<div id="select">
  <div class="message">请输入手势密码</div>
  <div class="radio">
    <label><input type="radio" name="pass">设置手势密码</label>
    <label><input type="radio" name="pass">验证手势密码</label>
  </div>
</div>

将添加到 dom 已 option 的形式传给 handLock:

var el = document.getElementById(‘handlock’), info =
el.getElementsByClassName(‘info’)[0], select =
document.getElementById(‘select’), message =
select.getElementsByClassName(‘message’)[0], radio =
select.getElementsByClassName(‘radio’)[0], setPass =
radio.children[0].children[0], checkPass =
radio.children[1].children[0]; new handLock({ el: el, info: info,
message: message, setPass: setPass, checkPass: checkPass, n: 3
}).init();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var el = document.getElementById(‘handlock’),
  info = el.getElementsByClassName(‘info’)[0],
  select = document.getElementById(‘select’),
  message = select.getElementsByClassName(‘message’)[0],
  radio = select.getElementsByClassName(‘radio’)[0],
  setPass = radio.children[0].children[0],
  checkPass = radio.children[1].children[0];
new handLock({
  el: el,
  info: info,
  message: message,
  setPass: setPass,
  checkPass: checkPass,
  n: 3
}).init();

参考

H5lock
Canvas教程
js获取单选框里面的值
前端高性能滚动 scroll
及页面渲染优化

3 赞 5 收藏
评论

必赢娱乐棋牌 4

4. 手动重置密码

思路也很简单,就是添加点击事件,点击之后,改变 model
即可,点击事件如下:

this.dom.setPass.addEventListener(‘click’, function(e){
self.lsPass.model = 2; // 改变 model 为设置密码 self.updateMessage(); //
更新 message self.showInfo(‘请设置密码’, 1000); })
this.dom.checkPass.addEventListener(‘click’, function(e){
if(self.lsPass.pass){ self.lsPass.model = 1; self.updateMessage();
self.showInfo(‘请验证密码’, 1000) }else{ self.showInfo(‘请先设置密码’,
1000); self.updateMessage(); } })

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
this.dom.setPass.addEventListener(‘click’, function(e){
  self.lsPass.model = 2; // 改变 model 为设置密码
  self.updateMessage(); // 更新 message
  self.showInfo(‘请设置密码’, 1000);
})
this.dom.checkPass.addEventListener(‘click’, function(e){
  if(self.lsPass.pass){
    self.lsPass.model = 1;
    self.updateMessage();
    self.showInfo(‘请验证密码’, 1000)
  }else{
    self.showInfo(‘请先设置密码’, 1000);
    self.updateMessage();
  }
})

ps:这里面还有几个小的 bug,因为 model 只有 3
个,所以设置的时候,当点击重置密码的时候,没有设置密码成功,又切成验证密码状态,此时无法提升沿用旧密码,原因是
model 只有三个

关于 showInfo

由于showInfo 中有 setTimeout 函数,可以看到函数里的演出为
1s,导致如果我们操作的速度比较快,在 1s 内连续 show 了很多个
info,后面的 info 会被第一个 info 的 setTimeout 弄乱,显示的时间小于
1s,或更短。比如,当重复点击设置手势密码和验证手势密码,会产生这个 bug。

解决办法有两个,一个是增加一个专门用于显示的数组,每次从数组中取值然后显示。另一种解题思路和防抖动的思路很像,就是当有一个新的
show 到来时,把之前的那个 setTimeout 清除掉。

这里采用第二种思路:

showInfo: function(message, timer){ // 专门用来显示 info
clearTimeout(this.showInfo.timer); var info = this.dom.info;
info.innerHTML = message; info.style.display = ‘block’;
this.showInfo.timer = setTimeout(function(){ info.style.display = ”; },
timer || 1000) },

1
2
3
4
5
6
7
8
9
showInfo: function(message, timer){ // 专门用来显示 info
  clearTimeout(this.showInfo.timer);
  var info = this.dom.info;
  info.innerHTML = message;
  info.style.display = ‘block’;
  this.showInfo.timer = setTimeout(function(){
    info.style.display = ”;
  }, timer || 1000)
},

解决小尾巴

所谓的小尾巴,如下:

必赢娱乐棋牌 5

解决办法也很简单,在 touchend 的时候,先进行 clearRect 就 ok 了。

准备及布局设置

我这里用了一个比较常规的做法:

(function(w){ var handLock = function(option){} handLock.prototype = {
init : function(){}, … } w.handLock = handLock; })(window) // 使用 new
handLock({ el: document.getElementById(‘id’), … }).init();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(function(w){
  var handLock = function(option){}
 
  handLock.prototype = {
    init : function(){},
    …
  }
 
  w.handLock = handLock;
})(window)
 
// 使用
new handLock({
  el: document.getElementById(‘id’),
  …
}).init();

常规方法,比较易懂和操作,弊端就是,可以被随意的修改。

传入的参数中要包含一个 dom 对象,会在这个 dom 对象內创建一个
canvas。当然还有一些其他的 dom 参数,比如 message,info 等。

关于 css 的话,懒得去新建文件了,就直接內联了。

4. 标记已画

前面已经说了,我们把已经 touch
的点(圆)放到数组中,这个时候需要将这些已经 touch
的点给标记一下,在圆心处画一个小实心圆:

JavaScript

drawPoints: function(){ for (var i = 0 ; i < this.touchCircles.length
; i++) { this.ctx.fillStyle = ‘#FFFFFF’; this.ctx.beginPath();
this.ctx.arc(this.touchCircles[i].x, this.touchCircles[i].y, this.r
/ 2, 0, Math.PI * 2, true); this.ctx.closePath(); this.ctx.fill(); } }

1
2
3
4
5
6
7
8
9
drawPoints: function(){
  for (var i = 0 ; i < this.touchCircles.length ; i++) {
    this.ctx.fillStyle = ‘#FFFFFF’;
    this.ctx.beginPath();
    this.ctx.arc(this.touchCircles[i].x, this.touchCircles[i].y, this.r / 2, 0, Math.PI * 2, true);
    this.ctx.closePath();
    this.ctx.fill();
  }
}

同时添加一个 reset 函数,当 touchend 的时候调用,400ms 调用 reset 重置
canvas。

到现在为止,一个 H5 手势解锁的简易版已经基本完成。

用 canvas 实现 Web 手势解锁

2017/04/04 · HTML5 ·
Canvas

原文出处: songjz   

最近参加 360 暑假的前端星计划,有一个在线作业,截止日期是 3 月 30
号,让手动实现一个 H5 手势解锁,具体的效果就像原生手机的九宫格解锁那样。

必赢娱乐棋牌 6

实现的最终效果就像下面这张图这样:

必赢娱乐棋牌 7

基本要求是这样的:将密码保存到 localStorage
里,开始的时候会从本地读取密码,如果没有就让用户设置密码,密码最少为五位数,少于五位要提示错误。需要对第一次输入的密码进行验证,两次一样才能保持,然后是验证密码,能够对用户输入的密码进行验证。

2. 画线

画线需要借助 touch event 来完成,也就是,当我们 touchstart
的时候,传入开始时的相对坐标,作为线的一端,当我们 touchmove
的时候,获得坐标,作为线的另一端,当我们 touchend 的时候,开始画线。

这只是一个测试画线功能,具体的后面再进行修改。

有两个函数,获得当前 touch 的相对坐标:

getTouchPos: function(e){ // 获得触摸点的相对位置 var rect =
e.target.getBoundingClientRect(); var p = { // 相对坐标 x:
e.touches[0].clientX – rect.left, y: e.touches[0].clientY – rect.top
}; return p; }

1
2
3
4
5
6
7
8
getTouchPos: function(e){ // 获得触摸点的相对位置
  var rect = e.target.getBoundingClientRect();
  var p = { // 相对坐标
    x: e.touches[0].clientX – rect.left,
    y: e.touches[0].clientY – rect.top
  };
  return p;
}

画线:

drawLine: function(p1, p2){ // 画线 this.ctx.beginPath();
this.ctx.lineWidth = 3; this.ctx.moveTo(p1.x, p2.y);
this.ctx.lineTo(p.x, p.y); this.ctx.stroke(); this.ctx.closePath(); },

1
2
3
4
5
6
7
8
drawLine: function(p1, p2){ // 画线
  this.ctx.beginPath();
  this.ctx.lineWidth = 3;
  this.ctx.moveTo(p1.x, p2.y);
  this.ctx.lineTo(p.x, p.y);
  this.ctx.stroke();
  this.ctx.closePath();
},

然后就是监听 canvas 的 touchstarttouchmove、和 touchend 事件了。


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图