这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

说在前面

鼠标控制元素旋转在现在也是一个很常见的功能,让我们从实现div元素的旋转控制开始来了解元素旋转的具体原理和实现方法吧。

效果展示

体验地址

code.juejin.cn/pen/7290719…

实现步骤

画一个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)

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?的更多相关文章

  1. Linux usb子系统(一) _写一个usb鼠标驱动

    USB总线是一种典型的热插拔的总线标准,由于其优异的性能几乎成为了当下大小设备中的标配. USB的驱动可以分为3类:SoC的USB控制器的驱动,主机端USB设备的驱动,设备上的USB Gadget驱动 ...

  2. golang 裸写一个pool池控制协程的大小

    这几天深入的研究了一下golang 的协程,读了一个好文 http://mp.weixin.qq.com/s?__biz=MjM5OTcxMzE0MQ==&mid=2653369770& ...

  3. 在vue中写一个跟着鼠标跑的div,div里面动态显示数据

    1.div应该放在body里面,这是我放在body中的一个div里面的div <!-- 信息查看层 --> <div class="floatDiv" :styl ...

  4. [python] 1、python鼠标点击、移动事件应用——写一个自动下载百度音乐的程序

    1.问题描述: 最近百度总爱做一些破坏用户信任度的事——文库金币变券.网盘限速,吓得我赶紧想办法把存在百度云音乐中的歌曲下载到本地. http://yinyueyun.baidu.com/ 可问题是云 ...

  5. caffe 入门实例2 如何写一个模型

    占坑,记录如何写一个基于lenet5的模型,并进行测试.

  6. OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11627508.html 前言: 因为接下来的项目需求是要读取多个3D模型,并且移动拼接,那么我 ...

  7. THREE.js代码备份——webgl - geometry - dynamic(模拟海浪,通过时间(毫秒)来控制平面点的运动模拟海浪,鼠标控制写在另外的js中)

    HTML: <!DOCTYPE html> <html lang="en"> <head> <title>three.js webg ...

  8. 用js写一个鼠标坐标实例

    HTML代码 写一个div来作为鼠标区域 div中写一个span显示坐标信息 <body> <div id=""> <span></spa ...

  9. 基于meanshift的手势跟踪与电脑鼠标控制(手势交互系统)

    基于meanshift的手势跟踪与电脑鼠标控制(手势交互系统) zouxy09@qq.com http://blog.csdn.net/zouxy09 一年多前开始接触计算机视觉这个领域的时候,年幼无 ...

  10. (转)如何基于FFMPEG和SDL写一个少于1000行代码的视频播放器

    原文地址:http://www.dranger.com/ffmpeg/ FFMPEG是一个很好的库,可以用来创建视频应用或者生成特定的工具.FFMPEG几乎为你把所有的繁重工作都做了,比如解码.编码. ...

随机推荐

  1. JOISC 2022 记录

    Day1 T1 Jail 操作很类似华容道.由于这题是可以树,同时每一个人走的都是最短路,这也就意味着不会出现通过好多个人一起的挪动来匀出空间. 所以如果合法,必然存在一种方案是每一次直接将一个人挪到 ...

  2. Python中保存字典类型数据到文件

    三种方法: 1.在 Python 中使用 pickle 模块的 dump 函数将字典保存到文件中import pickle my_dict = { 'Apple': 4, 'Banana': 2, ' ...

  3. 在nginx 服务器部署vue项目

    以人人快速开发的开源项目:renren-fast-vue 为例 注:这里开始认为各位都会使用nginx 打包vue项目 npm run build 测试打包的项目是否可以运行 serve dist 可 ...

  4. 复习一下JVM内存结构

    一.程序计数器 程序计数器内存很小,可以看作是当前线程所执行字节码的行号指示器. 有了它,程序就能被正确的执行. 因为有线程切换的存在,则每个线程必须有各自独立的程序计数器,即线程私有的内存. 这里再 ...

  5. android:加载PDF几种方法汇总对比

    在安卓项目中,加载PDF文件,是一个比较常见的需求.又分为两大类, 1.加载网络PDF 2.加载一个本地静态PDF. 查阅资料,纵观网上在安卓中打开PDF的各种方式,大致可以分为以下几类, 1.直接使 ...

  6. 【Azure 应用服务】Web App Service 中的 应用程序配置(Application Setting) 怎么获取key vault中的值

    问题描述 App Service中,如何通过 Application Setting 来配置 Key Vault中的值呢? 问题解答 首先,App Service服务可以直接通过引用的方式,无需代码的 ...

  7. 【Azure 应用服务】更新镜像后并重启应用服务,部署日志始终没有出现加载新镜像成功的日志

    问题描述 在App Service中部署镜像文件,发现镜像一直没有部署,重启App Service服务也无效果. DockerFile如下: FROM crunchgeek/php-fpm:7.0 # ...

  8. Java 常用类 String的使用---测试

    1 package com.bytezero.stringclass; 2 3 import org.junit.Test; 4 5 /** 6 * 7 * 8 * 9 * @author Bytez ...

  9. Java 线程安全问题 使用同步机制讲单例模式中的懒汉式改写为线程安全的

    1 package bytezero.deadlock; 2 3 /** 4 * 使用同步机制讲单例模式中的懒汉式改写为线程安全的 5 * 6 * 7 * 8 * 9 * @author Byteze ...

  10. Redis单线程为什么如此之快

    一.概述 Redis的高并发和快简单可以归结为一下几点: 1.Redis是基于内存的: 2.Redis是单线程的: 3.Redis使用多路复用技术. 4.高效的数据结构 但具体怎么做的呢,下面来详细看 ...