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

相关推荐
程序员爱技术5 分钟前
Vue 2 + JavaScript + vue-count-to 集成案例
前端·javascript·vue.js
并不会1 小时前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
悦涵仙子1 小时前
CSS中的变量应用——:root,Sass变量,JavaScript中使用Sass变量
javascript·css·sass
衣乌安、1 小时前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜1 小时前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师1 小时前
CSS的三个重点
前端·css
耶啵奶膘3 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^4 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie5 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic5 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js