Vue标签云

先看一波效果图:

标签云效果图

分析动画过程

  1. 标签的运动轨迹是环球运动。假设球中心的点坐标是 (0,0,0) ,则x=rsinθcosΦ y=rsinθsinΦ z=r*cosθ, 用 translate3d(x, y, z) 来实现位置变化;
  2. 标签越往后就会越看不见,也会越来越小。可以设置opacity、font-size来实现标签靠后的动画;
  3. 转动速度即就是x、y、z的变化速率,滚动半径的大小即就是x、y、z的变化范围。

代码实现

静态标签云

初始化标签云容器tag-cloud,以及标签集P

1
2
3
<div class="tag-cloud" ref="wrapper">
<p v-for="(item, index) in data" :key="index" ref="tag" @click="clickTag(item)" @dblclick="dbclickTag(item)">{{item.name}}</p>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<style scoped>
.tag-cloud {
width: 300px;
height: 300px;
position: relative;
color: #333;
margin: 0 auto;
text-align: center;
}

.tag-cloud p {
position: absolute;
top: 0px;
left: 0px;
color: #333;
font-family: Arial;
text-decoration: none;
margin: 0 10px 15px 0;
line-height: 18px;
text-align: center;
font-size: 16px;
padding: 4px 9px;
display: inline-block;
border-radius: 3px;
}
</style>

随机颜色和位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
for (var i = 0, length = this.data.length; i < length; i++) {
// 获取球面上均匀的点的经纬度 θ = arccos( ((2*num)-1)/all - 1); Φ = θ*sqrt(all * π);
let angleX = Math.acos((2 * (i + 1) - 1) / length - 1)
let angleY = angleX * Math.sqrt(length * Math.PI)
// 根据经纬度获取点的坐标,球中心的点坐标是 (0,0,0) x=r*sinθ*cosΦ y=r*sinθ*sinΦ z=r*cosθ;
const x = this.option.radius * Math.sin(angleX) * Math.cos(angleY)
const y = this.option.radius * Math.sin(angleX) * Math.sin(angleY)
const z = this.option.radius * Math.cos(angleX)
if (this.option.color) {
this.$refs.tag[i].style.color = this.option.color
} else {
// 随机颜色
this.$refs.tag[i].style.color =
'rgb(' +
Math.round(255 * Math.random()) +
',' +
Math.round(255 * Math.random()) +
',' +
Math.round(255 * Math.random()) +
')'
}
}

标签云的动画实现

开启定时器,通过定时设置每一个标签的(x, y, z, opacity, fontSize)来实现。

具体实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 在mounted的生命周期里面实现
const _self = this
this.timer = setInterval(function() {
for (var i = 0; i < _self.tagList.length; i++) {
_self.rotateX(_self.tagList[i])
_self.rotateY(_self.tagList[i])
_self.setPosition(
_self.tagList[i],
_self.option.radius,
_self.option.maxFont
)
}
}, 20)

/* 相关的设置方法 */
setPosition(tag, r, maxFont) {
// 设置每个标签的坐标位置和字体大小以及透明度
if (this.$refs.wrapper) {
tag.ele.style.transform =
'translate(' +
(tag.x +
this.$refs.wrapper.offsetWidth / 2 -
tag.ele.offsetWidth / 2) +
'px,' +
(tag.y +
this.$refs.wrapper.offsetHeight / 2 -
tag.ele.offsetHeight / 2) +
'px)'
tag.ele.style.opacity = tag.z / r / 2 + 0.7
tag.ele.style.fontSize = (tag.z / r / 2 + 0.5) * maxFont + 'px'
}
},
rotateX(tag) {
var cos = Math.cos(this.rotateAngleX)
var sin = Math.sin(this.rotateAngleX)
var y1 = tag.y * cos - tag.z * sin
var z1 = tag.y * sin + tag.z * cos
tag.y = y1
tag.z = z1
},
rotateY(tag) {
var cos = Math.cos(this.rotateAngleY)
var sin = Math.sin(this.rotateAngleY)
var x1 = tag.z * sin + tag.x * cos
var z1 = tag.z * cos - tag.x * sin
tag.x = x1
tag.z = z1
}

具体代码和使用说明请移步。Vue标签云

坚持原创技术分享,您的支持将鼓励我继续创作!