怎么写一个可以鼠标控制旋转的div?

说在前面

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

效果展示

体验地址

code.juejin.cn/pen/7290719...

实现步骤

画一个div

首先我们需要先画一个div,并在它上方加上旋转图标,我们可以通过这个图标来对div进行旋转,具体代码如下:

html 复制代码
<!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">&#x21bb;</div>
      </div>
    </div>
  </body>
  <script src="./index.js"></script>
</html>

加点css

将div设置为红色背景的方块,调整旋转图标的位置,具体代码如下:

css 复制代码
.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、获取方块和旋转图标元素对象

首先我们要先获取方块和旋转图标元素对象,便于后续事件监听和元素操作。

javascript 复制代码
const rotateDiv = document.querySelector(".rotate-div");
const rotateIcon = document.querySelector(".rotate-icon");

2、编写方块旋转逻辑

(1)获取方块中心点

getBoundingClientRect

getBoundingClientRect用于获取某个元素相对于视窗的位置集合。集合中有top, right, bottom, left等属性。

ini 复制代码
rectObject = object.getBoundingClientRect();

返回值类型:TextRectangle对象,每个矩形具有四个整数性质( 上, 右 , 下,和左 )表示的坐标的矩形,以像素为单位。

rectObject.top:元素上边到视窗上边的距离;

rectObject.right:元素右边到视窗左边的距离;

rectObject.bottom:元素下边到视窗上边的距离;

rectObject.left:元素左边到视窗左边的距离;

我们记录下方块的初始中心点:

javascript 复制代码
 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)

arduino 复制代码
Math.atan2(y, x)

y, x

atan2 方法返回一个 -pi 到 pi 之间的数值,表示点 (x, y) 对应的偏移角度。这是一个逆时针角度,以弧度为单位,正 X 轴和点 (x, y) 与原点连线 之间。注意此函数接受的参数:先传递 y 坐标,然后是 x 坐标。

atan2 接受单独的 x 和 y 参数,而 atan 接受两个参数的比值。

由于 atan2Math 的静态方法,所以应该像这样使用:Math.atan2(),而不是作为你创建的 Math 实例的方法。

javascript 复制代码
function getAngle(centerX, centerY, mouseX, mouseY) {
  return Math.atan2(mouseY - centerY, mouseX - centerX) * (180 / Math.PI);
}

使用当前鼠标位置相对角度减去鼠标初始点击点的相对角度即可得到鼠标旋转的角度。

javascript 复制代码
startingMouseAngle = getAngle(centerX, centerY, event.clientX, event.clientY);
const deltaMouseAngle = currentMouseAngle - startingMouseAngle;
(3)旋转角度简化

方块的最大旋转角度为360度,所以我们对角度进行取模,保持旋转角度在360度以内即可。

javascript 复制代码
function normalizeRotation(rotation) {
  if (rotation >= 0) {
    return rotation % 360;
  } else {
    return (rotation % 360) + 360;
  }
}
(4)给方块设置旋转角度
javascript 复制代码
rotateDiv.style.transform = `rotate(${newRotation}deg)`;

3、移除旋转逻辑

鼠标抬起的时候我们应该将旋转逻辑给移除,及将鼠标移动和抬起事件移除。

javascript 复制代码
function stopSpin() {
  window.removeEventListener("mousemove", spin);
  window.removeEventListener("mouseup", stopSpin);
}

4、完整代码

完整的JavaScrip代码如下:

javascript 复制代码
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;
}

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

相关推荐
一颗花生米。2 小时前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
学习使我快乐012 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19952 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
勿语&3 小时前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui
黄尚圈圈3 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水4 小时前
简洁之道 - React Hook Form
前端
正小安6 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch8 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光8 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   8 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发