3D 标签云
练习canvas的3D效果, 球体算法, 正好IFE 的项目有就记录一下咯.
大概思路
首先3D云其实就是一个球体, 在这个球体上平均分布各个点, 再把这些点
的坐标赋给标签,计算一下 z 轴的大小, 最后通过改变字体的大小/ 透明度
就可以模拟出立体的效果啦.
相关的一些公式及说明
- 球体 x/ y/ z 轴的坐标点
已知半径 R 和球心, 方便起见一般都以坐标轴的原点作为球心. 有如下三个方程式:1
2
3x = R * sinθ * cosø
y = R * sinθ * sinø
z = R * cosθ
其中θ 和 ø 可以去随机数, 来获取圆上的随机点坐标. 但是3D 云的坐标点是需要均匀分配的坐标点, 所以光是去随机点是不够的. 所以又有了下面的公式:
1 | // index 为当前索引, length 为标签长度 |
关键代码
1 | const setBall = _ => { |
以上就可以取得球体所需的平均坐标点, 接下来我们就需要去操作 DOM 每个标签了.
- 标签字体及透明度计算
1
2
3
4
5
6
7
8
9
10
11
12
13// fallLength 为焦距
let scale = fallLength/ (fallLength - this.z),
opa = (this.z + radius) / (2 * radius);
// 每个标签添加样式
this.element.style.cssText = `color: rgb(
${parseInt(Math.random() * 255)},
${parseInt(Math.random() * 255)},
${parseInt(Math.random() * 255)});
font-size: ${parseInt(15 * scale)}px;
opacity: ${opa + 0.5};
z-index: ${parseInt(scale * 100)};
left: ${this.x + CX - this.element.offsetWidth / 2}px;
top: ${this.y + CY - this.element.offsetHeight / 2}px`;
fallLength 是焦距, 也是一个常量, scale 和 opacity 都要通过 z 轴来调整的. 这里也是从别人的代码里看到的, 应该也是公式吧; 后面就是调整字体大小/ 透明度, 标签位置的操作了. 以上计算就是move()
函数中的内容. 现在球体已经出来了, 那么就该让他动起来了.
- 旋转算法
为了让球体动起来, 我们需要知道下面这三个公式:
然后我们需要两个函数, x 轴选择和 y 轴旋转, 关键代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23const rotateX = _ => {
// angleX 是事先定义好的角度值
let sin = Math.sin(angleX),
cos = Math.cos(angleX);
tags.forEach(function () {
let y1 = this.y * cos - this.z * sin,
z1 = this.z * cos + this.y * sin;
this.y = y1;
this.z = z1;
})
}
const rotateY = _ =>{
// angleY 是事先定义好的角度值
let cos = Math.cos(angleY),
sin = Math.sin(angleY);
tags.forEach(function () {
let x1 = this.x * cos - this.z * sin,
z1 = this.z * cos + this.x * sin;
this.x = x1;
this.z = z1;
})
}
这里 angleX 和 angleY 为角度值, 用来控制标签云的旋转方向和速度. 角度的正负值控制旋转方向; 大小控制旋转速度.
- 鼠标控制
这里就是最后一步了, 通过鼠标改变球体的旋转方向. 这里我做了一点点扩展几个输入框, 可以让用户自由填写云内容/ 数量及旋转速度, 下面直接看代码吧.
1 | // 来个事件监听 |
到这里3D 云的流程差不多就走完了, 下面放一个完整的 js 部分代码吧.
1 | (function (global) { |
Created on 17-10-8 by Cara
在线预览 demo