美文网首页优美编程
canvas中的数学0-系列1

canvas中的数学0-系列1

作者: 小遁哥 | 来源:发表于2018-10-29 23:34 被阅读49次

总会遇到一篇对的文章,能够和之前的积累产生化学反应。
单纯的学数学有些枯燥,但从canvas动画入手,便有一些意思了,在网上发现一些效果,是用原生js写的,让我对数学的应用有了全新的认识。
以前站在数学的规则之中,感觉到的是拥挤,现在站在它的上面,感受到了它的井井有条!

特效原地址:https://www.html5tricks.com/jquery-button-hover-animation.html 向前辈致敬!

我基于它做了一些改变,将其中的一部分重现在codepen上,页面分为上下两块 上面的部分是程序可变的量,能控制动画的展现方式,下面是canvas画布,用来展现,基于iview、vue编写。


image.png

首先我们从第一个效果入手,整体看一下流程

codepen 地址
https://codepen.io/xiaodun/pen/WagBLR

image.png

在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 鼠标移开,动画继续进行的关键。

相关文章

网友评论

    本文标题:canvas中的数学0-系列1

    本文链接:https://www.haomeiwen.com/subject/pgumtqtx.html