【Animejs教程】一个绝赞易用的动画库 Animejs,一个绝好的threejs动画辅助库

接触Animejs的契机

笔者在有一天制作threejs的动画时,发现一个问题,之前我一直在用的requestAnimationFrame,不适合用于制作大量的动画

1.我需要将大量的动画目标放到全局,或者要写多个requestAnimationFrame,不便于控制

	
	let a1 = ...
	let a2 = ...

	function animation(){
		//a1执行动画
		//a2执行动画
		requestAnimationFrame(animation);
	}
	
	//或

	let a1 = ...
	let raf1;

	function animation(){
		raf1 = requestAnimationFrame(animation);
		
		if(不满足a1动画条件){
			cancelAnimationFrame(raf1);
		}else{
			//执行a1动画
		}
	}
  1. 如果我要使用定时器,一旦帧率出现波动,动画将会出现错位问题

  2. 笔者也使用过threejs圈内流传最广的tweenjs,但是网络上能搜索到的tweenjs就有好几个版本,threejs自带的开发包中带一个,npm上有很多个版本,然后createjs下带一个,createjs.tween,还有一个tweenMax

可以说,tween的版本众多,且很难找到能匹配的文档,所以在前期,我只能选择文档比较足的createjs.tween

  1. 但是,我随后又遇到了麻烦,笔者当时使用的createjs.tween的写法比较蛋疼,且不能做非匀速的动画,一旦遇到加速动画,就成了麻烦

5.在上述的这么多问题的驱使下,我自己开发了一个动画库,一个基于requestAnimationFrame的动画库,但是,紧接着又一次遇到了,非匀速动画的算法问题

在一次又一次的搜寻中,我遇到了Animejs

animejs介绍

animejs官网

原先animejs是有中文站的,但是animejs.cn这个站点在这两年挂掉了

animejs是一个很全面很专业的动画库,除了动画的基础功能外,它还有内置了N种缓动函数,内置了自定义缓动方式,时间线控制等,各位可以自行查看官网的效果演示,来感受animejs的动画效果

animejs与threejs是可以完美兼容的,所以对于看我文章学习threejs的同学,如果对threejs的动画遇到困难,可以尝试使用一下animejs

闲话到此为止,接下来进入animejs的正式教程

animejs安装

npm

	npm install animejs --save

引入方式

	原生
		<script src="anime.min.js"></script>
	ES6:
		import anime from 'animejs/lib/anime.es.js';
	CommonJS
		const anime = require('animejs');

animejs在Github的链接

基础动画

animejs支持给任何 对象 做动画,比如说一个div,一个js对象,甚至一个数组等

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #d1{
            position: absolute;
            width: 50px;
            height: 50px;
            top:50px;
            background-color: #7FFF7F;
        }
    </style>
</head>
<body>

<div id="d1"></div>
<input type="button" value="播放动画" id="btn">

<script type="module">
	//由于笔者写threejs的习惯,这里已经习惯了使用ES版本的文件
    import anime from "./anime.es.js";

	//获取d1这个div
    let d1 = document.getElementById('d1');
	//获取按钮
    let btn = document.getElementById('btn');
	//给按钮绑定点击事件,点击后执行动画
    btn.onclick = ()=>{
        anime({
            targets:d1, //动画目标
            left:"100px", //目标指定的属性值要变化到多少,这里是让 css样式中的left变化到100px
            duration:3000 //动画播放时间
        })
    }

</script>
</body>
</html>


在这里插入图片描述

animejs如何绑定动画目标

上面的代码,可以用另一种写法同样的效果

id选择器

	let btn = document.getElementById('btn');

    btn.onclick = ()=>{
        anime({
            targets:"#d1",
            left:"100px",
            duration:3000
        })
    }

class选择器

使用class依然可行

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .d1{
            position: absolute;
            width: 50px;
            height: 50px;
            top:50px;
            background-color: #7FFF7F;
        }
    </style>
</head>
<body>

<div class="d1"></div>
<input type="button" value="播放动画" id="btn">

<script type="module">

    import anime from "./anime.es.js";

    let btn = document.getElementById('btn');

    btn.onclick = ()=>{
        anime({
            targets:".d1",
            left:"100px",
            duration:3000
        })
    }

</script>
</body>
</html>

js对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #d1{
            position: absolute;
            width: 50px;
            height: 50px;
            top:50px;
            background-color: #7FFF7F;
        }
    </style>
