vue2实现一个类似soul App球体动画特效的组件

旧项目的实现 需要vue3自己改改

安装依赖 npm install three --save

main.js

import * as THREE from 'three'
Vue.prototype.THREE = THREE

组件

<template>
  <div ref="threeDom"></div>
</template>

<script>
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
export default {
  name: 'StarrySky',
  props: {
    list: {
      type: Array,
      default() {
        return [    //模拟数据
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          },
          {
            name: 'hello'
          }
        ]
      }
    },
    isPlay: {  // 加速旋转
      type: Boolean,
      default: false
    }
  },
  computed: {
    currentSpeed() {
      // 为true时球体动画加速;false回到默认缓速
      return this.isPlay ? 0.04 : 0.001
    }
  },
  data() {
    return {
      renderer: null,
      group: null,
      controls: null,
      scene: null,
      camera: null
    }
  },
  mounted() {
    /**
     * 创建场景对象Scene
     */
    this.scene = new this.THREE.Scene()
    this.scene.background = null
    /**
     * 光源设置
     */
    //点光源
    const point = new this.THREE.PointLight(0xffffff)
    point.position.set(400, 200, 300) //点光源位置
    //环境光
    const ambient = new this.THREE.AmbientLight(0x444444)
    this.scene.add(ambient)
    /**
     * 相机设置
     */
    const width = window.innerWidth //窗口宽度
    const height = window.innerHeight //窗口高度
    this.camera = new this.THREE.PerspectiveCamera(
      40,
      width / height,
      1,
      10000
    )
    this.camera.position.set(0, 0, 3000)  // 3000这个值可以修改,比如需要适配移动端和pc端的话,一般设置为6000的话就适配移动端
    this.group = new this.THREE.Group()
    const texts = this.list
    for (var i = 0, l = texts.length; i < l; i++) {
      const phi = Math.acos(-1 + (2 * i) / l)
      const theta = Math.sqrt(l * Math.PI) * phi
      // 渲染list数据
      const sprite = this.createS(texts[i].name)
       // 这里的.scale.set对点进行了缩放,可自行调整点大小
      sprite.scale.set(160, 160, 1)
      sprite.position.setFromSphericalCoords(800, phi, theta)

      //sphere.push(sprite)
      this.group.add(sprite)
    }
    this.scene.add(this.group)
    /**
     * 创建渲染器对象
     */
    this.renderer = new this.THREE.WebGLRenderer({
      antialias: true,
      alpha: true  // 该属性为true就隐藏自身的背景颜色;false就是默认黑色背景
    })
    this.renderer.setSize(width, height) //设置渲染区域尺寸
    this.renderer.shadowMap.enabled = false
    this.renderer.setPixelRatio(window.devicePixelRatio)
    this.$refs.threeDom.appendChild(this.renderer.domElement) //body元素中插入canvas对象
    //执行渲染操作指定场景、相机作为参数
    this.renderer.render(this.scene, this.camera)
    this.controls = new OrbitControls(this.camera, this.renderer.domElement)
    this.render()
  },
  methods: {
    render() {
      this.renderer.render(this.scene, this.camera) //执行渲染操作
      this.group.rotateY(-this.currentSpeed) //每次绕y轴旋转0.01弧度
      this.group.rotateX(this.currentSpeed)
      this.controls.update()
      requestAnimationFrame(this.render) //请求再次执行渲染函数render
    },
    createS(_text) {
      function makeTextCanvas(text, width, height) {
        var canvas = document.createElement('canvas')
        canvas.width = width
        canvas.height = height
        var c = canvas.getContext('2d')
        c.clearRect(0, 0, c.canvas.width, c.canvas.height)
        // 文字
        c.beginPath()
        c.translate(width / 2, height / 2)
        c.fillStyle = '#9F9FA2' //文本填充颜色
        c.font = '78px Arial' //字体样式设置
        c.textBaseline = 'middle' //文本与fillText定义的纵坐标
        c.textAlign = 'center' //文本居中(以fillText定义的横坐标)
        c.fillText(text, 0, 0)
        c.setTransform(1, 0, 0, 1, 0, 0)
        const textHeight = 78
        const circleY = height / 2 + textHeight / 2 + 50
        c.beginPath()
        c.arc(width / 2, circleY, 50, 0, Math.PI * 2, false)
        c.fillStyle = 'rgba(217, 217, 217, 1)'
        c.fill()
        return c.canvas
      }
      var textCanvas = makeTextCanvas(_text, 300, 300)
      var texture = new this.THREE.CanvasTexture(textCanvas)
      texture.generateMipmaps = false
      texture.minFilter = this.THREE.LinearFilter
      texture.magFilter = this.THREE.LinearFilter
      let pinMaterial = new this.THREE.SpriteMaterial({
        map: texture
      })
      let mesh = new this.THREE.Sprite(pinMaterial)
      return mesh
    }
  }
}
</script>

<style scoped lang="less"></style>

页面导入组件并加上背景图后的效果, 可自动旋转,手动拖拽旋转,手动缩放球体

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值