設置:transform :rotateX(30deg) rotateY(40deg) rotateZ(0deg)
/**
- 計算旋轉後的四個角點 3D 座標(支持動態左上角座標)
- @param {number} left - 左上角初始 x 座標
- @param {number} top - 左上角初始 y 座標
- @param {number} width - 元素寬度
- @param {number} height - 元素高度
- @param {number} [x=0] - rotateX 角度(度)
- @param {number} [y=0] - rotateY 角度(度)
- @param {number} [z=0] - rotateZ 角度(度)
- @param {number} [originX=width/2] - 旋轉中心 x(相對於左上角)
- @param {number} [originY=height/2] - 旋轉中心 y(相對於左上角)
- @returns {Array<{x: number, y: number, z: number}>} 四個角點的 3D 座標 [左上, 右上, 右下, 左下]
*/
const getTransformedCorners = (
x: number,
y: number,
width: number,
height: number,
rotateX: number,
rotateY: number,
rotateZ: number,
perspective: number = 2000
) => {
// 角度歸一化
const normalizeAngle = (angle: number) => ((angle % 360) + 360) % 360
rotateX = normalizeAngle(rotateX)
rotateY = normalizeAngle(rotateY)
rotateZ = normalizeAngle(rotateZ)
// 轉換為弧度(Z旋轉取反)
const degToRad = (deg: number) => deg * (Math.PI / 180)
const rx = degToRad(rotateX)
const ry = degToRad(rotateY)
const rz = degToRad(-rotateZ) // 關鍵修改處
// 中心點計算
const cx = x + width / 2
const cy = y + height / 2
// 四角局部座標
const corners = [
{ x: -width / 2, y: -height / 2, z: 0 },
{ x: width / 2, y: -height / 2, z: 0 },
{ x: -width / 2, y: height / 2, z: 0 },
{ x: width / 2, y: height / 2, z: 0 }
]
// 旋轉矩陣(CSS順序:先Z後Y再X)
const cosX = Math.cos(rx),
sinX = Math.sin(rx)
const cosY = Math.cos(ry),
sinY = Math.sin(ry)
const cosZ = Math.cos(rz),
sinZ = Math.sin(rz)
// 合併旋轉矩陣:R = Rx Ry Rz
const rotationMatrix = [
[cosY * cosZ, cosY * sinZ, -sinY],
[sinX * sinY * cosZ - cosX * sinZ, sinX * sinY * sinZ + cosX * cosZ, sinX * cosY],
[cosX * sinY * cosZ + sinX * sinZ, cosX * sinY * sinZ - sinX * cosZ, cosX * cosY]
]
// 應用變換
return corners.map((corner) => {
const xRotated = rotationMatrix[0][0] * corner.x + rotationMatrix[0][1] * corner.y
const yRotated = rotationMatrix[1][0] * corner.x + rotationMatrix[1][1] * corner.y
const zRotated = rotationMatrix[2][0] * corner.x + rotationMatrix[2][1] * corner.y
const scale = perspective / (perspective + zRotated)
return {
x: cx + xRotated * scale,
y: cy + yRotated * scale
}
})
}