2024-05-10

鼠标拖拽改变角度

<!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>
  <style>
    #box {
      width: 100px;
      height: 100px;
      background-color: #666;
      margin: 100px auto;
      position: relative;

    }
    #box-r {
      width: 20px;
      height: 20px;
      background-color: red;
      margin-left: -10px;
      left: 50%;
      position: absolute;
      bottom: -40px;
    }
  </style>
</head>
<body>
  <div id="box">
    <div id="box-r"></div>
  </div>
</body>
<script>
  var box = document.getElementById('box');
  var boxR = document.getElementById('box-r');
  var boxBounding = box.getBoundingClientRect();
  var boxRBounding = boxR.getBoundingClientRect();
  // 元素中心点
  var center = getCenter(boxBounding)
  // 拖拽块中心点
  var start = getCenter(boxRBounding)

  // 获取中心点
  function getCenter(obj) {
    return {
      x: obj.left + obj.width / 2,
      y: obj.top + obj.height / 2
    }
  }

  // 点击拖拽块
  // 拖动
  boxR.addEventListener('mousedown', () => {
    // 初始化相对位置
    center = getCenter(boxBounding)
    start = getCenter(boxRBounding)
    // 触发鼠标移动移动
    document.addEventListener('mousemove', setAngle)
  })

  // 释放鼠标
  document.addEventListener('mouseup', () => {
    // 结束移动监听
    document.removeEventListener('mousemove', setAngle)
  })

  // !!重点
  // 设置角度(弧度)
  function setAngle(e) {
      // 相减确定圆心
      var x = e.clientX - center.x;
      var y = e.clientY - center.y;
      var x1 = start.x - center.x;
      var y1 = start.y - center.y;
      // 使用 Math.atan2 求出当前弧度减去起始点弧度
      var angle = Math.atan2(y, x) - Math.atan2(y1, x1);
      // 设置弧度,注意单位(rad)
      // 相减也符合象限,不用考虑方向
      box.style.transform = 'rotate(' + angle + 'rad)';
  }
  
</script>
</html>

vue3

// useTransformRotate hook
// 这里使用的是角度,所以会用转换关系
import { onMounted, Ref, ref } from 'vue'
import { useEventListener } from '@vueuse/core'

// 获取中心点
function getCenter (obj: DOMRect) {
  return {
    x: obj.left + obj.width / 2,
    y: obj.top + obj.height / 2
  }
}

// 弧度转角度
function toDeg (rad: number) {
  return rad * 180 / Math.PI
}

// 角度转弧度
function toRad (deg: string) {
  return parseInt(deg) * (Math.PI / 180);
}

// 设置角度
function setAngle (e: MouseEvent, center: { x: number, y: number }, start: { x: number, y: number }, centerRef: Ref, startRad: Ref) {
  // 相减确定圆心
  var x = e.clientX - center.x;
  var y = e.clientY - center.y;
  var x1 = start.x - center.x;
  var y1 = start.y - center.y;
  // 使用 Math.atan2 求出当前弧度减去起始点弧度
  var angle = Math.atan2(y, x) - Math.atan2(y1, x1);
  const deg = toDeg(startRad.value + angle)
  centerRef.value.style.transform = 'rotate(' + deg + 'deg)';
  return deg
}

const useTransformRotate = (centerRef: Ref, startRef: Ref) => {
  let center = { x: 0, y: 0 }
  let start = { x: 0, y: 0 }
  const startRad = ref(0)
  const rotateDeg = ref(0)
  const rotateDown = ref(true)
  const handleSetAngle = (e: MouseEvent) => {
    // 保存改变角度
    rotateDeg.value = setAngle(e, center, start, centerRef, startRad)
  }
  // 这里需要在挂载完成后获取,否则获取不到
  onMounted(() => {
    useEventListener(startRef.value, 'mousedown', (e: MouseEvent) => {
      // 阻止冒泡
      e.stopPropagation()
      if (centerRef.value && startRef.value) {
        // 初始化相对位置
        center = getCenter(centerRef.value.getBoundingClientRect())
        start = getCenter(startRef.value.getBoundingClientRect())
        // 获取角度原始值
        const transformValue = centerRef.value.style.transform
        if (transformValue != null && transformValue !== '') {
          const deg = transformValue.match(/rotate\((-?\d*.?\d*)deg\)/)![1]
          // 设置初始弧度
          startRad.value = toRad(deg)
        }
        rotateDown.value = false
        // 鼠标移动监听
        document.addEventListener('mousemove', handleSetAngle)
      }
    })
  })

  // 释放鼠标
  useEventListener(document, 'mouseup', () => {
    // 结束移动监听
    document.removeEventListener('mousemove', handleSetAngle)
    // 设置结束标识
    rotateDown.value = true
  })
  return {
    // 改变角度
    rotateDeg,
    // 结束标识,可通过 watch 监听
    rotateDown
  }
}

export default useTransformRotate

补充

圆的弧度 2pi = 360°

90deg = 100grad = 0.25turn ≈ 1.570796326794897rad

弧度转角度:deg = rad * 180 / Math.PI

角度转弧度:rad = deg * (Math.PI / 180)

Math.atan2() 返回从原点(0,0)到(x,y)点的线段与x轴正方向之间的平面角度(弧度值),也就是Math.atan2(y,x)

Math.atan2() - JavaScript | MDN (mozilla.org)

rotate() - CSS(层叠样式表) | MDN (mozilla.org)

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容