在掘金上偶然看到jy发的旋转球特效,心血来潮研究下用纯js实现3D旋转球的特效。榨干了数亿脑细胞,花费整整一天的摸鱼时间才研究出用数学三角函数来实现效果。话不多说,让我细细讲解一番。
实现效果图如下:
第一步,实现一个平面圆
如图将圆平均分为n份,每个点之间的夹角为360 / n,圆的中心为(x, y, 0),圆的半径为r,圆上点的坐标如下图:
根据三角函数,可得圆点上坐标为Xn = x + sinα * r, Yn = y - cosα * r, Zn = 0
const centerX = r;
const centerY = r;
for (let j = 1; j <= num; j++) {
const dom = document.querySelector(
`.sphere .text:nth-child(${j})`
);
const a = Math.PI / 180;
const angle = (360 / num) * (j - 1) * a;
const w = dom.innerText.length * 16;
dom.style.transform = `translateX(${centerX + r * Math.sin(angle) - w / 2}px) translateY(${centerY - r * Math.cos(angle)}px)`;
}
w是文字的总长度,减去 w / 2是为了将文字居中到点。
第二步,实现旋转圆面
计算沿y轴旋转θ角度的圆,(Xn, Yn, Zn) ---旋转θ---> (Xr, Yr, Zr)
分析:
- 旋转前的点和旋转后的点在一个圆上,圆的半径r1等于sinα * r
- y轴不变,Xr = x + r1 * cosθ,Yr = Yn, Zr = r1 * sinθ
const r1 = r * Math.sin(angle);
dom.style.transform = `translateX(${
centerX + r1 * Math.cos(a1) - w / 2
}px) translateY(${centerY - r * Math.cos(angle)}px) translateZ(${
r1 * Math.sin(a1)
}px)`;
w是文字的总长度,减去 w / 2是为了将文字居中到点。
第三步,旋转球体
球体旋转β角度,文字也会跟着旋转,为了使文字始终在平面上,文字需要反向旋转β
this.angle = 0;
function rotate() {
this.timer = setInterval(() => {
this.sphere.style.transform = `rotateY(${this.angle}deg)`;
document.querySelectorAll('.sphere .text').forEach((ele) => {
let transform = ele.style.transform;
if (!transform.includes('rotateY')) {
ele.style.transform = `${transform} rotateY(-${this.angle}deg)`;
} else {
ele.style.transform = transform.replace(
/rotateY\([-0-9]+deg\)/,
`rotateY(-${this.angle}deg)`
);
}
});
this.angle += β;
if (this.angle === 360) {
this.angle = 0;
}
}, 100);
}
源代码详见👇