h5使用canvas画布实现手势解锁

前言

最近做的一个app项目使用的 apicloud 来实现跨平台开发,现在需要为这个 app 添加手势(九宫格)解锁的功能,apicloud 已经有一些第三方的原生实现的手势解锁插件,因为是原生的性能也比较好,调用也比较方便,但是都不能对它们的样式做修改,所以就打算自己来实现这个功能。这篇文章将实现过程整理分享出来,希望有需要的可以了解。分享出来的代码只实现了最基本的 设置密码功能解锁功能比较密码 的功能等,一些高级功能例如:不能限制一个点最多经过多少次、限制用户设置密码的长度。

手势解锁

通过手指将屏幕上的九个点依次连接起来形成一个图案,所以叫图案解锁。如上图每一个解锁圆圈后面其实都是一个数字,每次比较的并不是是用户画出来的图案,而是每次手指经过图案时串联起来的圆圈下的数字组成的密码字符串,本质上我们比较的还是字符串的密码,只不过站在用户的角度看是绘制出来的图案。图案的记忆远比数字字符串记的牢固。

实现步骤

绘制密码盘

密码盘的绘制比较简单,唯一需要注意需要通过动态计算使九个点围成的正方式始终在屏幕的中间位置,在手机上还需要减去状态栏的高度。

var width = $(document).width();
var height = $(document).height() - 40; //减去手机状态栏的高度

//九宫格其实就是九个点,9个点的坐标对象
var lockCicle = {
    x: 0, //x坐标
    y: 0, //y坐标
    color: "#999999",
    state: "1" //状态当前点是否已经被链接过
};

var offset = (width - height) / 2; //计算偏移量
var arr = []; //九个点的坐标数组

//计算九个点坐标的方法
for (var i = 1; i <= 3; i++) {
    //每一行
    for (var j = 1; j <= 3; j++) {
        //每一行的每一个
        var lockCicle = {};
        //横屏
        if (offset > 0) {
            lockCicle.x = (height / 4) * j + Math.abs(offset);
            lockCicle.y = (height / 4) * i;
            lockCicle.state = 0;
            //竖屏
        } else {
            lockCicle.x = (width / 4) * j;
            lockCicle.y = (width / 4) * i + Math.abs(offset);
            lockCicle.state = 0;
        }
        arr.push(lockCicle);
    }
}

//初始化界面的方法
function init() {
    ctx.clearRect(0, 0, width, height); //清空画布
    pointerArr = []; //清楚绘制路径
    for (var i = 0; i < arr.length; i++) {
        arr[i].state = 0; //清除绘制状态
        drawPointer(i);
    }
}

//绘制九宫格解锁界面
function drawPointer(i) {
    ctx.save();
    var radius = 0;
    if (hastouch) {
        radius = width / 12;
    } else {
        radius = 24;
    }
    var _fillStyle = "#dd514c";
    var _strokeStyle = "#dd514c";
    //不同状态显示不同颜色
    if (arr[i].state == 1) {
        _strokeStyle = "#1bd6c5";
    }
    //绘制原点
    ctx.beginPath();
    ctx.fillStyle = _fillStyle;
    ctx.arc(arr[i].x, arr[i].y, 6, 0, Math.PI * 2, false);
    ctx.fill();
    ctx.closePath();
    //绘制圆圈
    ctx.beginPath();
    ctx.strokeStyle = _strokeStyle;
    ctx.lineWidth = 0.3;
    ctx.lineCap = "round";
    ctx.lineJoin = "round";
    ctx.arc(arr[i].x, arr[i].y, radius, 0, Math.PI * 2, false);
    ctx.stroke();
    ctx.closePath();
    ctx.restore();
}

//初始化界面
init();

绘制连线

绘制连线的方法

var pointerArr = []; //连接线点的坐标数组
var startX, startY; //线条起始点
var puts = []; //经过的九个点的数组
var currentPointer; //当前点是否已经连接
var pwd = []; //密码
var confirmPwd = []; //确认密码
var unlockFlag = false; //是否解锁的标志

/**
 ** 绘制链接线的方法,将坐标数组中的点绘制在canvas画布中
 **/
function drawLinePointer(x, y, flag) {
    ctx.clearRect(0, 0, width, height);
    ctx.save();
    ctx.beginPath();
    ctx.strokeStyle = "#1bd6c5";
    ctx.lineWidth = 5;
    ctx.lineCap = "round";
    ctx.lineJoin = "round";
    for (var i = 0; i < pointerArr.length; i++) {
        if (i == 0) {
            ctx.moveTo(pointerArr[i].x, pointerArr[i].y);
        } else {
            ctx.lineTo(pointerArr[i].x, pointerArr[i].y);
        }
    }
    ctx.stroke();
    ctx.closePath();
    ctx.restore();
    for (var i = 0; i < arr.length; i++) {
        drawPointer(i); //绘制圆圈和原点
        if (ctx.isPointInPath(x, y) && currentPointer != i) {
            //判断鼠标点击是否在圆中
            pointerArr.push({
                x: arr[i].x,
                y: arr[i].y
            });
            currentPointer = i;
            puts.push(i + 1);
            startX = arr[i].x;
            startY = arr[i].y;
            arr[i].state = 1;
        }
    }
    if (flag) {
        ctx.save();
        ctx.beginPath();
        ctx.globalCompositeOperation = "destination-over";
        ctx.strokeStyle = "#e2e0e0";
        ctx.lineWidth = 5;
        ctx.lineCap = "round";
        ctx.lineJoin = "round";
        ctx.moveTo(startX, startY);
        ctx.lineTo(x, y);
        ctx.stroke();
        ctx.beginPath();
        ctx.restore();
    }
}

h5使用canvas画布实现手势解锁

扫一扫手机访问