canvas 实现vue 手势解锁组件

news/2025/2/23 22:01:37

1.手机锁屏九宫格解锁组件

2.代码如下

<template>
<canvas id="gesture" ref="canvas" :style="style" />
</template>

<script>
export default {
name: 'GestureLock',
props: {
chooseType: {
type: Number,
default: 3 // 3: 3*3, 4: 4*4, 5: 5*5
}
},
data() {
return {
touchedFlag: false, // 是否正在绘制
canvas: null,
ctx: null,
radius: 0, // 计算后的半径大小
style: {
width: 450,
height: 500
},
devicePixelRatio: window.devicePixelRatio || 1,
circleArr: [],
lastPoint: [],
restPoint: []
};
},
mounted() {
this.canvas = this.$refs.canvas;
this.ctx = this.canvas.getContext('2d');

this.canvas.width = this.style.width * this.devicePixelRatio;
this.canvas.height = this.style.height * this.devicePixelRatio;

this.createCircle();
this.bindEvent();
},
beforeDestroy() {
this.canvas.removeEventListener('touchstart', this.onStartHandler);
this.canvas.removeEventListener('touchmove', this.onMoveHandler);
this.canvas.removeEventListener('touchend', this.onEndHandler);
},
methods: {
drawPoint(style) {
// 初始化圆心
for (var i = 0; i < this.lastPoint.length; i++) {
this.ctx.fillStyle = style;
this.ctx.beginPath();
this.ctx.arc(
this.lastPoint[i].x,
this.lastPoint[i].y,
this.radius / 2.5,
0,
Math.PI * 2,
true
);
this.ctx.closePath();
this.ctx.fill();
}
},
drawStatusPoint(type) {
// 初始化状态线条
for (var i = 0; i < this.lastPoint.length; i++) {
this.ctx.strokeStyle = type;
this.ctx.beginPath();
this.ctx.arc(
this.lastPoint[i].x,
this.lastPoint[i].y,
this.radius,
0,
Math.PI * 2,
true
);
this.ctx.closePath();
this.ctx.stroke();
}
},
drawCircle(x, y) {
// 初始化解锁密码面板 小圆圈
this.ctx.strokeStyle = '#648F83'; // 密码的点点默认的颜色
this.ctx.lineWidth = 2;
this.ctx.beginPath();
this.ctx.arc(x, y, this.radius, 0, Math.PI * 2, true); // 画圆
this.ctx.closePath();
this.ctx.stroke();
},
drawLine(style, position) {
// style:颜色 解锁轨迹
this.ctx.beginPath();
this.ctx.strokeStyle = style;
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);
}
this.ctx.lineTo(position.x, position.y);
this.ctx.stroke();
this.ctx.closePath();
},
createCircle() {
var n = this.chooseType;
var count = 0;
this.radius = this.ctx.canvas.width / (1 + 4 * n); // 公式计算
this.lastPoint = [];
this.circleArr = [];
this.restPoint = [];
var r = this.radius;

for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
count++;
let point = {
x: j * 4 * r + 3 * r,
y: i * 4 * r + 3 * r,
index: count
};
this.circleArr.push(point);
this.restPoint.push(point);
}
}

this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);

// 画9个圆
for (let i = 0; i < this.circleArr.length; i++) {
this.drawCircle(this.circleArr[i].x, this.circleArr[i].y);
}
},
onStartHandler(e) {
e.preventDefault(); // 某些android 的 touchmove不宜触发 所以增加此行代码

// 重置图案
this.onReset();
var position = this.getPosition(e);

for (var i = 0; i < this.circleArr.length; i++) {
if (
Math.abs(position.x - this.circleArr[i].x) < this.radius &&
Math.abs(position.y - this.circleArr[i].y) < this.radius
) {
this.touchedFlag = true;
this.drawPoint(this.circleArr[i].x, this.circleArr[i].y);
this.lastPoint.push(this.circleArr[i]);
this.restPoint.splice(i, 1);
break;
}
}
},
onMoveHandler(e) {
if (this.touchedFlag) {
this.onUpdateHandler(this.getPosition(e));
}
},
onEndHandler(e) {
if (this.touchedFlag) {
this.touchedFlag = false;
this.$emit('input', this.lastPoint.map((point) => {
return point.index;
}));
// 重绘最后所有点
this.onUpdateHandler(this.lastPoint[this.lastPoint.length - 1]);
}
},
onUpdateHandler(position) {
// 核心变换方法在touchmove时候调用
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);

for (let i = 0; i < this.circleArr.length; i++) {
// 每帧先把面板画出来
this.drawCircle(this.circleArr[i].x, this.circleArr[i].y);
}

this.drawPoint('#648F83'); // 每帧花轨迹
this.drawStatusPoint('#648F83'); // 每帧花轨迹

