问题描述
我正在尝试在 HTML 页面上使用 mousemove 事件旋转 DIV 元素。我想使用点积找到旋转角度。我知道也可以使用 Math.atan2,但我想在我的示例中使用点积。
到目前为止,我尝试实现以下公式:
cos(angle) = dot(a,b) / (length(a) * length(b))
但是下面的实现效果不佳。 可能是什么问题?
谢谢
代码笔: https://codepen.io/1rosehip/pen/qBrLYLo
const $Box = document.getElementById('Box');
const shapeRect = $Box.getBoundingClientRect();
const shapeCenterX = shapeRect.x + shapeRect.width / 2;
const shapeCenterY = shapeRect.y + shapeRect.height / 2;
/**
* get vector magnitude
* @param {Array.<number>} v
* @return {number}
*/
const length = v => {
return Math.sqrt(v[0] ** 2 + v[1] ** 2);
};
/**
* dot product
* @param {Array.<number>} v1
* @param {Array.<number>} v2
* @return {number}
*/
const dot = (v1,v2) => {
return v1[0] * v2[0] + v1[1] * v2[1];
};
/**
* handle rotation
*/
document.addEventListener('mousemove',(evt) => {
// vector #1 - shape center
const centerVector = [shapeCenterX,shapeCenterY];
const centerVectorLength = length(centerVector);
// vector #2 - mouse position
const mouseVector = [evt.pageX,evt.pageY];
const mouseVectorLength = length(mouseVector);
// cos(angle) = dot(a,b) / (length(a) * length(b))
const radians = Math.acos(dot(centerVector,mouseVector) / (centerVectorLength * mouseVectorLength));
const degrees = radians * (180 / Math.PI);
const angle = (degrees + 360) % 360;
$Box.style.transform = `rotate(${degrees}deg)`;
});
#Box{
position: absolute;
background: #111;
left: 100px;
top: 100px;
width: 100px;
height: 100px;
}
<div id="Box"></div>
解决方法
我发现了问题。
(1) 向量是从错误的原点(页面左上角而不是形状中心)定义的。
(2) Math.acos 返回 [0,pi] 而不是 [0,2*pi] 范围内的结果。 当鼠标向左移动并通过形状中心时,它应该固定(360 - 度)。
固定版本的codepen: https://codepen.io/1rosehip/pen/JjWwaYE
const $box = document.getElementById('box');
const shapeRect = $box.getBoundingClientRect();
const shapeCenterX = shapeRect.x + shapeRect.width / 2;
const shapeCenterY = shapeRect.y + shapeRect.height / 2;
/**
* get vector magnitude
* @param {Array.<number>} v
* @return {number}
*/
const length = v => {
return Math.sqrt(v[0] ** 2 + v[1] ** 2);
};
/**
* dot product
* @param {Array.<number>} v1
* @param {Array.<number>} v2
* @return {number}
*/
const dot = (v1,v2) => {
return v1[0] * v2[0] + v1[1] * v2[1];
};
/**
* handle rotation
*/
document.addEventListener('mousemove',(evt) => {
// vector #1 - shape center
const centerVector = [evt.pageX - shapeCenterX,0 - shapeCenterY];
const centerVectorLength = length(centerVector);
// vector #2 - mouse position
const mouseVector = [evt.pageX - shapeCenterX,evt.pageY - shapeCenterY];
const mouseVectorLength = length(mouseVector);
// cos(angle) = dot(a,b) / (length(a) * length(b))
const radians = Math.acos(dot(centerVector,mouseVector) / (centerVectorLength * mouseVectorLength));
let degrees = radians * (180 / Math.PI);
// const angle = (degrees + 360) % 360;
if(evt.pageX < shapeCenterX){
degrees = 360 - degrees;
}
$box.style.transform = `rotate(${degrees}deg)`;
});
#box{
position: absolute;
background: #111;
left: 100px;
top: 100px;
width: 100px;
height: 100px;
}
<div id="box"></div>