1. 程式人生 > >用 canvas 實現 Web 手勢解鎖

用 canvas 實現 Web 手勢解鎖

實現的最終效果就像下面這張圖這樣:
11.png 
基本要求是這樣的:將密碼儲存到 localStorage 裡,開始的時候會從本地讀取密碼,如果沒有就讓使用者設定密碼,密碼最少為五位數,少於五位要提示錯誤。需要對第一次輸入的密碼進行驗證,兩次一樣才能保持,然後是驗證密碼,能夠對使用者輸入的密碼進行驗證。
H5 手勢解鎖

準備及佈局設定

我這裡用了一個比較常規的做法:
  1. (function(w){
  2.   var handLock = function(option){}
  3.   handLock.prototype = {
  4.     init : function(){},
  5.     ...
  6.   }
  7.   w.handLock = handLock;
  8. })(window)
  9. // 使用
  10. new handLock({
  11.   el: document.getElementById('id'),
  12.   ...
  13. }).init();
複製程式碼 常規方法,比較易懂和操作,弊端就是,可以被隨意的修改。

傳入的引數中要包含一個 dom 物件,會在這個 dom 物件內建立一個 canvas。當然還有一些其他的 dom 引數,比如 message,info 等。

關於 css 的話,懶得去新建檔案了,就直接內聯了。
canvas

1. 學習 canvas 並搞定畫圓

MDN 上面有個簡易的教程,大致瀏覽了一下,感覺還行。Canvas教程。

先建立一個 canvas,然後設定其大小,並通過 getContext 方法獲得繪畫的上下文:
  1. var canvas = document.createElement('canvas');
  2. canvas.width = canvas.height = width;
  3. this.el.appendChild(canvas);
  4. this.ctx = canvas.getContext('2d');
複製程式碼 然後呢,先畫 n*n 個圓出來:

  1. createCircles: function(){
  2.   var ctx = this.ctx,
  3.     drawCircle = this.drawCircle,
  4.     n = this.n;
  5.   this.r = ctx.canvas.width / (2 + 4 * n) // 這裡是參考的,感覺這種畫圓的方式挺合理的,方方圓圓
  6.   r = this.r;
  7.   this.circles = []; // 用來儲存圓心的位置
  8.   for(var i = 0; i < n; i++){
  9.     for(var j = 0; j < n; j++){
  10.       var p = {
  11.         x: j * 4 * r + 3 * r,
  12.         y: i * 4 * r + 3 * r,
  13.         id: i * 3 + j
  14.       }
  15.       this.circles.push(p);
  16.     }
  17.   }
  18.   ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // 為了防止重複畫
  19.   this.circles.forEach(function(v){
  20.     drawCircle(ctx, v.x, v.y); // 畫每個圓
  21.   })
  22. },
  23. drawCircle: function(ctx, x, y){ // 畫圓函式
  24.   ctx.strokeStyle = '#FFFFFF';
  25.   ctx.lineWidth = 2;
  26.   ctx.beginPath();
  27.   ctx.arc(x, y, this.r, 0, Math.PI * 2, true);
  28.   ctx.closePath();
  29.   ctx.stroke();
  30. }
複製程式碼 畫圓函式,需要注意:如何確定圓的半徑和每個圓的圓心座標(這個我是參考的),如果以圓心為中點,每個圓上下左右各擴充套件一個半徑的距離,同時為了防止四邊太擠,四周在填充一個半徑的距離。那麼得到的半徑就是 width / ( 4 * n + 2),對應也可以算出每個圓所在的圓心座標,也有一套公式,GET。
2. 畫線

畫線需要藉助 touch event 來完成,也就是,當我們 touchstart 的時候,傳入開始時的相對座標,作為線的一端,當我們 touchmove 的時候,獲得座標,作為線的另一端,當我們 touchend 的時候,開始畫線。

這只是一個測試畫線功能,具體的後面再進行修改。

有兩個函式,獲得當前 touch 的相對座標:
  1. getTouchPos: function(e){ // 獲得觸控點的相對位置
  2.   var rect = e.target.getBoundingClientRect();
  3.   var p = { // 相對座標
  4.     x: e.touches[0].clientX - rect.left,
  5.     y: e.touches[0].clientY - rect.top
  6.   };
  7.   return p;
  8. }
