记录--怎么写一个可以鼠标控制旋转的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几乎为你把所有的繁重工作都做了,比如解码.编码. ...
随机推荐
- JS leetcode 寻找旋转排序数组中的最小值 题解分析,你不得不了解的二分法
壹 ❀ 引 堕落了一天,那么接着来刷leetcode,今天做的一题不算复杂,题目来自leetcode153. 寻找旋转排序数组中的最小值,题目描述如下: 假设按照升序排序的数组在预先未知的某个点上进行 ...
- Python中Try/Except/else/final语句
python中的try/except/else/finally语句 与其他语言相同,在python中,try/except语句主要是用于处理程序正常执行过程中出现的一些异常情况,如语法错误(pyt ...
- Linux进程的创建与销毁
Linux操作系统是一种多任务.多用户的操作系统,这意味着它可以同时运行多个进程,每个进程都可以执行不同的任务. 在本文中,我们将介绍如何在Linux系统中创建和销毁进程. 进程的创建 在Linux系 ...
- 升级 vcpkg 遇到的一些坑
项目上有个需求要用到 wil 库,于是打开 cmd 输入: vcpkg install wil:x86-windows-static 等了很久,一直卡在配置命令 连续试了好几遍,还是不行,安装其他的静 ...
- windbg 分析 32 位进程的 64 位转储文件
场景: x86 的项目在 x64 的 windows 机器上运行时出现未响应的情况,使用任务管理器创建该进程的转储文件 因为项目是 32 位的,所以使用 x86 的 windbg 来调试 dmp 文件 ...
- 使用SecScanC2构建P2P去中心化网络实现反溯源
个人博客: xzajyjs.cn 前言 这款工具是为了帮助安全研究人员在渗透测试过程中防止扫描被封禁.保护自己免溯源的一种新思路.其利用到了区块链中的p2p点对点去中心化技术构建以来构建代理池. 工具 ...
- 硬件开发笔记(八): 硬件开发基本流程,制作一个USB转RS232的模块(七):创建基础DIP元器件(晶振)封装并关联原理图元器件
前言 有了原理图,可以设计硬件PCB,在设计PCB之间还有一个协同优先动作,就是映射封装,原理图库的元器件我们是自己设计的.为了更好的表述封装设计过程,本文描述了创建晶振封装(DIP),将原理图的 ...
- 基于kubeadm部署k8s1.80.0
k8s搭建 硬件要求 测试环境 # master 2核 4G 20G # node 4核 8G 40G 生产环境 # master 8核 16G 100G # node 16核 64G 500G 方式 ...
- django之manage.py migrate无效的问题
问题 已有的model,迁移之后,想重新设置字段,于是将migrations文件夹中除__init__.py之外其他文件都删掉,并且把数据库中的表删除,再次执行以下步骤python manage.py ...
- Hibernate-Validator扩展之自定义注解
一.Hibernate-Validator介绍 Hibernate-Validator框架提供了一系列的注解去校验字段是否符合预期,如@NotNull注解可以校验字段是否为null,如果为null ...
