工作生活

bodymovin把AE动画转换成HTML5/Android/i

2019-07-03  本文已影响0人  Clover园
//先安装   "bodymovin": "^4.13.0",
//data.json是在AE导出的JSON

import React from 'react'
import bodymovin from 'bodymovin'

class Loading2 extends React.Component{
  componentDidMount(){
    const animData = {
      wrapper: document.querySelector('#animationWindow'),
      animType: 'svg',
      loop: true,
      prerender: true,
      autoplay: true,
      animationData:require('./data.json')
    };
    this.anim = bodymovin.loadAnimation(animData);
    this.anim.setSpeed(1.42);
  }
  componentWillUnmount(){
    this.anim = null
  }
  render(){
    return (
      <div  style={{width:'100%',height:'100%'}}>
        <div id="animationWindow" style={{width:'100%',height:'100%'}}/>
      </div>
    )
  }
}
export default Loading2

鼠标动画=》安装"gsap": "^2.0.1",

//BGParticle.js
import {TweenLite,Circ} from "gsap/all";

class BGParticle {
  constructor(id) {
    this.id = id
    this.width = window.innerWidth
    this.height = window.innerHeight
    this.points = []
    this.target = {}
    this.canvas = null
    this.ctx = null
    this.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
      window.webkitRequestAnimationFrame || window.msRequestAnimationFrame
    this.cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame

  }

  createCanvas() {
    this.canvas = document.createElement('canvas')
    this.ctx = this.canvas.getContext('2d')
    this.canvas.style.display = 'block'        //防止全屏的canvas出现滚动条
    this.canvas.width = this.width
    this.canvas.height = this.height
    this.canvas.style.position = 'fixed'
    this.canvas.style.top = '0'
    this.canvas.style.left = '0'
    document.getElementById(this.id).appendChild(this.canvas)
  }

  createPoints() {
    const {width, height} = this
    //创建粒子和粒子的起始位置
    for (let x = 0; x < width; x = x + width / 20) {
      for (let y = 0; y < height; y = y + height / 20) {
        let px = x + Math.random() * width / 20;
        let py = y + Math.random() * height / 20;
        let p = {x: px, originX: px, y: py, originY: py};
        this.points.push(p);
      }
    }
    //给每个粒子添加新属性closest、radius
    for (let i = 0; i < this.points.length; i++) {
      let closest = [];
      let p1 = this.points[i];
      for (let j = i + 1; j < this.points.length; j++) {
        let p2 = this.points[j]
        let placed = false;
        for (let k = 0; k < 5; k++) {
          if (!placed) {
            if (closest[k] === undefined) {
              closest[k] = p2;
              placed = true;
            }
          }
        }
        for (let k = 0; k < 5; k++) {
          if (!placed) {
            if (this.getDistance(p1, p2) < this.getDistance(p1, closest[k])) {
              closest[k] = p2;
              placed = true;
            }
          }
        }
      }
      p1.closest = closest;
      p1.radius = 2 + Math.random() * 2
      //给粒子添加抖动
      this.shakePoint(p1);
    }
  }

  shakePoint(point) {
    TweenLite.to(point, 1 + 1 * Math.random(), {
      x: point.originX - 50 + Math.random() * 100,
      y: point.originY - 50 + Math.random() * 100, ease: Circ.easeInOut,
      onComplete: () => {
        this.shakePoint(point);
      }
    });
  }

  drawPoint(point, ctx) {
    if (!point.pointActive) return;
    ctx.beginPath();
    ctx.arc(point.x, point.y, point.radius, 0, 2 * Math.PI, false);
    ctx.fillStyle = 'rgba(156,217,249,' + point.pointActive + ')';
    ctx.fill();
  }

  drawLines(point, ctx) {
    if (!point.lineActive) return;
    for (let item of point.closest) {
      ctx.beginPath();
      ctx.moveTo(point.x, point.y);
      ctx.lineTo(item.x, item.y);
      ctx.strokeStyle = 'rgba(156,217,249,' + point.lineActive + ')';
      ctx.stroke();
    }
  }

  getDistance(p1, p2) {
    return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2);
  }

  handleResize() {
    this.width = window.innerWidth
    this.height = window.innerHeight
    this.canvas.width = this.width
    this.canvas.height = this.height
  }

  handleMouseMove(e) {
    let posx = 0, posy = 0;
    if (e.pageX || e.pageY) {
      posx = e.pageX;
      posy = e.pageY;
    }
    else if (e.clientX || e.clientY) {
      posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
      posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
    }
    this.target.x = posx;
    this.target.y = posy;
  }

  init() {
    this.createCanvas()
    this.createPoints()
    this.start()

    window.onresize = (e) => this.handleResize(e)
    window.onmousemove = (e) => this.handleMouseMove(e)
  }

  start() {
    const {width, height, getDistance, points, ctx, target, requestAnimationFrame} = this
    this.ctx.clearRect(0, 0, width, height);

    for (let point of points) {
      if (Math.abs(getDistance(target, point)) < 4000) {
        point.lineActive = 0.3;
        point.pointActive = 0.6;
      } else if (Math.abs(getDistance(target, point)) < 20000) {
        point.lineActive = 0.1;
        point.pointActive = 0.3;
      } else if (Math.abs(getDistance(target, point)) < 40000) {
        point.lineActive = 0.02;
        point.pointActive = 0.1;
      } else {
        point.lineActive = 0;
        point.pointActive = 0;
      }

      this.drawLines(point, ctx)
      this.drawPoint(point, ctx);
    }
    this.myReq = requestAnimationFrame(() => this.start());
  }

  destory() {
    const cancelAnimationFrame = this.cancelAnimationFrame
    cancelAnimationFrame(this.myReq)
    window.onresize = null
    window.onmousemove = null
  }
}
export default BGParticle;
//--------------------------------------------------------------------
 //用的页面引入
import BGParticle from '../../utils/BGParticle'

//初始化时
this.particle = new BGParticle('backgroundBox')
this.particle.init()
//记得销毁
 componentWillUnmount () {
    this.particle && this.particle.destory()
  }
//html中
  <div id='backgroundBox' style={styles.backgroundBox}/>
//css
const styles = {
  backgroundBox: {
    position: 'fixed',
    top: '0',
    left: '0',
    width: '100vw',
    height: '100vh',
    backgroundImage: 'url(https://github.com/zhangZhiHao1996/image-store/blob/master/react-admin-master/bg1.jpg?raw=true)',
    backgroundSize: '100% 100%',
    transition:'all .5s'
  }
}

登录的背景图太大,等载入完后再显示,实际上是图片预加载,

loadImageAsync (url) {
   return new Promise(function(resolve, reject) {
     const image = new Image();
     image.onload = function() {
       resolve(url);
     };
     image.onerror = function() {
       console.log('图片载入错误')
     };
     image.src = url;
   });
 }
//调用
this.loadImageAsync(url).then(url=>{
     this.setState({
       loading:false,
       url
     })
   }).then(()=>{
     //为什么写在then里?id为backgroundBox的DOM元素是在loading为false时才有,而上面的setState可能是异步的,必须等到setState执行完成后才去获取dom
     this.particle = new BGParticle('backgroundBox')
     this.particle.init()
  })
上一篇下一篇

猜你喜欢

热点阅读