鼠标拖拽改变角度
<!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)