複製程式碼 畫線:
  1. drawLine: function(p1, p2){ // 畫線
  2.   this.ctx.beginPath();
  3.   this.ctx.lineWidth = 3;
  4.   this.ctx.moveTo(p1.x, p2.y);
  5.   this.ctx.lineTo(p.x, p.y);
  6.   this.ctx.stroke();
  7.   this.ctx.closePath();
  8. },
複製程式碼 然後就是監聽 canvas 的 touchstart、touchmove、和 touchend 事件了。
3. 畫折線

所謂的畫折線,就是,將已經觸控到的點連起來,可以把它看作是畫折線。

首先,要用兩個陣列,一個數組用於已經 touch 過的點,另一個數組用於儲存未 touch 的點,然後在 move 監聽時候,對 touch 的相對位置進行判斷,如果觸到點,就把該點從未 touch 移到 touch 中,然後,畫折線,思路也很簡單。
  1. drawLine: function(p){ // 畫折線
  2.   this.ctx.beginPath();
  3.   this.ctx.lineWidth = 3;
  4.   this.ctx.moveTo(this.touchCircles[0].x, this.touchCircles[0].y);
  5.   for (var i = 1 ; i < this.touchCircles.length ; i++) {
  6.     this.ctx.lineTo(this.touchCircles[i].x, this.touchCircles[i].y);
  7.   }
  8.   this.ctx.lineTo(p.x, p.y);
  9.   this.ctx.stroke();
  10.   this.ctx.closePath();
  11. },
複製程式碼
  1. judgePos: function(p){ // 判斷 觸點 是否在 circle 內
  2.   for(var i = 0; i < this.restCircles.length; i++){
  3.     temp = this.restCircles[i];
  4.     if(Math.abs(p.x - temp.x) < r && Math.abs(p.y - temp.y) < r){
  5.       this.touchCircles.push(temp);
  6.       this.restCircles.splice(i, 1);
  7.       this.touchFlag = true;
  8.       break;
  9.     }
  10.   }
  11. }
複製程式碼 4. 標記已畫

前面已經說了,我們把已經 touch 的點(圓)放到陣列中,這個時候需要將這些已經 touch 的點給標記一下,在圓心處畫一個小實心圓:
  1. drawPoints: function(){
  2.   for (var i = 0 ; i < this.touchCircles.length ; i++) {
  3.     this.ctx.fillStyle = '#FFFFFF';
  4.     this.ctx.beginPath();
  5.     this.ctx.arc(this.touchCircles[i].x, this.touchCircles[i].y, this.r / 2, 0, Math.PI * 2, true);
  6.     this.ctx.closePath();
  7.     this.ctx.fill();
  8.   }
  9. }
複製程式碼 同時新增一個 reset 函式,當 touchend 的時候呼叫,400ms 呼叫 reset 重置 canvas。

到現在為止,一個 H5 手勢解鎖的簡易版已經基本完成。
password

為了要實現記住和重置密碼的功能,把 password 儲存在 localStorage 中,但首先要新增必要的 html 和樣式。
1. 新增 message 和 單選框

為了儘可能的使介面簡潔(越醜越好),直接在 body 後面添加了:
  1. <div id="select">
  2.   <div class="message">請輸入手勢密碼</div>
  3.   <div class="radio">
  4.     <label><input type="radio" name="pass">設定手勢密碼</label>
  5.     <label><input type="radio" name="pass">驗證手勢密碼</label>
  6.   </div>
  7. </div>
複製程式碼 將新增到 dom 已 option 的形式傳給 handLock:
  1. var el = document.getElementById('handlock'),
  2.   info = el.getElementsByClassName('info')[0],
  3.   select = document.getElementById('select'),
  4.   message = select.getElementsByClassName('message')[0],
  5.   radio = select.getElementsByClassName('radio')[0],
  6.   setPass = radio.children[0].children[0],
  7.   checkPass = radio.children[1].children[0];
  8. new handLock({
  9.   el: el,
  10.   info: info,
  11.   message: message,
  12.   setPass: setPass,
  13.   checkPass: checkPass,
  14.   n: 3
  15. }).init();
複製程式碼 2. info 資訊顯示

關於 info 資訊顯示,自己寫了一個懸浮窗,然後預設為 display: none,然後寫了一個 showInfo 函式用來顯示提示資訊,直接呼叫:
  1. showInfo: function(message, timer){ // 專門用來顯示 info
  2.   var info = this.dom.info;
  3.   info.innerHTML = message;
  4.   info.style.display = 'block';
  5.   setTimeout(function(){
  6.     info.style.display = '';
  7.   }, 1000)
  8. }