</head>
<body>

<div id="d1"></div>
<input type="button" value="播放动画" id="btn">

<script type="module">

    import anime from "./anime.es.js";

    let btn = document.getElementById('btn');

    let d1 = document.getElementById('d1');

    let param = {
        left:0
    }

    btn.onclick = ()=>{
        anime({
            targets:param,
            left:100,
            duration:3000,
            update:()=>{ //动画每播放一帧执行一次
                d1.style.left = param.left + "px";
            }
        })
    }

</script>
</body>
</html>

以上所有写法都是同样的效果

threejs对象

以下代码均在threejs基础教程中做过讲解,这里不再赘述

    function addMesh(){
        let geometry = new THREE.BoxGeometry(1,1,1);
        let material = new THREE.MeshStandardMaterial({color:0xff0000});
        let mesh = new THREE.Mesh(geometry,material);
        scene.add(mesh);

        document.getElementById('btn').onclick = ()=>{
            anime({
                targets: mesh.position,//animejs的targets必须是一个对象
                x:5,//这里的x,必须是当前对象下拥有的属性,mesh.position是一个Vector3对象,它的下面有x这条属性
                duration:3000
            })
        }
    }

在这里插入图片描述

多个目标

    btn.onclick = ()=>{
        anime({
            targets:['#d1','#d2'],
            left:100,
            duration:3000
        })
    }

这里非常好理解,就是变成了数组,然后让数组内的所有元素做相同的动作

如果你想让所有的元素做不同的动作,请看下面

animejs动画对象的编写格式

上面演示的过程中,我们不难发现,执行一次动画,必须需要的东西有:

  1. 动画目标
  2. 执行时间
  3. 动画执行方式
  4. 动画配置

animejs中,我们需要传入一个对象,比如说上面的

        anime({
            targets:'#d1',
            left:100,
            duration:3000
        })
		//完全可以写成这样
		let animeConfig = {
			//动画目标
			targets:"#d1",
			//动画的执行方式
			left:100,
			
			//动画的执行时间,默认为1000
			duration:3000
			
			//动画配置
		}

animejs支持的动画

dom元素动画

比如说

anime({
  targets: '.d1',
  left: '240px',
  backgroundColor: '#FFF',
  borderRadius: ['0%', '50%'],
});

在这里插入图片描述
animejs支持 给大部分常见的css元素属性做动画,比如元素的位置,旋转角度,大小,背景色,边框等,css的动画这里就介绍这一点,其他的可以参考官方的说明
animejs官网对css属性动画的说明

对象动画

    let btn = document.getElementById('btn');
    let d1 = document.getElementById('d1');

    let param = {
        left:0,
        backgroundColor:"#7fff7f",
        borderRadius:"0%"
    }

    btn.onclick = ()=>{
        anime({
            targets: param,
            left:270,
            backgroundColor: '#00ffff',
            borderRadius: "50%",
            update:()=>{
                d1.style.left = param.left + "px";
                d1.style.backgroundColor = param.backgroundColor;
                d1.style.borderRadius = param.borderRadius;
            }
        });
    }

上述代码效果与上面dom动画基本一致

可以看出,animejs支持基本数据的动画变化,支持颜色变化,也支持字符串的变化

有些人要问了:为什么要单独写一个param来创建动画呢?

动画目标与实际目标

在上面的代码中,我们创建了一个param,作为动画目标,让它进行变化,这样我们就可以更方便写一些其他的控制逻辑

创建动画目标还能解决不同对象同时开始做动画的逻辑问题,如threejs中,同时要做位移和旋转,甚至缩放动画时

    function addMesh(){
        let geometry = new THREE.BoxGeometry(1,1,1);
        let material = new THREE.MeshStandardMaterial({color:0xff0000});
        let mesh = new THREE.Mesh(geometry,material);
        scene.add(mesh);

        document.getElementById('btn').onclick = ()=>{
            let param = {
                px : 0, py : 0, pz : 0,
                rx : 0, ry : 0, rz : 0
            }

            anime({
                targets: param,
                px:5,
                py:-1,
                pz:5,
                rx:Math.PI * 0.5,
                ry:Math.PI,
                rz:Math.PI * 0.3,
                update:()=>{
                    mesh.position.x = param.px;
                    mesh.position.y = param.py;
                    mesh.position.z = param.pz;
                    mesh.rotation.x = param.rx;
                    mesh.rotation.y = param.ry;
                    mesh.rotation.z = param.rz;
                }
            })
        }
    }

	//并不是说,做复杂动画,就必须要和上面一致,这里更强调的是逻辑清晰
	//同时写3个anime动画也可行,这个根据自己的实际需求去写即可

