记录--怎么写一个可以鼠标控制旋转的div?
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
说在前面
鼠标控制元素旋转在现在也是一个很常见的功能,让我们从实现div元素的旋转控制开始来了解元素旋转的具体原理和实现方法吧。
效果展示
体验地址
实现步骤
画一个div
首先我们需要先画一个div,并在它上方加上旋转图标,我们可以通过这个图标来对div进行旋转,具体代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./index.css" />
</head>
<body>
<div class="container">
<div class="rotate-div">
<div class="rotate-icon">↻</div>
</div>
</div>
</body>
<script src="./index.js"></script>
</html>
加点css
将div设置为红色背景的方块,调整旋转图标的位置,具体代码如下:
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
} .rotate-div {
position: relative;
width: 200px;
height: 200px;
background-color: red;
transform-origin: center center;
} .rotate-icon {
position: absolute;
top: -50px; /* 调整图标的位置 */
left: 50%;
transform: translateX(-50%);
font-size: 20px;
cursor: pointer;
}
效果如下:
完成鼠标拖拽旋转功能
鼠标在旋转图标按下的时候,我们需要监听鼠标移动事件,根据鼠标移动位置和初始点击位置的相对角度来计算方块旋转的角度。
1、获取方块和旋转图标元素对象
首先我们要先获取方块和旋转图标元素对象,便于后续事件监听和元素操作。
const rotateDiv = document.querySelector(".rotate-div");
const rotateIcon = document.querySelector(".rotate-icon");
返回值类型:TextRectangle对象,每个矩形具有四个整数性质( 上, 右 , 下,和左 )表示的坐标的矩形,以像素为单位。
rectObject.top:元素上边到视窗上边的距离;
rectObject.right:元素右边到视窗左边的距离;
rectObject.bottom:元素下边到视窗上边的距离;
rectObject.left:元素左边到视窗左边的距离;
我们记录下方块的初始中心点:
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
(2)计算旋转角度
Math.atan2()
Math.atan2()
返回从原点 (0,0) 到 (x,y) 点的线段与 x 轴正方向之间的平面角度 (弧度值),也就是 Math.atan2(y,x)
Math.atan2(y, x)
atan2
方法返回一个 -pi 到 pi 之间的数值,表示点 (x, y) 对应的偏移角度。这是一个逆时针角度,以弧度为单位,正 X 轴和点 (x, y) 与原点连线 之间。注意此函数接受的参数:先传递 y 坐标,然后是 x 坐标。
atan2
接受单独的 x 和 y 参数,而 atan
接受两个参数的比值。
由于 atan2
是 Math
的静态方法,所以应该像这样使用:Math.atan2()
,而不是作为你创建的 Math
实例的方法。
function getAngle(centerX, centerY, mouseX, mouseY) {
return Math.atan2(mouseY - centerY, mouseX - centerX) * (180 / Math.PI);
}
使用当前鼠标位置相对角度减去鼠标初始点击点的相对角度即可得到鼠标旋转的角度。
startingMouseAngle = getAngle(centerX, centerY, event.clientX, event.clientY);
const deltaMouseAngle = currentMouseAngle - startingMouseAngle;
(3)旋转角度简化
方块的最大旋转角度为360度,所以我们对角度进行取模,保持旋转角度在360度以内即可。
function normalizeRotation(rotation) {
if (rotation >= 0) {
return rotation % 360;
} else {
return (rotation % 360) + 360;
}
}
(4)给方块设置旋转角度
rotateDiv.style.transform = `rotate(${newRotation}deg)`;
3、移除旋转逻辑
鼠标抬起的时候我们应该将旋转逻辑给移除,及将鼠标移动和抬起事件移除。
function stopSpin() {
window.removeEventListener("mousemove", spin);
window.removeEventListener("mouseup", stopSpin);
}
4、完整代码
完整的JavaScrip代码如下:
const rotateDiv = document.querySelector(".rotate-div");
const rotateIcon = document.querySelector(".rotate-icon"); let startingMouseAngle = 0;
let startingRotation = 0; rotateIcon.addEventListener("selectstart", function (event) {
event.preventDefault();
});
rotateIcon.addEventListener("mousedown", function (event) {
const rect = rotateDiv.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
startingMouseAngle = getAngle(centerX, centerY, event.clientX, event.clientY);
startingRotation = getCurrentRotation(); window.addEventListener("mousemove", spin);
window.addEventListener("mouseup", stopSpin);
}); function stopSpin() {
window.removeEventListener("mousemove", spin);
window.removeEventListener("mouseup", stopSpin);
} function spin(event) {
const rect = rotateDiv.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const currentMouseAngle = getAngle(
centerX,
centerY,
event.clientX,
event.clientY
);
const deltaMouseAngle = currentMouseAngle - startingMouseAngle;
let newRotation = startingRotation + deltaMouseAngle;
newRotation = normalizeRotation(newRotation);
rotateDiv.style.transform = `rotate(${newRotation}deg)`;
} function normalizeRotation(rotation) {
if (rotation >= 0) {
return rotation % 360;
} else {
return (rotation % 360) + 360;
}
} function getAngle(centerX, centerY, mouseX, mouseY) {
return Math.atan2(mouseY - centerY, mouseX - centerX) * (180 / Math.PI);
} function getCurrentRotation() {
const transformStyle = window
.getComputedStyle(rotateDiv)
.getPropertyValue("transform");
const matrix = new DOMMatrixReadOnly(transformStyle);
const angle = Math.acos(matrix.a) * (180 / Math.PI);
return matrix.b < 0 ? -angle : angle;
}
本文转载于:
https://juejin.cn/post/7290410631655292969
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
记录--怎么写一个可以鼠标控制旋转的div?的更多相关文章
- Linux usb子系统(一) _写一个usb鼠标驱动
USB总线是一种典型的热插拔的总线标准,由于其优异的性能几乎成为了当下大小设备中的标配. USB的驱动可以分为3类:SoC的USB控制器的驱动,主机端USB设备的驱动,设备上的USB Gadget驱动 ...
- golang 裸写一个pool池控制协程的大小
这几天深入的研究了一下golang 的协程,读了一个好文 http://mp.weixin.qq.com/s?__biz=MjM5OTcxMzE0MQ==&mid=2653369770& ...
- 在vue中写一个跟着鼠标跑的div,div里面动态显示数据
1.div应该放在body里面,这是我放在body中的一个div里面的div <!-- 信息查看层 --> <div class="floatDiv" :styl ...
- [python] 1、python鼠标点击、移动事件应用——写一个自动下载百度音乐的程序
1.问题描述: 最近百度总爱做一些破坏用户信任度的事——文库金币变券.网盘限速,吓得我赶紧想办法把存在百度云音乐中的歌曲下载到本地. http://yinyueyun.baidu.com/ 可问题是云 ...
- caffe 入门实例2 如何写一个模型
占坑,记录如何写一个基于lenet5的模型,并进行测试.
- OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11627508.html 前言: 因为接下来的项目需求是要读取多个3D模型,并且移动拼接,那么我 ...
- THREE.js代码备份——webgl - geometry - dynamic(模拟海浪,通过时间(毫秒)来控制平面点的运动模拟海浪,鼠标控制写在另外的js中)
HTML: <!DOCTYPE html> <html lang="en"> <head> <title>three.js webg ...
- 用js写一个鼠标坐标实例
HTML代码 写一个div来作为鼠标区域 div中写一个span显示坐标信息 <body> <div id=""> <span></spa ...
- 基于meanshift的手势跟踪与电脑鼠标控制(手势交互系统)
基于meanshift的手势跟踪与电脑鼠标控制(手势交互系统) zouxy09@qq.com http://blog.csdn.net/zouxy09 一年多前开始接触计算机视觉这个领域的时候,年幼无 ...
- (转)如何基于FFMPEG和SDL写一个少于1000行代码的视频播放器
原文地址:http://www.dranger.com/ffmpeg/ FFMPEG是一个很好的库,可以用来创建视频应用或者生成特定的工具.FFMPEG几乎为你把所有的繁重工作都做了,比如解码.编码. ...
随机推荐
- MySQL百万级数据大分页查询优化的实现
前言:在数据库开发过程中我们经常会使用分页,核心技术是使用用limit start, count分页语句进行数据的读取. 一.MySQL分页起点越大查询速度越慢 直接用limit start, cou ...
- Python xpath语法与 lxml 模块
XPath 语法 XPath 使用路径表达式来选取 XML 文档中的节点或节点集.节点是通过沿着路径 (path) 或者步 (steps) 来选取的. XML 实例文档 我们将在下面的例子中使用这个 ...
- SP28304 ADATEAMS - Ada and Teams 题解
题目传送门 前置知识 乘法逆元 | 排列组合 解法 简单的排列组合.从 \(n\) 个学校中选出 \(a\) 个学校,共有 \(\dbinom{n}{a}\) 种不同的方案数.选出的 \(a\) 个学 ...
- Nginx实战-公网LB限流配置等
前提: Nginx要实现根据ip地址进行限流与不限流的区分需要通过源码包安装GeoIP模块 找到与yum安装版本相同的源码包,通过configure进行安装 ./configure --prefix= ...
- UML类图入门实战
介绍 UML--Unified modeling language UML (统一建模语言),是一种用于软件系统分析和设计的语言工具,它用于帮助软件开发人员进行思考和记录思路的结果. UML 本身是一 ...
- 启动HDFS伪分布式环境时报权限错误
问题描述 操作系统:Ubuntu18.04 LTS HDFS版本:hadoop-3.2.3 普通用户登录,参照官方文档在单机上安装伪分布式环境时,启动HDFS报权限错误. 具体报错信息如下: $ ./ ...
- RK3568开发笔记(八):开发板烧写buildroot固件(支持hdmi屏),搭建Qt交叉编译开发环境,编译一个Demo,目标板运行Demo测试
前言 前面发现开发板用ubuntu固件发现空间不够,本篇使用buildroot固件,来实现目标板运行qt界面应用. 烧写buildroot固件 这部分更详细的参照<RK3568开发笔 ...
- 程序员应具备的PS基本技能(三):程序员使用PSD源文件切图
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- 网络通信部分之bs/cs架构,网络概念,osi七层网络模型,TCP/UDP协议---day27
1.网络开发的两大架构c/s,b/s # ### 1.网络开发的两大架构 a文件 -> b文件 借助c文件 a文件和b文件进行数据交流,借助c文件中转数据 a文件把数据放在c文件中,b文件从c文 ...
- Python函数每日一讲 - 简洁快速学会globals()函数
引言 在 Python 中,globals() 函数是一个强大的工具,它允许您访问全局命名空间中的所有变量和函数.本文将深入探讨 globals() 函数的语法.用法以及实际应用场景,帮助大家更好地理 ...