複製程式碼 關於 info 的樣式,在 html 中呢。
3. 關於密碼

先不考慮從 localStorage 讀取到情況,新加一個 lsPass 物件,專門用於儲存密碼,由於密碼情況比較多,比如設定密碼,二次確認密碼,驗證密碼,為了方便管理,暫時設定了密碼的三種模式,分別是:
    model:1 驗證密碼模式

    model:2 設定密碼模式

    model:3 設定密碼二次驗證

具體看下面這個圖:
22.jpeg 
這三種 model ,只要處理好它們之間如何跳轉就 ok 了,即狀態的改變。

所以就有了 initPass:
  1. initPass: function(){ // 將密碼初始化
  2.   this.lsPass = w.localStorage.getItem('HandLockPass') ? {
  3.     model: 1,
  4.     pass: w.localStorage.getItem('HandLockPass').split('-')
  5.   } : { model: 2 };
  6.   this.updateMessage();
  7. 相關推薦

    canvas 實現 Web 手勢

    實現的最終效果就像下面這張圖這樣:   基本要求是這樣的:將密碼儲存到 localStorage 裡,開始的時候會從本地讀取密碼,如果沒有就讓使用者設定密碼,密碼最少為五位數,少於五位要提示錯誤。需要對第一次輸入的密碼進行驗證,兩次一樣才能保持,然後是驗證密碼,能夠對

    canvas手勢遇到的關於js匿名函式的問題

    今天在用canvas寫一個手勢解鎖的專案中,遇到一個問題,儘管我已經在js中聲明瞭一個全域性函式,但是沒有效果,開啟控制檯後一直報錯如下:       繞了很大一圈,發現我和原始碼就是在函式最後面缺少一個“();”,下面是原始碼, (function(){

    WPF實現手勢

    桌面程式的解鎖方式一般是賬號密碼,網際網路的可以使用掃碼解鎖,甚至人臉識別。但掃碼需要網路,人臉識別又較複雜。所以就想把安卓常用的手勢解鎖移植到桌面程式上。 先來張效果圖,有興趣的往下看,沒興趣的打擾了。      WPF手勢解鎖使用滑鼠點選事件,滑鼠移動事件,滑鼠彈起事件實現

    如何優雅地Redis實現分布式

    cal 沒有 cond 發現 指定 finally 描述 sel 現在 https://mp.weixin.qq.com/s?__biz=MzAxNjM2MTk0Ng==&mid=2247484976&idx=2&sn=a0b6771f0b4e471

    Websocket實現Web IM(一)

    前言:最近領導要求做一版簡單的類似web版微信web IM作為其他產品的過渡,經過跟同事討論後,決定用websocket嘗試做一下(微信使用的是長輪詢保持連線)。首先要解決的是掃碼登入和重連機制問題,雖然實現起來很簡單,但是以防忘記,還是要記錄一下。 一、掃碼登陸 1、二維碼

    canvas實現紅心飄飄的動畫效果

    兩週前,專案裡需要實現一個紅心飄飄的點贊效果。抓耳撓腮了老半天,看了幾篇大佬的文章,終於算是摸了個七七八八。不禁長嘆一聲,還是菜啊。先來看一下效果:(傳送門進去點一波) 一、Bezier曲線運動軌跡 其實用大白話描述一下需求就是讓一個紅心圖片沿著貝塞爾曲線的軌跡走,然後邊走邊消失。核心在於得到貝塞爾曲線

    開發工具起來,輕松Word更多隱藏技能!

    自定義功能區 打開 mark type 內容 EDA size pro 切換 你知道Word文檔中有一個不常提到卻很實用的排版工具嗎?它就是開發工具。今天小編就給大家分享3個關於使用開發工具的小技巧。 1.怎麽制作選擇題的方框? 先點擊"文件",選擇&q

    canvas實現一個vue彈幕元件

    看B站時,對彈幕的實現產生了興趣,一開始想到用css3動畫去實現,後來感覺這樣效能不是很好,查了下資料,發現可以用canvas實現,於是就摸索著寫了一個簡單的彈幕。 彈幕功能 支援動態新增彈幕 彈幕不重疊 自定義彈幕顏色 效果圖 demo  原始碼地址 前端框架選了比較熟悉的vuejs

    OC螢幕手勢

    感覺螢幕解鎖好像很牛的樣子,所以試著寫了一個,程式碼很簡單,手勢用到的也是原生的,如果該程式碼幫助了你,記得點贊,如果該程式碼有任何問題,也可以隨時和我聯絡。改程式碼用到的兩張圖片,是我隨便找的兩張,可以自行找圖片代替 效果圖: 需要用到的程式碼: ScreenLockView.h #i

    我在mycat實現web專案的多租戶(一)

    還沒畢業的小菜雞,在實習,領導讓做多租戶,於是聽說了mycat。 首先先去百度了Mycat。(指路官網:http://www.mycat.io/) 很開心的發現有官方文件(Mycat權威指南),還是我能看得懂的中文,真開心。 我有pdf的,想要的私信我。 快300頁的文件,我只看了前

    android手勢-------後臺恢復到前臺就啟動手勢

    我們在使用支付寶的時候會發現,每次我們按下返回鍵或者home鍵回到桌面之後,再次開啟此app時就會要求我們輸入手勢,正確輸入後會回到我們退出app時的activity,這個效果該如何實現呢。。。 首先

    iOS 開發實戰-屏介面(手勢

    之前寫了一篇關於鎖屏的文章,是密碼鎖屏,可以參照: 關於如何在App後臺啟動等問題,該篇就不再贅述,之專注於介紹核心的實現部分。原始碼在Github上可以獲取。 實現思路 手勢鎖屏是一個3*3的9宮格介面,將每一個宮格用一個Button表示,然後給每一個button附上一

    html5 canvas實現圖片自動滑動切換

    轉自:http://blog.csdn.net/iamke1987/article/details/9886707 圖片自動滑動效果很多網站都要用,最近在學html5就拿這個練練手,發現用canvas實現起來其實很簡單。程式碼比較粗糙,有很多改進的地方,不過還是先記錄一

    Java實現Web伺服器

      摘要:WWW的工作基於客戶機/伺服器計算模型,由Web 瀏覽器(客戶機)和Web伺服器(伺服器)構成,兩者之間採用超文字傳送協議(HTTP)進行通訊,HTTP協議的作用原理包括四個步驟:連線,請求,應答。根據上述HTTP協議的作用原理,本文實現了GET請求的Web伺服器程式的方法

    一個 C++ 實現的快速無佇列

    在程序間傳遞資料很煩人,真心煩人。一步做錯,資料就會損壞。(相較於其他讀寫方式)即使資料排列正確,也更易出錯。 一如既往的,有兩種方式處理這個問題:簡單的方式、麻煩的方式。 簡單的方式 使用你使用平臺提供的鎖(互斥、臨界區域,或等效)。這從概念上不難理解,使用上更簡單。你無需擔心排列問題,庫

    Android 手勢(包括一次、二次設定密碼)

    最近看到手勢解鎖功能,網上有一些大牛寫了很多原始碼,不過功能或多或少對自己的專案有些不同,琢磨著自己也寫一個,技術還不到家,有些東西是參照網上的demo 主要自定義View如下: package com.example.androidgesture; //

    利用JS 事件 與 Cnavas繪圖 以及 H5 快取寫的一個手勢(一)

    之前參加360前端實習生 星計劃時,遇到一個任務,就是利用H5 localStorage實現密碼的存入和獲取。當時還沒有學canvas 繪圖,感覺利用原生JS和CSS實現比較複雜;這次剛好看了JS高程的Canvas繪圖,所以正好可以理論與實踐結合一下,試著做了一

    Appium模擬滑動軌跡(如手勢

    final TouchAction gesture = new TouchAction(driver).press(startX, stratY) .moveTo(startX, stratY + height) .moveTo(s

    android自定義手勢View

       有時候為了程式的安全性,我們經常要採取一些安全措施,就像我們常用的支付寶那樣,隔一定的時間再回到應用程式時會讓使用者利用手勢去解鎖應用程式,最近由於專案需求,也要求做這樣一個功能,當用戶切出本應用程式15分鐘後回來,讓使用者手勢解鎖,整個需求的難點就在如何實現這個手勢

    canvas實現圍繞旋轉動畫

    使用canvas的convas來實現圍繞旋轉動畫,外圈順時針,裡層逆時針 html檔案 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8">