在这里插入图片描述

DOM数值与SVG

这两部分笔者很少用,直接看官方文档吧
DOM数值动画
SVG动画

动画基本配置

常用属性duration,delay,endDelay,easing

	   anime({
            targets: "#d1",
            left:270,
            duration:2000,//动画时间
            delay:500,//延迟多久播放
            endDelay:500,//播放完成后延迟多久动画彻底结束
            easing:"easeInOutElastic" //动画缓动方式
        });

在这里插入图片描述
在这里插入图片描述
duration:动画播放时间,这个好理解
delay,是指动画播放前的延迟时间,而这个时间被算在Duration内
EndDelay,是指动画播放完成后,还需要停顿多久,这个属性在后面的循环时会用到

easing,缓动方式,缓动方式,决定了我们能做更好看的动画

缓动方式算法表以及缓动动画演示
只要指向每一个缓动的线,我们就能知道我们的物体将会怎样运动

上图我们选择了
在这里插入图片描述
可以看出,我们的动画,是刚开始先抖动,然后极速到达后方,再抖动后到达指定位置
这就是缓动方式

缓动方式特别适合用于做一些高级动画效果,笔者这里用的最多的,就是在数字孪生项目中的飞入效果,先提前定义一个相机的飞入位置,然后再执行缓动动画,先快后慢的到达目的地,来实现一个很舒服的飞入效果

        document.getElementById('btn').onclick = ()=>{
            anime({
                targets: camera.position,
                x:0,
                y:10,
                z:10,
                easing:"easeOutCubic",
                update:()=>{
                    orbitControls.update();
                }
            })
        }

在这里插入图片描述

限制小数点的round

非常简单,就是限制你动画现实的数据是否要做小数点的限制,自己看官网吧,不做介绍了

对不同的属性做不同的动画效果

这里我就上官网文档的代码了,其实就是对不同的属性做了个不同的效果动画,也是用于做复杂动画时使用

anime({
  targets: '.specific-prop-params-demo .el',
  translateX: {
    value: 250,
    duration: 800
  },
  rotate: {
    value: 360,
    duration: 1800,
    easing: 'easeInOutSine'
  },
  scale: {
    value: 2,
    duration: 1600,
    delay: 800,
    easing: 'easeInOutQuart'
  },
  delay: 250 // All properties except 'scale' inherit 250ms delay
});

方向Direction

在这里插入图片描述
也是超级好理解的属性,默认是正常的动画播放

direction : reverse 倒着播放动画
direction :alternate ,反复播放,需要循环次数大于2才生效
代码过于简单,不写那么多了

anime({
  targets: '.dir-normal',
  translateX: 250,
  easing: 'easeInOutSine',
  direction: 'reverse',
});

循环loop

超级好理解,就是动画要播放几次,或是否要无限播放
loop这个属性,可以传入数字,可以传入true或false,默认值是false,即动画播放一次后就停止
传入数字必须是正整数,传入的数字是几就循环播放几次
传入的是true的情况下,动画将无限播放

	anime({
		targets:'#d1',
		loop: true,
	})

自动播放Autoplay

动画是否创建时就播放

    let a1 = anime({
        targets:"#d1",
        left:200,
        autoplay:false
    })

    btn.onclick = ()=>{
        a1.play();
    }

用于控制动画什么时候播放

动画支持的数据类型

过于简单的笔者这里就不写代码了,直接摘抄官网文档的代码来做讲解

css基本样式

//基本的数据操作
anime({
  targets: '.unitless-values-demo .el',
  translateX: 250, // -> 沿x轴平移250px
  rotate: 540, // -> 旋转540deg
  backgroundColor:'#000000', //从默认色变成黑色,支持各种css颜色,如'#fff',rgb(),rgba,hsl等等
});

//是个css属性它都支持
anime({
  targets: '.specific-unit-values-demo .el',
  width: '100%', // -> 从 '28px' 变化到 '100%',
});

