uniapp/vue中实现方框的移动、缩放,旋转操作(手指操作)

效果: 

<template><view class="container"><view class="rotatable" ref="view" :style="{  left: dragLeft + 'px', top: dragTop + 'px', transform: `scale(${scale}) rotate(${currentRotation}deg)`, }"src="your-image-source.jpg" @touchstart="touchStart" @touchmove="touchMove"@touchend="touchEnd" @touchcancel="touchEnd"></view></view>
</template><script>export default {data() {return {/*** 缩放的变量--开始*/scale: 1, // 初始缩放比例dragLeft: 0, // 初始位置dragTop: 0,startX: 0, // 记录第一个触点的初始位置startY: 0,prevDistance: null, // 上次触点间的距离isScaling: false, // 是否正在进行缩放/*** 缩放的变量--结束*/		/*** 旋转的变量--开始*/initialTouches: [],currentRotation: 0,/*** 旋转的变量--结束*//*** 移动的变量--开始*/// 初始位置dragLeft: 0,dragTop: 0,// 记录触摸开始时的位置startX: 0,startY: 0,// 是否正在拖动isDragging: false,/*** 移动的变量--结束*/initialTouch1: null,initialTouch2: null,prevAngle: null, // 上次触点连线与水平线的夹角isRotating: false, // 是否正在旋转initialTouches: [], // 存储初始的两个触点位置lastTouches: [], // 存储上一帧的两个触点位置initialScale: 1, // 初始缩放比例initialRotation: 0, // 初始旋转角度isScaling: false, // 是否正在缩放isRotating: false, // 是否正在旋转}},onLoad() {},methods: {touchStart(e) {if (e.touches.length === 2) {// 记录初始的两个触点位置this.initialTouches = [{ x: e.touches[0].pageX, y: e.touches[0].pageY },{ x: e.touches[1].pageX, y: e.touches[1].pageY },];// 计算初始的缩放比例和旋转角度(这里简化处理,实际可能需要更复杂的计算)this.initialScale = 1; // 实际应用中,可以通过计算两指间距与元素初始大小关系得到this.initialRotation = 0; // 可以基于两指间向量计算初始角度} else if (e.touches.length === 1) {// 防止页面滚动e.preventDefault();this.isDragging = true;// 记录起始位置this.startX = e.touches[0].clientX;this.startY = e.touches[0].clientY;}},touchMove(e) {if (e.touches.length === 2) {this.lastTouches = [{ x: e.touches[0].pageX, y: e.touches[0].pageY },{ x: e.touches[1].pageX, y: e.touches[1].pageY },];// 计算缩放const currentDistance = this.getDistance(this.lastTouches[0], this.lastTouches[1]);const initialDistance = this.getDistance(this.initialTouches[0], this.initialTouches[1]);const scale = currentDistance / initialDistance;if (Math.abs(scale - this.initialScale) > 0.1) {this.isScaling = true;this.updateScale(scale);} else {this.isScaling = false;}// 计算旋转const currentRotation = this.getRotation(this.lastTouches[0], this.lastTouches[1], this.initialTouches[0], this.initialTouches[1]);const rotationDelta = this.initialRotation - currentRotation ;if (Math.abs(rotationDelta) > 5) {this.isRotating = true;this.updateRotation(rotationDelta);} else {this.isRotating = false;}} else if (e.touches.length === 1) {if (!this.isDragging) return;e.preventDefault();// 计算新的位置let newX = this.dragLeft + (e.touches[0].clientX - this.startX);let newY = this.dragTop + (e.touches[0].clientY - this.startY);// 更新位置this.dragLeft = newX;this.dragTop = newY;// 重置起始位置this.startX = e.touches[0].clientX;this.startY = e.touches[0].clientY;}// }},touchEnd() {// 清空初始触点,以便下一次操作this.initialTouches = [];this.isDragging = false;this.isScaling = false;this.isRotating = false;this.prevAngle = null;// 触摸结束时重置状态this.isScaling = false;this.isRotating = false;this.initialTouches = [];this.lastTouches = [];},// 辅助方法getDistance(point1, point2) {return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));},getRotation(touch1, touch2, initialTouch1, initialTouch2) {// 使用向量叉乘法计算角度变化,注意根据具体场景调整计算逻辑const vector1 = [touch2.x - touch1.x, touch2.y - touch1.y];const vector2 = [initialTouch2.x - initialTouch1.x, initialTouch2.y - initialTouch1.y];return Math.atan2(vector1[0]*vector2[1] - vector1[1]*vector2[0], vector1[0]*vector2[0] + vector1[1]*vector2[1]) * (180 / Math.PI);},calculateAngle(touch1, touch2) {const dx = touch2.x - touch1.x;const dy = touch2.y - touch1.y;return Math.atan2(dy, dx) * (180 / Math.PI); // 返回角度(度)},calculateAngleDifference(startTouches, currentTouches) {// 计算两个触点间向量的角度差const angle1 = Math.atan2(startTouches[1].y - startTouches[0].y, startTouches[1].x - startTouches[0].x);const angle2 = Math.atan2(currentTouches[1].y - currentTouches[0].y, currentTouches[1].x - currentTouches[0].x);// 返回角度差(转换为度)return (angle2 - angle1) * (180 / Math.PI);},updateScale(newScale) {// 应用缩放变换,例如改变样式或更新数据绑定的变量this.scale = newScale;},updateRotation(rotationDelta) {// 应用旋转变换,累计旋转角度const newRotation = this.initialRotation + rotationDelta;this.currentRotation = newRotation;},// 计算两点之间的距离calculateDistance(touches) {const dx = touches[0].pageX - touches[1].pageX;const dy = touches[0].pageY - touches[1].pageY;return Math.sqrt(dx * dx + dy * dy);},}}
</script><style scoped lang="scss">.container {position: relative;.rotatable{position: absolute;width: 200px;height: 200px;border: 1px solid red;}}
</style>

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

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

相关文章

Lipowerline5.0 雷达电力应用软件下载使用

1.配网数据处理分析 针对配网线路点云数据&#xff0c;优化了分类算法&#xff0c;支持杆塔、导线、交跨线、建筑物、地面点和其他线路的自动分类&#xff1b;一键生成危险点报告和交跨报告&#xff1b;还能生成点云数据采集航线和自主巡检航线。 获取软件安装包联系邮箱:289…

Selenium CSS 选择器详细讲解

详细介绍 CSS 选择器 By.CSS_SELECTOR 在 Selenium 中&#xff0c;By.CSS_SELECTOR 是一种强大且灵活的定位方式。它使用 CSS 选择器语法来查找页面上的元素。CSS 选择器支持复杂的查询语法&#xff0c;可以根据元素的标签、类名、ID、属性等进行组合定位。 示例 HTML <!…

解决Java中的AssertionError异常的常用方法

解决Java中的AssertionError异常的常用方法 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将讨论在Java开发中常见的AssertionError异常&#xff0c;并…

递归的艺术:Python中5个递归函数经典问题与解析

递归&#xff0c;这门编程艺术中的魔法&#xff0c;它让复杂的问题变得简单&#xff0c;但初学者往往觉得它神秘莫测。别怕&#xff0c;今天我们就一起揭开递归的面纱&#xff0c;通过5个生动有趣的Python案例&#xff0c;让你轻松掌握递归的奥秘&#xff01; 1. 经典的阶乘问…

常用MQ消息中间件Kafka、ZeroMQ和RabbitMQ对比及RabbitMQ详解

1、概述 在现代的分布式系统和实时数据处理领域&#xff0c;消息中间件扮演着关键的角色&#xff0c;用于解决应用程序之间的通信和数据传递的挑战。在众多的消息中间件解决方案中&#xff0c;Kafka、ZeroMQ和RabbitMQ 是备受关注和广泛应用的代表性系统。它们各自具有独特的特…

CST电磁仿真软件的参数类型和含义【电磁仿真入门教程】

如果你是一位工程师或设计师&#xff0c;那你对电磁仿真软件CST Studio Suite一定不会感到陌生。CST软件可以帮助你模拟电磁场和电路行为&#xff0c;从而优化产品设计。本文将带你了解CST电磁仿真软件的一些关键参数&#xff0c;并解释其含义。CST电磁仿真软件的参数是指在使用…

安规管理:PLM安规管理、PLM安规管理新策略

安规管理&#xff1a;PLM安规管理、PLM安规管理新策略 随着科技的飞速发展&#xff0c;电子产品已经成为我们生活中不可或缺的一部分。然而&#xff0c;这些产品在给人们带来便利的同时&#xff0c;也可能带来触电、火灾、有害辐射等安全隐患。为了保护消费者的生命财产安全&am…

JavaScript全屏,监听页面是否全屏

在JavaScript中&#xff0c;直接监听浏览器是否进入全屏模式并不直接支持&#xff0c;因为全屏API主要是关于请求和退出全屏模式的&#xff0c;而没有直接的监听器可以告知页面何时进入或退出全屏模式。但是&#xff0c;你可以通过在你的代码中跟踪全屏状态的改变来模拟这个功能…

性能测试学习-执行测试脚本,监控性能指标

1、关于使用pymatlab库实现对数据表的增加&#xff0c;获取指定列操作&#xff0c;并在另一个py文件中调用 cursor游标的使用 """ 实现数据连接&#xff0c;并操作数据库&#xff0c;生成随机的用户数据 使用游标 """ import randomimport pym…

超越云端:Octopus v2端侧部署实现高效能语言模型

在人工智能领域&#xff0c;大型语言模型虽然在云端环境中展现出卓越的性能&#xff0c;但它们在隐私保护、成本控制以及对网络连接的依赖性方面存在不足。这些问题限制了AI技术在移动设备和边缘计算场景中的应用潜力。为了克服这些限制&#xff0c;研究者们一直在探索如何在设…

机器学习补充

一、数据抽样 数据预处理阶段&#xff1a;对数据集进行抽样可以帮助减少数据量&#xff0c;加快模型训练的速度/减少计算资源的消耗&#xff0c;特别是当数据集非常庞大时&#xff0c;比如设置sample_rate0.8.平衡数据集&#xff1a;通过抽样平衡正负样本&#xff0c;提升模型…

揭秘shopee、Lazada爆单秘诀:自养号补单策略大公开

在东南亚的电商跨境领域&#xff0c;Shopee和Lazada无疑占据了举足轻重的地位&#xff0c;为印地、马来、台湾、菲律宾、新加坡、泰国和越南等地的消费者提供了丰富的在线购物选择。随着电商竞争的日益激烈&#xff0c;许多商家开始探索各种有效的推广策略&#xff0c;其中&…

没有SSL证书,会造成哪些影响?

没有SSL证书&#xff0c;网站及其用户将会面临多种安全隐患和负面影响&#xff0c;主要包括但不限于以下几点&#xff1a; 1、安全警告&#xff1a;现代浏览器如谷歌Chrome会在用户尝试访问没有SSL证书的网站时显示明显的警告信息&#xff0c;如“不安全”标签&#xff0c;这会…

F407核心板小板快速入门000

1、现在实验室用的F407核心板有两个类型。都是用反客科技的板子。 一个是STM32F407ZGT6型号的FM板卡。一个是stm32F407VET6的板子FK板卡。前者是我们做工程训练大赛用到的。后者是做其他没有那么复杂的项目比如大创、电赛、机器人大赛等使用&#xff0c;板卡尺寸更小。 前者的参…

C++ 结构体对齐详解

目录 前言 一、为什么要对结构体进行对齐操作&#xff1f; 二、基本概念 三、 对齐规则 四、示例讲解 1.简单的变量对齐 2.结构体包含有结构体的对齐 结构体成员详细解析 五、使用指令改变对齐方式 __attribute__((packed)) #pragma pack(push, n) #pragma pack(pop) …

Java中如何处理XML数据?

Java中如何处理XML数据&#xff1f; 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨在Java中如何高效处理XML数据的技术和最佳实践。XML&…

Elasticsearch:赋能数据搜索与分析的利器

Elasticsearch&#xff1a;赋能数据搜索与分析的利器 在大数据的时代背景下&#xff0c;如何高效地搜索、分析和利用数据成为了企业和开发者面临的重要问题。Elasticsearch&#xff0c;作为Elastic Stack的核心组件&#xff0c;以其分布式、高扩展性和实时的搜索与分析能力&am…

【CentOS7】Linux安装Docker教程(保姆篇)

文章目录 查看是否已安装卸载&#xff08;已安装过&#xff09;docker安装友情提示 更多相关内容可查看 注&#xff1a;本篇为Centos7安装Docker&#xff0c;若为其他系统请理性参考 查看是否已安装 如果已安装&#xff0c;请卸载重新安装 docker --version这里显示已安装 …

人机的三级抽象

数学的三级抽象包括第一级抽象是数表示万物、第二级抽象是字母表征数、第三级抽象是运算规则的抽象&#xff08;如群论&#xff09;&#xff0c;在人机交互中&#xff0c;类比于数学的三级抽象&#xff0c;可以理解为&#xff1a; 第一级抽象&#xff1a;用户界面和操作的抽象化…

力扣第210题“课程表 II”

在本篇文章中&#xff0c;我们将详细解读力扣第210题“课程表 II”。通过学习本篇文章&#xff0c;读者将掌握如何使用拓扑排序来解决这一问题&#xff0c;并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释&#xff0c;以便于理解。 问题描述 力扣第210题“…