1. 程式人生 > >微信小程式----手勢鎖詳解

微信小程式----手勢鎖詳解

設計思路流程圖

這裡寫圖片描述

1、全域性常量

constructor(page,opts){
   // 初始化全域性常量資料
   this.page = page;
   this.width = opts.width || 300;
   this.height = opts.height || 300;
   this.canvasId = opts.canvasId || 'lock';
   this.type = opts.type || 3;
   this.cleColor = opts.cleColor || 'rgba(0,136,204,1)';
   this.size = this
.width / this.type / 2;//座標點之間的半間距 this.R = this.size / 2;//外圓半徑 this.r = this.size / 4;//內圓半徑 // 判斷是否在快取中存在密碼,如果存在,直接進行第二步驟:解碼,如果不存在,進行初始化,設定密碼 this.pswObj = wx.getStorageSync('password') ? { step: 2, password: JSON.parse(wx.getStorageSync('password')) } : { step: 0 }; // 啟動手勢鎖初始化 this
.init(); }

2、全域性變數

init(){
    const _this = this;

    // 定義全域性變數,標記start,手勢鎖的每個座標的中心點陣列,記錄選中陣列
    _this.flag = false;
    _this.locationArr = [];
    _this.lastPoint = [];
    _this.restPoint = [];

    // 設定canvas的寬高
    _this.page.setData({
      width : _this.width,
      height : _this.height
}); this.ctx = wx.createCanvasContext(this.canvasId, this); // 初始化中心座標陣列 this.location(); // 初始化繪製圖形圓 this.drawPo(); // 初始化繫結事件 this.bindEvent(); }

3、初始化座標陣列locationArr 和restPoint

location(){
    // 計算座標的x,y座標,同時記錄當前位置代表的數
    let count = 0,arr = [],arr0 = [];
    for(let i = 0; i < this.type; i++){
      for(let j = 0 ; j < this.type; j++){
        count++;
        arr.push({
          x: this.size * ((j + 1) * 2 - 1),//奇數個座標間半間距
          y: this.size * ((i + 1) * 2 - 1),//奇數個座標間半間距
          count: count//每個座標代表的數
        });
        arr0.push({
          x: this.size * ((j + 1) * 2 - 1),//奇數個座標間半間距
          y: this.size * ((i + 1) * 2 - 1),//奇數個座標間半間距
          count: count//每個座標代表的數
        });
      }
    }
    this.locationArr = arr;
    this.restPoint = arr0;
  }

4、繪製手勢鎖矩陣

繪製圓函式(bool值判斷當前繪製的是空心還是實心)

drawCle(x, y, r, bool){
    // 設定邊框顏色。
    bool ? this.ctx.setStrokeStyle(this.cleColor) : this.ctx.setFillStyle(this.cleColor);; // 注意用set
    // 設定線條的寬度。
    this.ctx.setLineWidth(2); // 注意用set
    // 開始建立一個路徑,需要呼叫fill或者stroke才會使用路徑進行填充或描邊。
    this.ctx.beginPath();
    // 畫一條弧線。
    this.ctx.arc(x, y, r, 0, Math.PI * 2, true);
    // 關閉一個路徑
    this.ctx.closePath();
    // 畫出當前路徑的邊框。預設顏色色為黑色。
    bool ? this.ctx.stroke():this.ctx.fill();
    // 將之前在繪圖上下文中的描述(路徑、變形、樣式)畫到 canvas 中。
    this.ctx.draw(true);
  }

矩陣繪製

drawPo(){
    // 繪製空心圓,繪製之前,清空canvas,防止重複繪製
    this.ctx.clearRect(0, 0, this.width, this.height);
    this.locationArr.forEach(current => {
      this.drawCle(current.x, current.y, this.R, true);
    });
  }

5、觸發move時線的繪製函式

drawLine(po) {// 解鎖軌跡
    this.ctx.beginPath();
    // 線寬
    this.ctx.lineWidth = 3;
    // 起始點
    this.ctx.moveTo(this.lastPoint[0].x, this.lastPoint[0].y);
    // 中間轉換的點
    for (var i = 1; i < this.lastPoint.length; i++) {
      this.ctx.lineTo(this.lastPoint[i].x, this.lastPoint[i].y);
    }
    // 正在移動選擇的點
    if (po) { this.ctx.lineTo(po.x, po.y);}
    this.ctx.stroke();
    this.ctx.closePath();
    this.ctx.draw(true);
  }

6、獲取當前位置的座標點函式

getPosition(e) { // 獲取touch點相對於canvas的座標
 return {
   x: e.touches[0].x,
   y: e.touches[0].y
 };
}

7、觸發touchstart事件處理

_this.page.onTouchStart = function(e){
 let po = _this.getPosition(e);//獲取當前準確座標
 for (let [key,val] of _this.locationArr.entries()){//迴圈對比最近的座標
   if (Math.abs(val.x - po.x) < _this.r && Math.abs(val.y - po.y) < _this.r){
     _this.flag = true;//進入判斷,觸發touchstart事件成功
     _this.drawCle(val.x, val.y, _this.r, false);//繪製該點的實心內圓
     _this.lastPoint.push(val);//記錄該點座標到lastPoint
     _this.restPoint.splice(key,1);//刪除記錄陣列restPoint的該點座標
     break;//找到座標,跳出迴圈
   }
 }
}

8、觸發touchmove事件處理

_this.page.onTouchMove = function (e) {
  _this.flag && _this.updata(_this.getPosition(e));
}

判斷是否觸發touchstart,如果觸發,執行updata函式。

更新最後點座標函式

updata(po){
    //清空canvas
    this.ctx.clearRect(0, 0, this.width, this.height);
    //重新繪製矩陣
    for (let val of this.locationArr) {
      this.drawCle(val.x, val.y, this.R, true);
    }
    //繪製已記錄座標的實心圓
    for (let val of this.lastPoint) {
      this.drawCle(val.x, val.y, this.r ,false);
    }
    //繪製解鎖路線
    this.drawLine(po);
    //找到移動中的還未落點的精確座標
    for (let [key, val] of this.restPoint.entries()) {
      if (Math.abs(po.x - val.x) < this.r && Math.abs(po.y - val.y) < this.r) {
        this.drawCle(val.x, val.y, this.r, false);
        this.lastPoint.push(val);
        this.restPoint.splice(key, 1);
        break;
      }
    }
  }

9、觸發touchend事件處理

_this.page.onTouchEnd = function (e) {
  if(_this.flag){
    _this.flag = false;
    _this.endData();
    _this.checkPassword(_this.lastPoint);
    setTimeout(function () {
      _this.reset();
    }, 500);
  }
}

通過流程圖,可以更加清楚的認識到做一個功能需要建立的變數和函式,流程步驟更加清楚,當然也需要製作的過程進行優化。建議製作一些大的功能的時候,如果流程不清楚,最好繪製流程圖,思路清晰,開發更快,考慮更周全。

其他

遊戲列表