//相对值
anime({
	targets:'d1',
	left:'+=100px',//让d1这个dom的left增加100px
})

//设定初始值和结束值
anime({
	targets:'d1',
	left:['0','200px'],//从0px变化到200px
})

数据

基本所有数字类型的数据都支持,同时也支持上述的相对值,百分比等,具体使用请根据个人需求来使用

时间线

时间线说白了就是连续的动画播放的时间线

时间线基础

在这里插入图片描述
如果我们需要做一段连续动画,如果没有时间线概念的话,就会出现无限套娃的情况

	anime({
		targets:anime1,
		...
		changeComplete:()=>{
			anime({
				targets:anime2,
				...
				changeComplete:()=>{
					anime({
						targets:anime3,
						...
						changeComplete:()=>{
							...
						}
					})
				}
			})
		}
	})

上述的套娃逻辑,我相信是个人都不愿意写,这个时候官方提供了一种时间线的解决方案

	//创建时间线
    let timeline = anime.timeline({
        targets:"#d1",
        autoplay:false
    })
	//1秒 向右移动到300px
    timeline.add({
        left:300,
        duration:1000,
        easing:"linear"
    });
	//1.5秒向下移动到150px
    timeline.add({
        top:150,
        duration:1500,
        easing:"easeOutBounce"
    });
	//0.5秒向左移动到0
    timeline.add({
        left:0,
        duration:500,
        easing:"easeInElastic"
    });
	//2秒向上移动到50
    timeline.add({
        top:50,
        duration:2000,
        easing:"easeOutBack"
    });


    btn.onclick = ()=>{
        timeline.play();
    }

在这里插入图片描述
时间线在add了新的动画后,在执行动画时,会默认按照顺向播放来播放,所以总动画时间 = 每个时间线添加的动画总时间之和

时间线偏移

但是,我们也不是永远都是顺向播放的动画,也有可能前面的一段动画没有播完,就要开始播下一段

在这里插入图片描述
这里我们就使用时间线的第二个功能,时间线偏移

偏移有两种方法,一种是相对一种是绝对

    let timeline = anime.timeline({
        targets:"#d1",
        autoplay:false
    })

    timeline.add({
        left:300,
        duration:1000,
        easing:"linear"
    });

    timeline.add({
        top:150,
        duration:1500,
        easing:"easeOutBounce"
    },"-=500"); //让向下移动的动画提前0.5秒执行

    timeline.add({
        left:0,
        duration:500,
        easing:"easeInElastic"
    },1000); //让向左移动的动画,在时间线播放第一秒的时候执行

    timeline.add({
        top:50,
        duration:2000,
        easing:"easeOutBack"
    });


    btn.onclick = ()=>{
        timeline.play();
    }

在这里插入图片描述
timeline.add( animeConfig, timelineOffset )

animeConfig:本质上就前面介绍的那一大堆
timelineOffset:时间线偏移,比如说,你希望你的某一段动画,在指定的时间执行,那么这里填入具体执行的数字即可,如果你希望你的动画提前或延后一段时间执行,那么,只需要填入字符串表达式即可,如 : “-=500” (提前0.5秒执行)

动画控制

前面讲到了autoplay时,我们其实就已经用了一个动画控制

anime.play(); 就可以控制动画的播放

anime.pause(); 就可以控制动画的暂停,暂停后再使用 play(); 即可从暂停位置继续播放动画

但是要注意,animejs中没有停止,如果你希望停止动画并让动画恢复到原位,需要你调整动画的时间位置

anime.restart() 重播,执行重播后,动画将从第0秒第一帧开始播放

anime.reverse(); 让动画反向播放,这里和动画配置里的direction:reverse 功能一样,但是,使用函数可以更有效的控制动画的正向反向播放

anime.seek( time ) 让动画播放到指定的时间,比如说,我当前动画是10秒,那么,我anime.seek(5000),就可以让动画切换到第5秒的位置

上述属性对timeline均有效

