总会遇到一篇对的文章,能够和之前的积累产生化学反应。
单纯的学数学有些枯燥,但从canvas动画入手,便有一些意思了,在网上发现一些效果,是用原生js写的,让我对数学的应用有了全新的认识。
以前站在数学的规则之中,感觉到的是拥挤,现在站在它的上面,感受到了它的井井有条!
特效原地址:https://www.html5tricks.com/jquery-button-hover-animation.html 向前辈致敬!
我基于它做了一些改变,将其中的一部分重现在codepen上,页面分为上下两块 上面的部分是程序可变的量,能控制动画的展现方式,下面是canvas画布,用来展现,基于iview、vue编写。
image.png
首先我们从第一个效果入手,整体看一下流程
codepen 地址
https://codepen.io/xiaodun/pen/WagBLR
在mounted钩子中,会动态为canvas的长高赋值,并监听了窗口改变的事件。
this.canvasDom = document.getElementById("effect-id");
this.headerDom = document.getElementById("header-id");
this.pen = this.canvasDom.getContext("2d");
var computed = ()=>{
let headerDomComputedStyle = window.getComputedStyle(this.headerDom);
let width = window.innerWidth;
let height = window.innerHeight - ( parseInt(headerDomComputedStyle.height) || 0)
this.canvasDom.setAttribute("width",width-2*this.borderWidth)
this.canvasDom.setAttribute("height",height-2*this.borderWidth)
this.width = width;
this.height = height;
}
computed();
window.addEventListener('resize',computed);
因为使用css控制canvas的width、height是不行的,使用flex计划失败。
这里还有一个坑,iview的Slider组件出现了margin导致的父元素高度问题,获取头部的高度获取不到那一部分,但它真实存在,最后只能
.ivu-slider::before,.ivu-slider::after{
display:table;
content:"";
}
动画都是基于鼠标进入,鼠标移动,鼠标离开这三个过程。主要逻辑都在start函数里进行,mouse_enter会做一些初始化的工作。
在动画开始之前填充元素
if(this.isStart && this.data.length == 0){
for(var i=0;i<this.height/5;i++) {
this.data.push({
x:Math.pow(-1,i) * this.width,
y:5 * i,
w:this.width,
h:5
})
}
}
this.isStart 在鼠标进入时为true,鼠标离开时为false,this.data用来存储动画执行所需要的数据,this.width是画布的宽度,this.height是画布的高度。
这里是为了生成两种类型的矩形数据,一类数据从-this.width开始画,一类从this.width开始画,注意他们的长度和高度是一样的
for(let i=0;i<this.data.length;i++){
let item = this.data[i];
if(this.isStart){
item.x -= item.x / 14;
}
else{
if(i % 2 === 0){
// item.x -= Math.floor((item.x + this.width)/14)
item.x -= Math.ceil((item.x + this.width)/14)
}
else{
item.x += Math.floor((this.width - item.x) / 14);
}
}
this.pen.fillRect(item.x,item.y,this.width,item.h);
}
鼠标进入时只执行
item.x -= item.x / 14;就可以了,因为从左边开始的 item.x小于0=>item.x/14小于0,减去一个小于0的数相当于加上。随着Math.abs(item.x)的越来越小,导致越到后面动画越慢,正因为如此,不用加任何判断,矩形也不会运动到边界外,而是无限趋紧于边界
鼠标离开时,是动画的一个反向进行,i % 2 === 0 从右往左运动的方块,随着item.x 负的越来越多item.x + this.width越来越小,无限趋近于-this.width,这里使用ceil是使得矩形更块的运动,这里使用floor是不行的,会变成减去0,下面不使用ceil是为了防止加上0
从鼠标移入到移除,位置在-this.width位置的矩形一直在向右运动,位置在this.width位置的矩形一直在向左运动
这也是为什么使用if(i % 2 === 0) 来区分,而不是通过大于0还是小于0来判断。
不看代码是不是很难感知
有时候,我们并非看到整个动画的全部,或者动画不是向我们常理认为的那样运行
item.x + this.width 、 this.width - item.x这种逆向思维的运用更是简化了实现
还有一点,因为人类对于态物体的认知,可能会带有一些附加效果,比如鼠标进入时,无限接近边界时是没什么感觉的,但是撤离时就感觉怪怪的,其实逻辑是一样的。
改变一些地方的实现,就会看到不同的动画!
收尾
if(this.isStart || this.data[0].x > -this.width){
requestAnimationFrame(()=>{
this.start();
})
}
else{
this.data = [];
this.pen.clearRect(0,0,this.width,this.height)
}
this.data[0].x > -this.width 鼠标移开,动画继续进行的关键。
网友评论