this.drawLine('#648F83', position, this.lastPoint); // 每帧画圆心

for (let i = 0; i < this.restPoint.length; i++) {
if (
Math.abs(position.x - this.restPoint[i].x) < this.radius &&
Math.abs(position.y - this.restPoint[i].y) < this.radius
) {
this.drawPoint(this.restPoint[i].x, this.restPoint[i].y);
this.lastPoint.push(this.restPoint[i]);
this.restPoint.splice(i, 1);
break;
}
}
},
onReset() {
this.createCircle();
},
bindEvent() {
// 网页
this.canvas.addEventListener('mousedown', this.onStartHandler);
this.canvas.addEventListener('mousemove', this.onMoveHandler);
this.canvas.addEventListener('mouseup', this.onEndHandler);
// 移动端
this.canvas.addEventListener('touchstart', this.onStartHandler);
this.canvas.addEventListener('touchmove', this.onMoveHandler);
this.canvas.addEventListener('touchend', this.onEndHandler);
},
getPosition(e) {
// 获取touch点相对于canvas的坐标
var rect = e.currentTarget.getBoundingClientRect();
var position = e.touches ? {
x: (e.touches[0].clientX - rect.left) * this.devicePixelRatio,
y: (e.touches[0].clientY - rect.top) * this.devicePixelRatio
} : {
x: (e.clientX - rect.left) * this.devicePixelRatio,
y: (e.clientY - rect.top) * this.devicePixelRatio
};
return position;
}
}
};
</script>
3.组件引用
<GestureLock v-model="gestureData"></GestureLock>
data () {
return {
gestureData:[]
};
}
 
watch: {
// 按绘制的顺序输出的数组
gestureData(val) {
console.log(val);
}
},
4.结果

 

转载于:https://www.cnblogs.com/zhengao/p/10040547.html


http://www.niftyadmin.cn/n/2606769.html

相关文章

Scala - 快速学习06 - 面向对象

1- 类 1.1- 简介&#xff1a;类、方法及对象 类是用来创建对象的蓝图。Scala文件中包含的多个类之间&#xff0c;都是彼此可见的&#xff0c;不需要声明为public。创建对象定义好类以后&#xff0c;就可以使用new关键字来创建对象。字段默认为public&#xff0c;在类外部和内部…

设计模式-创建型模式-建造者模式

设计模式-创建型模式-建造者模式建造者模式即生成器模式&#xff0c;将一个复杂的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 代码如下 // 产品类 public class Product{public void doSomething(){// 业务处理} } // 抽象建造者 public abstract …

redis 系列18 事件

一.概述 Redis服务器是一个事件驱动程序&#xff0c;服务器需要处理两类事件&#xff1a;1文件事件&#xff0c;2时间事件。文件事件是关于客户端与服务器之间的通信操作。时间事件是关于服务器内部的一些定时操作。本篇还是参照"Redis设计与实现"书&#xff0c;简要…

ts学设计模式: 第一篇: 单例模式

模式定义 单例模式: 确保一个类只有一个实例, 并且提供一个全局访问的方法, 属于创建型模式。 模式结构图 代码实现 懒汉模式1. 懒汉模式中单例是在需要的时候才去创建的&#xff0c;如果单例已经创建&#xff0c;再次调用获取接口将不会重新创建新的对象&#xff0c;而是直接返…

在SpringBoot框架中使用拦截器

1.继承WebMvcConfigureAdapter类&#xff0c;覆盖其addInterceptors接口,注册我们自定义的拦截器 1 package com.eth.wallet.config;2 3 4 import com.eth.wallet.interceptor.MyInterceptor;5 import org.springframework.boot.SpringBootConfiguration;6 import org.springfr…

各种不同的词向量,在这里有整理

在这个地址&#xff1a; https://github.com/Embedding/Chinese-Word-Vectors 转载于:https://www.cnblogs.com/charlesblc/p/10073039.html

Thinking in Java 读书总结(一)

前言 之前有零散地阅读过TIJ&#xff0c;但是都是针对自己的问题去有针对性的阅读&#xff0c;没有从头梳理过Java的一些基础知识。从前段时间开始自己也开始了整体性地学习TIJ的过程&#xff0c;也从这篇博客开始把自己的一些感悟和理解总结起来&#xff0c;也希望能对大家和我…

ActiveMQ之队列和主题发布订阅实例

JMS 消息模型 JMS消息服务应用程序结构支持两种模型&#xff1a;点对点模型&#xff0c;发布者/订阅者模型。   &#xff08;1&#xff09;点对点模型(Queue) 一个生产者向一个特定的队列发布消息&#xff0c;一个消费者从这个队列中依次读取消息。 模型特点&#xff1a;只有…