[业务实践]vue 3d球体标签云
前言
经过一段时间编码,我的博客终于上线了。前端用的nuxt,后端使用eggjs,其中有一个3D标签云的效果,将这个标签云的代码分享给大家
先看效果
基础知识
拿出高中的数学知识:
直角坐标与球面坐标的关系:
x=rsin(φ)cos(θ)y=rsin(φ)sin(θ)z=rcos(φ)x=r\sin\left(\varphi\right)\cos\left(\theta\right) \\y=r\sin\left(\varphi\right)\sin\left(\theta\right) \\z=r\cos\left(\varphi\right)x=rsin(φ)cos(θ)y=rsin(φ)sin(θ)z=rcos(φ)
步骤:
1.初始化点坐标分布
- 定义基本参数
data() {
return {
fontSize: 12,//当元素在X轴上字体大小
tagEle: null,//初始化所有未分布的元素
paper: null,//背景元素
RADIUS: 80,//球体半径
fallLength: 160,//球体直径,其实用于计算字体大小,如元素在Y轴最大值即160上,字体显示最大24px
tags: [], //经过计算沿球表面均匀分布的元素
angleX: 0,//沿X轴旋转角度
angleY: 0,//沿Y轴旋转角度
x: 0,
y: 0,
z: 0,
CX: 0,//球体中心x轴
CY: 0,//球体中心y轴
}
}
- 利用数学公式法均匀分布各个元素:
分别算出φ及ϕ,代码中用a,b表示\mathrm{分别算出}\varphi 及\phi,\mathrm{代码中用}a,b\mathrm{表示}\\分别算出φ及ϕ,代码中用a,b表示
for (let i = 0; i < this.tagEle.length; i++) {
let k = (2 * (i + 1) - 1) / this.tagEle.length - 1
let a = Math.acos(k)
let b = a * Math.sqrt(this.tagEle.length * Math.PI)
}
- 计算三维坐标:
for (let i = 0; i < this.tagEle.length; i++) {
let k = (2 * (i + 1) - 1) / this.tagEle.length - 1
let a = Math.acos(k)
let b = a * Math.sqrt(this.tagEle.length * Math.PI)
this.x = this.RADIUS * Math.sin(a) * Math.cos(b)
this.y = this.RADIUS * Math.sin(a) * Math.sin(b)
this.z = this.RADIUS * Math.cos(a)
}
- 缓存坐标,将元素移动至各个坐标轴上:
for (let i = 0; i < this.tagEle.length; i++) {
let k = (2 * (i + 1) - 1) / this.tagEle.length - 1
let a = Math.acos(k)
let b = a * Math.sqrt(this.tagEle.length * Math.PI)
this.x = this.RADIUS * Math.sin(a) * Math.cos(b)
this.y = this.RADIUS * Math.sin(a) * Math.sin(b)
this.z = this.RADIUS * Math.cos(a)
let tag = { ele: this.tagEle[i], x: this.x, y: this.y, z:this.z}
this.tags.push(tag)
this.move(tag)
}
move(tag) {
let { ele, x, y, z } = tag
let scale = this.fallLength / (this.fallLength - z)
let alpha = (z + this.RADIUS) / (2 * this.RADIUS)
//让后面的元素文字小一些突出3d感
ele.style.fontSize = this.fontSize * scale + 'px'
//让后面的元素淡一些突出3d感
ele.style.opacity = alpha + 0.5
ele.style.filter = 'alpha(opacity = ' + (alpha + 0.5) * 100 + ')'
ele.style.zIndex = parseInt(scale * 100)
//将元素移动到相应的点坐标上
ele.style.transform = `translate(${
x + this.CX - ele.offsetWidth / 2
}px, ${y + this.CY - ele.offsetHeight / 2}px)`
}
初始化元素
2.球旋转后x,y,z轴变化1
- 定义随X,Y轴函数旋转函数(设由X轴方向旋转角度参数angleX、angleY/次):
rotateX() {
let _this = this
let cos = Math.cos(this.angleX)
let sin = Math.sin(this.angleX)
this.tags.forEach((tag) => {
let y1 = tag.y * cos - tag.z * sin
let z1 = tag.z * cos + tag.y * sin
tag.y = y1
tag.z = z1
})
},
rotateY() {
let _this = this
let cos = Math.cos(this.angleY)
let sin = Math.sin(this.angleY)
this.tags.forEach((tag) => {
let x1 = tag.x * cos - tag.z * sin
let z1 = tag.z * cos + tag.x * sin
tag.x = x1
tag.z = z1
})
}
- 转动后重新移动元素布置,定义动画函数
animate() {
let _this = this
setInterval(() => {
_this.rotateX()
_this.rotateY()
_this.tags.forEach((tag) => {
_this.move(tag)
})
}, 30)
},
3.初始化vue mouted生命周期
this.tagEle = document.querySelectorAll('.tag')
this.paper = document.querySelector('.tagBall')
//球中心点取背景元素的中间
this.CX = this.paper.offsetWidth / 2
this.CY = this.paper.offsetHeight / 2
//初始化旋转角
this.angleX = ((Math.random() - 0.5) * Math.PI) / 250
this.angleY = ((Math.random() - 0.5) * Math.PI) / 250
this.init()
this.animate()
转载自:https://juejin.cn/post/7067079870076944392