Kun

Kun

IT学徒、技术民工、斜杠青年,机器人爱好者、摄影爱好 PS、PR、LR、达芬奇潜在学习者


共 212 篇文章


  前端可视化(五)-动画库

Lottie

Lottie是一款由airbnb开源的跨平台动画渲染库,支持Android, iOS, Web, Windows平台。是专门用于解析从AE(Adobe After Effects)中通过Bodymovin插件导出的JSON文件,直接渲染动画。

简单的demo

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Lottie</title>
    <!-- 重点:引入Lottie JS 文件 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.9.4/lottie.min.js"></script>
    <style>
      #app {
        width: 400px;
        height: 400px;
      }
    </style>
  </head>
  <body>
    <!-- 定义动画渲染的容器 -->
    <div id="app"></div>
  </body>

  <script>
    // loadAnimation 渲染动画
    const lottieAnimationItem = lottie.loadAnimation({
      // 选取一个容器,用于渲染动画
      container: document.querySelector("#app"),
      // 定义JSON文件路径
      path: "https://assets10.lottiefiles.com/packages/lf20_l3qxn9jy.json",
      // 是否循环播放
      loop: true,
      // 渲染的格式svg/canvas/html,svg性能更优,兼容性更好
      renderer: "svg",
    });
  </script>
</html>

Lottie-web

为了在项目中能够快速复用,将Lottie动画渲染简易封装成react组件Lottie

安装

# lottie-web是针对web渲染的库
yarn add lottie-web

使用

import React, { useRef, useEffect, useMemo, forwardRef, useImperativeHandle, Ref } from 'react';
import lottie, { AnimationItem } from 'lottie-web';

// 渲染类型
type rendererType = 'svg' | 'canvas' | 'html';

// 常用属性
interface IProps {
  // 是否循环播放
  loop?: boolean;
  // 渲染动画的类型
  renderer?: rendererType;
  // 是否自动播放
  autoplay?: boolean;
  // 动画渲染数据,与path互斥
  animationData?: any;
  // JSON文件路径,与animationData互斥
  path?: string;
}

export default forwardRef((props: IProps, ref: Ref<any>) => {
  // 设置props的默认值
  const { loop = true, renderer = 'svg', path = '', animationData, autoplay = true } = props;

  // 设置动画渲染的容器
  const containerEle = useRef(null);
  // 对外暴露的ref对象
  const lottieAnimation = useRef(null);

  // 指定想父级调用组件暴露的ref对象,方便元素控制当前动画的播放与暂停
  useImperativeHandle(ref, () => ({
    // 获取当前动画对象实例
    getInstance: () => lottieAnimation.current,
    // 播放,继续播放
    play: () => {
      lottieAnimation.current.play();
    },
    // 暂停动画
    pause: () => {
      lottieAnimation.current.pause();
    },
    // 停止动画,区别于暂停动画pause()
    stop: () => {
      lottieAnimation.current.stop();
    }
  }));
  
  

  // 缓存动画的相关配置
  const animationOptions = useMemo(() => {
    const options: IProps = {
      loop,
      renderer,
      autoplay
    };

    // 优先取animationData
    if (animationData) {
      options.animationData = animationData;
    } else {
      options.path = path;
    }

    return options;
  }, [loop, renderer, path, animationData, autoplay]);

  useEffect(() => {
    if (!containerEle.current) {
      return;
    }

    // 渲染动画
    const lottieAnimationItem: AnimationItem = lottie.loadAnimation({
      container: containerEle.current,
      ...animationOptions
    });
    
    // 将渲染后的动画示例对象赋值给lottieAnimation.current,对外暴露
    lottieAnimation.current = lottieAnimationItem;
    
    // 一定要注意这里的对象销毁,避免内存泄露,以及重复渲染动画
    return () => {
      // 重置为null
      lottieAnimation.current = null;
      // 销毁动画对象
      lottieAnimationItem.destroy();
    };
  }, [animationOptions]);

  // 因为lottie动画是无线宽高的,所以这里直接设置渲染的容器宽度、高度为父级元素100%即可
  return <div ref={containerEle} style={{ width: '100%', height: '100%' }}></div>;
});

调用

import React, { useRef } from "react";
import "./styles.css";
import Lottie from "./lottie";
import animationData from "./animation.json";

export default function App() {
  // 初始化ref
  const lottieRef = useRef(null);
  
  return (
    <div className="App">
      {/* 指定路径 */}
      <div className="container">
        <button
          onClick={() => {
            if (!lottieRef.current) {
              return;
            }
            // 暂停动画
            lottieRef.current.pause();
          }}
        >
          暂停
        </button>
        <button
          onClick={() => {
            if (!lottieRef.current) {
              return;
            }
            // 从当前状态继续向前播放
            lottieRef.current.play();
          }}
        >
          播放
        </button>
        <button
          onClick={() => {
            if (!lottieRef.current) {
              return;
            }
            // 停止动画,恢复到初始状态,注意与pause()方法的区别
            lottieRef.current.stop();
          }}
        >
          停止
        </button>
        <Lottie ref={lottieRef} path="https://assets10.lottiefiles.com/packages/lf20_l3qxn9jy.json"></Lottie>
      </div>
      {/* 指定animationData */}
      <div className="container">
        <Lottie animationData={animationData}></Lottie>
      </div>
    </div>
  );
}

animejs

Mojs

parallax.js

Velocityjs

flubber

流畅动画库

npm安装

npm install flubber

html引入

<script src="https://unpkg.com/flubber@0.3.0"></script>

使用

var flubber = require("flubber"); // Node classic
import { interpolate } from "flubber" // ES6

theatrejs

配合threejs生成3d动画或者操作dom/svg生成2d动画,

以threejs项目为例

安装

# with npm
npm install --save @theatre/core @theatre/studio

创建studio

/* ... */
import * as THREE from 'three'

import studio from '@theatre/studio'

/**
 * Theatre.js
 */

studio.initialize()
/* ... */

创建project和sheet

import * as THREE from 'three'

import studio, { getProject } from '@theatre/core'

// Initialize the studio
studio.initialize()

// Create a project for the animation
const project = getProject('THREE.js x Theatre.js')

// Create a sheet
const sheet = project.sheet('Animated scene')

// Create a Theatre.js object with the props you want to
// animate
const torusKnotObj = sheet.object('Torus Knot', {
  // Note that the rotation is in radians
  // (full rotation: 2 * Math.PI)
  rotation: types.compound({
    x: types.number(mesh.rotation.x, { range: [-2, 2] }),
    y: types.number(mesh.rotation.y, { range: [-2, 2] }),
    z: types.number(mesh.rotation.z, { range: [-2, 2] }),
  }),
})

torusKnotObj.onValuesChange((values) => {
  const { x, y, z } = values.rotation

  mesh.rotation.set(x * Math.PI, y * Math.PI, z * Math.PI)
})

基本概念

Projects

Projects是theatrejs中基本的单元

import { getProject } from '@theatre/core'

// This will create a project called "My Project"
// or return it if it already exists:
const project = getProject('My Project', { state: projectState })

Sheets

Sheet Objects

Sequences

Studio

渲染库

zrender

ZRender 是二维绘图引擎,它提供 Canvas、SVG、VML 等多种渲染方式。ZRender 也是 ECharts 的渲染器。

如果你觉得我的文章对你有帮助的话,希望可以推荐和交流一下。欢迎關注和 Star 本博客或者关注我的 Github