回调函数

    let anime1 = anime({
        targets:"#d1",
        left:500,
        autoplay:false,
        delay:500,
        endDelay:500,
        loop:5,
        begin:()=>{ //动画开始前执行,在delay之前
            index ++;
            console.log(index + " begin");
        },
        update:()=>{
            //动画每执行一帧执行一次
        },
        loopBegin:()=>{//循环开始前执行
            index ++;
            console.log(index + " loopBegin");
        },
        loopComplete: ()=>{//一轮循环结束后执行
            index ++;
            console.log(index + " loopComplete");
        },
        complete:()=>{
            index ++;
            console.log(index + " complete");
        },
        change:()=>{
            //动画每变化一次执行一次
        },
        changeBegin:()=>{//变化开始前执行
            index ++;
            console.log(index + " changeBegin");
        },
        changeComplete: ()=>{//变化结束后执行
            index ++;
            console.log(index + " changeComplete");
        }
    });


    btn.onclick = ()=>{
        anime1.play();
    }

在这里插入图片描述

除去两个执行频率特别高的,我打印了执行五次循环的一段动画的生命周期

begin 在动画的延迟时间之前,一般用于执行一些动画开始前的代码

loopBegin 是在每一轮循环的开始之前,一般用于动画循环过程中的监听
loopComplete是在每一轮循环播放结束后,同上,但是该函数主要在循环结束时执行

changeComplete是在每次动画目标数据变化结束时执行,会跟在loopComplete后面执行,即使没有循环它也会在动画播放完成后执行,主要用于动画结束后执行下一段脚本时使用

complete会在动画全部执行完毕时执行,若loop设置为true时,则不执行,同上

一般来说我们常用的就是update和change

比如说在threejs中,相机飞入动画
我们不仅要控制相机移动,我们还需要让相机每一帧都看向指定的目标,所以这个时候,update或者change函数就用得上了,我们可以用这两属性监听相机,每次相机变化就让它lookAt一下目标,这样就能实现流畅平滑的动画了,这个案例在上方有写

结语

到此为止,animejs的基础教程就结束了

部分animejs的内容比较绕,需要你多写代码才能够感受到,尤其是时间线的部分

animejs特别适合与threejs,pixijs等webgl框架搭配使用,如果你在学习threejs的话,那么笔者强烈推荐你学习一下animejs

animejs有很多高级用法,这里笔者并未提及,如官方文档中的helper,svg动画,函数参数等,这些由于笔者并未使用过,所以并未将这些内容写出,若需要使用到这些功能时,请参阅官方文档

animejs唯一指定官方文档

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 我推荐一个在OCR领域非常受欢迎的:Tesseract OCR。Tesseract是一个开源的OCR引擎,拥有高准确率和识别多种语言的能力。它在计算机视觉领域有着广泛的应用,并且被许多大型公司所采用,比如Google和HP。如果你需要一个功能强大,稳定可靠的OCR,那么Tesseract是一个不错的选择。 ### 回答2: 推荐一个OCR最好的有:Tesseract OCR。 Tesseract OCR是一个开源的OCR引擎,由Google开发和维护。它支持多种语言,并且能够识别多种文本格式,如印刷体和手写体。Tesseract OCR具有高度可定制性,能够根据不同的需求进行优化和配置。 Tesseract OCR提供了简单易用的命令行接口,也可以通过API集成到各种编程语言中,如Python、Java和C++等。它具有丰富的功能,包括自动文本方向检测、图像预处理、字典补全等。另外,Tesseract OCR还支持训练自定义模型,以提高特定领域的识别能力。 Tesseract OCR在OCR领域享有很高的声誉,被广泛应用于文档识别、图书数字化、车牌识别等各种场景。它的准确度和性能已经得到了很多用户的认可和肯定。 综上所述,推荐使用Tesseract OCR作为OCR引擎,它是一个功能强大、性能优异的,可以满足大部分OCR需求。 ### 回答3: 推荐一个最好的OCR是Tesseract。Tesseract是一个非常流行和功能强大的OCR引擎,可以将图片中的文本转换成可编辑的文本。Tesseract具有许多优点,首先它是一个开源,可以免费使用和修改。其次,Tesseract在文字识别方面表现出色,准确度较高,特别是针对印刷体文字。它可以处理多种语言,并且支持多种输出格式,如文本文件、HTML和PDF等。此外,Tesseract还可以处理多种图像格式,包括JPEG、PNG和TIFF等。Tesseract还有一个活跃的开发社区,用户可以从中获取最新的技术支持和更新。使用Tesseract的API也非常简单,可以通过多种编程语言进行集成,如Python、Java和C++等。总的来说,如果你正在寻找一个功能强大、准确度高并且易于使用的OCR,Tesseract是一个很好的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值