前言
经过一段时间编码,我的博客终于上线了。前端用的nuxt,后端使用eggjs,其中有一个3D标签云的效果,将这个标签云的代码分享给大家
先看效果
基础知识
拿出高中的数学知识:
直角坐标与球面坐标的关系:
步骤:
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轴 } }
利用数学公式法均匀分布各个元素:
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://blog.reviosky.com)