[业务实践] vue 3d球体标签云

前言

经过一段时间编码,我的博客终于上线了。前端用的nuxt,后端使用eggjs,其中有一个3D标签云的效果,将这个标签云的代码分享给大家

先看效果

3dCloud

基础知识

拿出高中的数学知识:

3dXYZ

直角坐标与球面坐标的关系:

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)

步骤:

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{表示}\\
       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)`
     }
    

初始化元素

3dCloud

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()

文章归类于: 前端

文章标签: #vue

版权声明: 自由转载-署名-非商用

0条评论

提示:

评论会在审核通过后显示在下方

昵称必填,用于展示在评论中

邮箱必填,不会公开展示,方便及时收到回复

网址选填,方便看到的人去访问,请完整填写,例如(https://blog.reviosky.com)

快来抢个沙发吧