vue 手势解锁功能

效果

实现

<script setup lang="ts">
const canvasRef = ref<HTMLCanvasElement>()
const ctx = ref<CanvasRenderingContext2D | null>(null)
const width = px2px(600)
const height = px2px(700)
const radius = ref(px2px(50))const init = () => {const canvas = canvasRef.valueif (!canvas) returncanvas.width = widthcanvas.height = heightctx.value = canvas.getContext('2d')render()}
onMounted(init)// 圆
type CircleType = { x: number; y: number; n: number }
const circlePointList = ref<CircleType[]>([])
const circleChooseList = ref<CircleType[]>([])
const circleSolidWidth = px2px(5)
const drawCircle = (x: number, y: number, r = radius.value) => {// 画圆const c = ctx.valueif (!c) returnc.strokeStyle = '#CFE6FF'c.lineWidth = circleSolidWidthc.beginPath()c.arc(x, y, r, 0, 2 * Math.PI, true)c.closePath()c.stroke()
}
const renderCircleList = () => {const c = ctx.valueif (!c) returnc.clearRect(0, 0, width, height)const line_num = 3const row_num = 3const r = radius.valueconst rTotalLen = r * 2 * line_num// 算x的偏移量const paddingX = px2px(50)const w = width - paddingX * 2const marginX = (w - rTotalLen) / (line_num - 1)const offsetX = (w - marginX * (line_num - 1) - rTotalLen) / 2// 算y的偏移量const paddingY = px2px(50)const h = height - paddingY * 2const marginY = (h - r * 2 * row_num) / (row_num - 1)const offsetY = (h - marginY * (row_num - 1) - r * 2 * row_num) / 2// 循环画for (let i = 0; i < line_num; i++) {for (let j = 0; j < row_num; j++) {const x = r + j * 2 * r + marginX * j + offsetX + paddingXconst y = r + i * 2 * r + marginY * i + offsetY + paddingYdrawCircle(x, y)circlePointList.value.push({ x, y, n: circlePointList.value.length + 1 })}}
}
const drawChooseCircle = (x: number, y: number, r = radius.value, r2 = px2px(8)) => {const c = ctx.valueif (!c) returnc.strokeStyle = '#CFE6FF'c.lineWidth = circleSolidWidthc.beginPath()c.arc(x, y, r, 0, 2 * Math.PI, true)c.closePath()c.stroke()c.beginPath()c.arc(x, y, r2, 0, 2 * Math.PI, false)c.closePath()c.fillStyle = '#CFE6FF'c.fill()c.stroke()
}
const renderChooseCircle = () => {const list = circleChooseList.valuefor (let i = 0; i < list.length; i++) {const { x, y } = list[i]drawChooseCircle(x, y)}
}
const getIsChooseCircleByPoint = (x: number, y: number): { active: boolean; circle: CircleType | null } => {const list = circlePointList.valuefor (let i = 0; i < list.length; i++) {const { x: x1, y: y1 } = list[i]const r = radius.valueconst leftIs = x > x1 - r - circleSolidWidthconst rightIs = x < x1 + r + circleSolidWidthconst topIs = y > y1 - r - circleSolidWidthconst bottomIs = y < y1 + r + circleSolidWidthif (leftIs && rightIs && topIs && bottomIs) return { active: true, circle: list[i] }}return { active: false, circle: null }
}
const addCircleChoose = (c: CircleType) => {const list = circleChooseList.valueconst o = list.find((item) => item.n === c.n)if (o) returnlist.push(c)
}// 线
const drawLine = (x1: number, y1: number, x2: number, y2: number) => {const c = ctx.valueif (!c) returnc.beginPath()c.strokeStyle = '#CFE6FF'c.lineWidth = px2px(3)c.lineCap = 'round'c.moveTo(x1, y1)c.lineTo(x2, y2)c.stroke()c.closePath()
}
const renderChooseLine = () => {const list = circleChooseList.valueif (list.length < 2) returnfor (let i = 1; i < list.length; i++) {drawLine(list[i - 1].x, list[i - 1].y, list[i].x, list[i].y)}
}// 渲染
const render = () => {renderCircleList()renderChooseCircle()renderChooseLine()
}
const reset = () => {renderCircleList()circleChooseList.value = []pointList.value = []
}// 事件
const pointList = ref<{ x: number; y: number }[]>([])
const getPoint = (touch: Touch) => {const canvas = canvasRef.value// 这种方式tranform时,获取的坐标是错误的// const offsetLeft = canvas?.offsetLeft || 0// const offsetTop = canvas?.offsetTop || 0if(!canvas) return { x: 0, y: 0 }const rect = canvas.getBoundingClientRect()const offsetLeft = rect.xconst offsetTop = rect.yreturn { x: touch.clientX - offsetLeft, y: touch.clientY - offsetTop }
}
const touchstart = (e: TouchEvent) => {const touch = e.touches[0]const p = getPoint(touch)pointList.value.push(p)const o = getIsChooseCircleByPoint(p.x, p.y)if (o.active && o.circle) addCircleChoose(o.circle)
}
const touchmove = (e: TouchEvent) => {const touch = e.touches[0]const p = getPoint(touch)pointList.value.push(p)const o = getIsChooseCircleByPoint(p.x, p.y)if (o.active && o.circle) addCircleChoose(o.circle)render()const p0 = circleChooseList.value[circleChooseList.value.length - 1]if (!p0) returndrawLine(p0.x, p0.y, p.x, p.y)
}
const touchend = () => {reset()
}
</script><template><div class="flex flex-center flex-column"><BaseHead title="test"></BaseHead><h1>vue手势解锁功能</h1><canvas class="canvas" ref="canvasRef" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"></canvas></div>
</template><style lang="scss" scoped>
.page{width: 100vw;height: 100vh;box-sizing: border-box;overflow: hidden;
}
.canvas {position: fixed;top: 400px;left: 50%;transform: translateX(-50%);background-color: #ccc;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/487609.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java字符集【ASCII,GBK,Unicode】

1.常见字符集 1.标准ASCII字符集 美国信息交换标准代码&#xff0c;包括了英文、符号等。 标准ASCII使用1个字节存储一个字符&#xff0c;首位是0&#xff0c;总共可表示128个字符&#xff0c;对美国人来说完全够用。 2.GBK&#xff08;汉字内码扩展规范&#xff0c;国标&#…

【GB28181】wvp-gb28181-Pro 运行错误汇总避坑大全(持续更新)

快捷查找 1、【问题】终端控制台打印的日志乱码 1、【问题】终端控制台打印的日志乱码 【解决】 由于windows系统默认编码是gbk,导致jar包在windows系统运行中文会导致乱码 控制台日志乱码&#xff1a; 打开cmd命令框&#xff0c;输入以下命令 chcp 65001 更改cmd的编码为UTF-8…

反序列化 [NPUCTF2020]ReadlezPHP1

打开题目 直接查看源代码 打开源代码发现了个./time.php?source 访问一下 审计代码&#xff1a; 现存在反序列化语句&#xff1a;$ppp unserialize($_GET["data"]);和执行漏洞&#xff1a;echo $b($a); 发现在__destruct()方法里面有 echo $b($a); 这个是php的…

Vue3项目结构分析

node_modules: 是项目npm install下载的node依赖库。 public&#xff1a; favicon.ico: 网页图标logo图片。index.html: 入口html。是一个基础的html页面&#xff0c;其中进行网页最基础的设置&#xff0c;并且设置了id为app的div盒子。该页面即为Vue单页面应用的基础页面。后…

基于Springboot实现课程评分系统设计和实现

基于java Springboot实现课程评分系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取源码…

大数据-数据可视化-环境部署vue+echarts+显示案例

文章目录 一、安装node.js1 打开火狐浏览器,下载Node.js2 进行解压3 配置环境变量4 配置生效二、安装vue脚手架1 下载vue脚手架,耐心等待。三、创建vue项目并启动1 创建2 启动四、下载echarts.js与axios.js到本地。五、图表显示demo【以下所有操作均在centos上进行】 一、安…

【Linux网络】网络编程套接字(TCP)

目录 地址转换函数 字符串IP转整数IP 整数IP转字符串IP 关于inet_ntoa 简单的单执行流TCP网络程序 TCP socket API 详解及封装TCP socket 服务端创建套接字 服务端绑定 服务端监听 服务端获取连接 服务端处理请求 客户端创建套接字 客户端连接服务器 客户端…

Web3之光:揭秘数字创新的未来

随着数字化时代的深入发展&#xff0c;Web3正以其独特的技术和理念&#xff0c;为我们打开数字创新的崭新视角。作为数字化时代的新兴力量&#xff0c;Web3将深刻影响着我们的生活、工作和社会。本文将揭秘Web3的奥秘&#xff0c;探讨其在数字创新领域的前景和潜力。 1. 重新定…

Day22_JDK新特性(Lambda表达式,Optional类,StreamAPI,方法引用与构造器引用,java9-17新特性)

文章目录 Day22 JDK新特性学习目标1 Lambda表达式1.1 函数式编程思想1.2 函数接口的概念1.3 Java8之前的函数式接口1.4 Lambda表达式语法1、标准格式演示2、Lambda表达式的简化 1.5 Java8之后引入的函数式接口**1、消费型接口****2、供给型接口****3、判断型接口****4、功能型接…

浅析SpringBoot框架常见未授权访问漏洞

文章目录 前言Swagger未授权访问RESTful API 设计风格swagger-ui 未授权访问swagger 接口批量探测 Springboot Actuator未授权访问数据利用未授权访问防御手段漏洞自动化检测工具 CVE-2022-22947 RCE漏洞原理分析与复现漏洞自动化利用工具 其他常见未授权访问Druid未授权访问漏…

怎样通过本地电脑搭建SFTP服务器,并实现公网访问?

本地电脑搭建SFTP服务器&#xff0c;并实现公网访问 文章目录 本地电脑搭建SFTP服务器&#xff0c;并实现公网访问1. 搭建SFTP服务器1.1 下载 freesshd 服务器软件1.3 启动SFTP服务1.4 添加用户1.5 保存所有配置 2. 安装SFTP客户端FileZilla测试2.1 配置一个本地SFTP站点2.2 内…

Linux Android USB gadget(从设备驱动)

Linux Android USB gadget 一:Linux usb gadget 与 Android Composite Gadget二:原生方式和Android方式如何配置函数调用逻辑内核配置原生驱动android驱动三:mass_storage配置虚拟化U盘四:遍历usb设备五:adb usb判断usb设备为adb获取adb配置信息adb设备序列号发送与接收《Linux…