vue 手势解锁功能

news/发布时间2024/5/15 7:58:09

效果

实现

<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.bcls.cn/skRf/4457.shtml

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

相关文章

探究全链路压力测试的含义与重要性

全链路压力测试是指对整个应用系统的各个环节或组件进行压力测试&#xff0c;以模拟实际生产环境中的用户负载和流量&#xff0c;评估系统在高负载条件下的性能表现。 1. 全链路压力测试的含义 全链路压力测试涉及系统的所有组件和环节&#xff0c;包括前端用户界面、应用服务器…

深入探索STM32的存储选项:片内RAM、片内Flash与SDRAM

博客&#xff1a;深入探索STM32的存储选项&#xff1a;片内RAM、片内Flash与SDRAM 在嵌入式系统设计中&#xff0c;存储管理是一个至关重要的方面&#xff0c;尤其是对于基于STM32这类强大的微控制器来说。STM32系列微控制器因其高性能、低功耗以及灵活的存储选项而广受欢迎。本…

MFC 皮肤库配置

1.创建MFC 对话框 2.添加皮肤资源 添加资源 添加头文件 关闭SDL检测 添加静态库文件 修改字符集 添加头文件 将皮肤中的ssk文件加载到初始化实例中 > 运行即可

ChatGPT 4.0 升级指南

1.ChatGPT 是什么&#xff1f; ChatGPT 是由 OpenAI 开发的一种基于人工智能的聊天机器人&#xff0c;它基于强大的语言处理模型 GPT&#xff08;Generative Pre-trained Transformer&#xff09;构建。它能够理解人类语言&#xff0c;可以为我们解决实际的问题。 1.模型规模…

uni-app nvue vue3 setup中实现加载webview,解决nvue中获取不到webview实例的问题

注意下面的方法只能在app端使用&#xff0c; let wv plus.webview.create("","custom-webview",{plusrequire:"none", uni-app: none, width: 300,height:400,top:uni.getSystemInfoSync().statusBarHeight44 }) wv.loadURL("https://ww…

2024全国水科技大会暨流域水环境治理与水生态修复论坛(六)

论坛召集人 冯慧娟 中国环境科学研究院流域中心研究员 刘 春 河北科技大学环境与工程学院院长、教授 一、会议背景 为深入贯彻“山水林田湖是一个生命共同体”的重要指示精神&#xff0c;大力实施生态优先绿色发展战略&#xff0c;积极践行人、水、自然和谐共生理念&…

Kotlin 进阶 学习 委托

1.接口委托 package com.jmj.jetpackcomposecompositionlocal.byStudy/*** 接口委托*/ interface HomeDao{fun getAllData():List<String> }interface ADao{fun getById(id:Int):String }class HomeDaoImpl:HomeDao{override fun getAllData(): List<String> {ret…

新手学习Cesium的几点建议

Cesium是当前非常火热的三维数字地球开发框架&#xff0c;很多公司基于Cesium做项目以及形成了自己的产品&#xff0c;关于Cesium的学习&#xff0c;有诸多网站、书籍、学习资料甚至培训教材&#xff0c;这里不再详细推荐&#xff0c;从学习Cesium的角度&#xff0c;资料和教程…

亿道丨三防平板丨加固平板丨为零售业提供四大优势

随着全球经济的快速发展&#xff0c;作为传统行业的零售业也迎来了绝佳的发展机遇&#xff0c;在互联网智能化的大环境下&#xff0c;越来越多的零售企业选择三防平板电脑作为工作中的电子设备。作为一种耐用的移动选项&#xff0c;三防平板带来的不仅仅是坚固的外壳。坚固耐用…

车载电子电器架构 —— 车辆模式管理

车载电子电器架构 —— 车辆模式管理 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的…

Python实战:xlsx文件的读写

Python实战&#xff1a;xlsx文件的读写 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 &#x1f448; 希望得到您的订阅和支持~ &#…

Linux进程【补充】

文章目录 进程概念task_struct 进程创建forkvfork写时拷贝 进程状态僵尸进程孤儿进程守护进程 进程地址空间是什么为什么怎么做 进程概念 进程是一个程序的执行实例或者是担当系统资源分配的实体。当一个程序运行时&#xff0c;被从硬盘加载到内存中&#xff0c;操作系统为每个…

电脑wifi丢失修复

当你打开电脑突然发现wifi功能不见了&#xff0c;可以先查看一下网卡的状态 在控制面板中找到设备管理器&#xff0c;打开就能找到网络适配器&#xff0c; 我这里是修复过的&#xff0c;wifi丢失后这里可能会显示WALN是丢失的&#xff0c;其他项显示黄色感叹号。 如何修复呢…

LaTex和Word中推荐使用的矢量图片格式

1、LaTex 推荐使用eps矢量格式。&#xff08;该格式直接放在word中不会显示&#xff0c;但是通过插入word后双击打开查看 2、Word 推荐使用svg矢量格式。该格式可以直接插入word中。 3、plt保存代码 import matplotlib.pyplot as plt# 绘制图形 x [1, 2, 3, 4, 5] y1 [1…

RandAugment(NeurIPS 2020)论文速读

paper&#xff1a;RandAugment: Practical automated data augmentation with a reduced search space third-party implementation&#xff1a;https://github.com/open-mmlab/mmpretrain/blob/main/mmpretrain/datasets/transforms/auto_augment.py 存在的问题 自动增强策…

《Docker 简易速速上手小册》第3章 Dockerfile 与镜像构建(2024 最新版)

文章目录 3.1 编写 Dockerfile3.1.1 重点基础知识3.1.2 重点案例&#xff1a;创建简单 Python 应用的 Docker 镜像3.1.3 拓展案例 1&#xff1a;Dockerfile 优化3.1.4 拓展案例 2&#xff1a;多阶段构建 3.2 构建流程深入解析3.2.1 重点基础知识3.2.2 重点案例&#xff1a;构建…

ArcgisForJS如何在线编辑ArcGIS Server发布的几何要素?

文章目录 0.引言1.ArcGIS创建几何要素2.ArcGIS Server发布几何要素3.ArcgisForJS在线编辑ArcGIS Server发布的几何要素 0.引言 ArcGIS For JS 是一种用于创建和编辑地理信息的 JavaScript 库&#xff0c;它允许用户在线编辑 ArcGIS Server 发布的几何要素。本文从ArcGIS创建几…

MATLAB环境下一维时间序列信号的欠定盲源分离方法

在酒会上会有多种声音&#xff0c;如酒杯碰撞的声音、朋友之间聊天的声音、会场中音乐的声音等&#xff0c;这些声音混叠起来使我们难以得到我们感兴趣的声音信号&#xff0c;怎样获得我们想要得到的声音信号&#xff0c;这就是盲源分离BSS研究上的最经典问题“鸡尾酒会”问题。…

sentinel整合nacos在gateway中实现限流

sentinel整合nacos在gateway中实现限流 一、应用层面完成网关整合nacos和sentinel实现限流 前沿 启动nacos与sentinel的jar的启动&#xff0c;这里不细讲 sentinel官网 https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5 sentinel 下载地址 https://github.com/…

Linux-基础知识(黑马学习笔记)

硬件和软件 我们所熟知的计算机是由&#xff1a;硬件和软件组成。 硬件&#xff1a;计算机系统中电子&#xff0c;机械和光电元件等组成的各种物理装置的总称。 软件&#xff1a;是用户和计算机硬件之间的接口和桥梁&#xff0c;用户通过软件与计算机进行交流。 而操作系统…
推荐文章