本文主要介紹使用如何實現手動拖拽旋轉元素的效果。
1、簡述
最近在研究如何實現手動控制元素的旋轉效果,在網上找了很多,都沒有找出類似的實現,因此經過一些調研和計算,最終完美實現效果,在這里記錄下來。
2、效果展示
通過手動旋轉的方式,實現組件的360度無縫旋轉。圖示是實現結果的幾個截圖:
-
0deg
-
順時針轉到
66deg
-
逆時針轉到
315deg
-
轉到
180deg
3、實現分析
如圖所示,實現難點在於計算出兩點間連線的傾斜角 angle
這里需要掌握的幾個知識點:
3.1 獲取轉動的角度
使用 Math.atan2()
函數可以非常高效的實現之,它是返回點與原點之間的傾斜角,如圖所示,如果想計算出點 (x1,y1)
與 原點 (cx,cy)
與X軸的角度,只需要執行:
Math.atan2(y1 - cy, x1 - cx)
需要注意的是,它的取值范圍是[-PI, PI]。
當 (x1, y1) 在第一象限, 0 < θ < PI/2
當 (x1, y1) 在第二象限 PI/2 < θ≤PI
當 (x1, y1) 在第三象限, -PI < θ < -PI/2
當 (x1, y1) 在第四象限, -PI/2 < θ < 0
3.2 角度與弧度之間的轉換
角度 = 弧度 * 180 / Math.PI;
弧度= 角度 * Math.PI / 180;
3.3 組件中心點位置計算
使用getBoundingClientRect()
的方法可以獲取出容器的位置信息,用當前位置減去寬/高的一半,即可獲取中心點位置。
//中心點
cx = x + width / 2;
cy = y + height / 2;
4、最終代碼
/**
* 獲得旋轉夾角
* @param {*} x1 旋轉點1
* @param {*} y1
* @param {*} x2 旋轉點2
* @param {*} y2
*/
function getAngle(x1, y1, x2, y2) {
// 獲取組件的位置信息
let rect = document.getElementsByClassName('active-ele')[0].getBoundingClientRect();
let {
x,
y,
width,
height
} = rect;
//中心點
let cx = x + width / 2;
let cy = y + height / 2;
//2個點之間的角度獲取
let c1 = Math.atan2(y1 - cy, x1 - cx) * 180 / (Math.PI);
let c2 = Math.atan2(y2 - cy, x2 - cx) * 180 / (Math.PI);
let angle;
c1 = c1 <= -90 ? (360 + c1) : c1;
c2 = c2 <= -90 ? (360 + c2) : c2;
//夾角獲取
angle = Math.floor(c2 - c1);
angle = angle < 0 ? angle + 360 : angle;
return angle;
}
/**
* 獲得旋轉夾角
* @param startPos.x 指的是初始位置的x坐標
* @param startPos.y 指的是初始位置的y坐標
* @param startPos.r 指的是初始的旋轉角度
*/
let angle = getAngle(startPos.x, startPos.y, e.x, e.y);
let startAngle = startPos.r;
let deg;
// 賦值的旋轉角度
let rotate;
// 順時針旋轉
if (e.x - startX > 0) {
deg = startAngle + angle;
rotate = deg > 360 ? deg - 360 : deg;
} else {
// 逆時針旋轉
angle = 360 - angle;
deg = startAngle - angle;
rotate = deg < 0 ? deg + 360 : deg;
}