美文网首页优美编程
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