zoukankan      html  css  js  c++  java
  • canvas 实现简单的粒子运动效果

    实现效果如下

    canvas粒子演示

    设计思路

    1.初始化画布

    2.再自定义创建80个圆点(数量可自定义),然后初始化

    3.然后实现是在一定距离范围内的圆点两两相连,并且运动起来

    4.然后实现鼠标移进出现圆点与里面的圆点能相连

    设计方法

    1.初始化画布

    // 初始化画布
            let ele = document.getElementById('my_canvas');
            ele.width = ele.offsetWidth;
            ele.height = ele.offsetHeight;
            let ctx = ele.getContext('2d');

    2.创建圆与连线(使用构造函数,封装所有的方法与属性)

    function random(min,max){
                return min+Math.random()*(max-min);
            }
    
    // 创建圆(构造器函数)
            function circle(x,y){
                this.x=x;
                this.y=y;
                this.radius=random(.8,4);
                // 偏移
                this.speed_x=random(-1,1);
                this.speed_y=random(-1,1);
    
                // 移动
                this.move=function (width,height){
                    this.speed_x=(this.x<width && this.x>0)?this.speed_x:(-this.speed_x);
                    this.speed_y=(this.y<width && this.y>0)?this.speed_y:(-this.speed_y);
                    this.x+=this.speed_x;
                    this.y+=this.speed_y;
                }
    
                // 画圆
                this.drawCircle=function (ctx){
                    ctx.beginPath();
                    ctx.fillStyle=`rgba(${random(0,255)},${random(0,255)},${random(0,255)},.6)`  
                    ctx.arc(this.x,this.y,this.radius,0,360);
                    ctx.fill(); 
                }
    
                // 画连线
                this.drawLine=function(ctx,_circle){
                    let dx=this.x-_circle.x;
                    let dy=this.y-_circle.y;
                    let d=Math.sqrt( Math.pow(dx,2) + Math.pow(dy,2) );
                    // 勾股定理求距离
                    if(d<120){
                        ctx.beginPath();
                        ctx.moveTo(this.x,this.y);
                        ctx.lineTo(_circle.x,_circle.y);
                        ctx.strokeStyle='rgba(201, 201, 201, 0.5)';
                        ctx.stroke();
                    }             
                }
            }

    3. 创建80个点,将其初始化,放进数组存储,以便移动是可以利用(初始化之后,要调用draw方法绘制画面)

    // 创建圆点集合数组
            let circles=[];
            let circleCount=80;
    // 初始化circleCount个圆
            function init(){
                for(let i=0;i<circleCount;i++){
                    circles.push(new circle(random(0,ele.width),random(0,ele.height)));
                }
                draw();
            }
            init();
    

    4.在画布上绘制出下面静态的画面

    代码如下

     // 通过调用draw()方法,实现每一次80个点的位置的变化(看似实在运动)
            function draw(){
                // 清空上一次的画布
                ctx.clearRect(0,0,ele.width,ele.height);
            
                for(let i=0;i<circles.length;i++){
                    circles[i].move(ele.width,ele.height);
                    circles[i].drawCircle(ctx);
                    for(let j=i+1;j<circles.length;j++){
                        circles[i].drawLine(ctx,circles[j]);
                    }
                }
    }

    5.实现圆点的自由运动

    上面的代码,是静态的画面(默认draw方法只执行一次),所以只能我们通过手动点击刷新来改变位置

    若想自动更新,可以通过计时器主要是采用requestAnimationFrame来代替setInterval

    下面的这段代码(适用于不同浏览器,解决了一些浏览器没有requestAnimationFrame这个方法

    1  window.requestAnimationFrame = window.requestAnimationFrame 
    2                                         || window.mozRequestAnimationFrame 
    3                                         || window.webkitRequestAnimationFrame 
    4                                         || window.msRequestAnimationFrame
    5                                         || function(callback){
    6                                             setInterval(callback,16.7)
    7                                             };

    从上面的代码,我们可以引申出一个名词,叫做垫片(polyfill)->适配不同的浏览器缺少某个方法的一段算法 这段代码的作用就是解决一些浏览器没有requestAnimationFrame这个方法,

    像这样的一段算法,或者说代码,是有名词来称呼它的叫做 垫片(polyfill)

    该如何使用这个requestAnimationFrame呢??(注:红字为使用方法)

     function draw(){
                ctx.clearRect(0,0,ele.width,ele.height);
            
                for(let i=0;i<circles.length;i++){
                    circles[i].move(ele.width,ele.height);
                    circles[i].drawCircle(ctx);
                    for(let j=i+1;j<circles.length;j++){
                        circles[i].drawLine(ctx,circles[j]);
                    }
                }
               
                requestAnimationFrame(draw);
            }

    6. 实现上面例子中用鼠标移进的效果

     构造出鼠标实时位置画圆点的函数

     
    function currentCircle(x,y){ circle.call(this,x,y) this.drawCircle=function (ctx){ ctx.beginPath(); ctx.arc(this.x,this.y,this.radius,0,360); ctx.fillStyle='rgba(255,255,255,0)'; ctx.fill(); } }

      注: 其中的circle.call(this,x,y)的代码call的第一个参数中是this,由于我们使用let currentPoint=new currentCircle(0,0)

          所以this绑定在currentPoint这个对象身上,假设没有new这个关键字,那么1这个this指向的就是window(在非严格模式下)。

       call 是能够改变this指向,表示了this的值从一个环境传到另一个环境。而将一个对象作为call的第一个参数,则this将绑定这个对象,也就是currentCircle;其他参数为传参。

       因此,我们可以理解成把circle函数的所有方法和属性,用到的this都是 currentCircle的方法和属性。

    例子

          var a=7;
    	  var obj={
    		  a:4
    	  }
    	  function test(){
    		  return this.a;
    	  }
    	  test() // 结果 7
    	  test.call(obj) // 结果4 

    获取鼠标实时的位置

    代码如下:

    // 初始化鼠标的位置 (这个是对象)
    let currentPoint=new currentCircle(0,0);
    
    // 鼠标移进
     window.onmousemove= function (event){
          let e = event|| window.event;
          let scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
          let scrollY = document.documentElement.scrollTop || document.body.scrollTop;
     // 鼠标的坐标(实时改变)
          currentPoint.x = e.pageX || e.clientX + scrollX;
          currentPoint.y= e.pageY || e.clientY + scrollY;  
       }
       // 鼠标移出
      window.onmouseout = function() {
         currentPoint.x = null;
         currentPoint.y = null;
       }

    draw绘制出鼠标的效果

    function draw(){
                // 清空上一次的画布
                ctx.clearRect(0,0,ele.width,ele.height);
            
                for(let i=0;i<circles.length;i++){
                    circles[i].move(ele.width,ele.height);
                    circles[i].drawCircle(ctx);
                    for(let j=i+1;j<circles.length;j++){
                        circles[i].drawLine(ctx,circles[j]);
                    }
                }

    // 表示如果鼠标的位置不为null,就会执行下面的操作
    if(currentPoint.x){ currentPoint.drawCircle(ctx); for(let k=0;k<circles.length;k++){ currentPoint.drawLine(ctx,circles[k]); } } requestAnimationFrame(draw); }

    完整代码如下:

      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4     <meta charset="UTF-8">
      5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
      6     <meta http-equiv="X-UA-Compatible" content="ie=edge">
      7     <title>canvas 粒子特效</title>
      8     
      9 </head>
     10 <body >
     11     <style>
     12         body {
     13             margin: 0;
     14             height: 100%;
     15         }
     16 
     17         canvas {
     18              100%;
     19             height: 100%;
     20             position: absolute;
     21             top: 0px;
     22             left: 0;
     23         }
     24     </style>
     25     <canvas id="my_canvas" width="400" height="400"></canvas>
     26     <script>
     27         // 初始化画布
     28         let ele = document.getElementById('my_canvas');
     29         ele.width = ele.offsetWidth;
     30         ele.height = ele.offsetHeight;
     31         let ctx = ele.getContext('2d');
     32         
     33         // 创建圆点集合数组
     34         let circles=[];
     35         let circleCount=80;
     36         let currentPoint=new currentCircle(0,0);
     37         // 初始化circleCount个圆
     38         function init(){
     39             for(let i=0;i<circleCount;i++){
     40                 circles.push(new circle(random(0,ele.width),random(0,ele.height)));
     41             }
     42             draw();
     43         }
     44         init();
     45 
     46         
     47         window.requestAnimationFrame = window.requestAnimationFrame 
     48                                         || window.mozRequestAnimationFrame 
     49                                         || window.webkitRequestAnimationFrame 
     50                                         || window.msRequestAnimationFrame
     51                                         || function(callback){
     52                                             setInterval(callback,16.7)
     53                                             };
     54 
     55         function random(min,max){
     56             return min+Math.random()*(max-min);
     57         }
     58         
     59         
     60         // 通过调用draw()方法,实现每一次80个点的位置的变化(看似实在运动)
     61         function draw(){
     62             // 清空上一次的画布
     63             ctx.clearRect(0,0,ele.width,ele.height);
     64         
     65             for(let i=0;i<circles.length;i++){
     66                 circles[i].move(ele.width,ele.height);
     67                 circles[i].drawCircle(ctx);
     68                 for(let j=i+1;j<circles.length;j++){
     69                     circles[i].drawLine(ctx,circles[j]);
     70                 }
     71             }
     72             if(currentPoint.x){
     73                 currentPoint.drawCircle(ctx);
     74                 for(let k=0;k<circles.length;k++){
     75                     currentPoint.drawLine(ctx,circles[k]);
     76                 }
     77             }
     78             requestAnimationFrame(draw);
     79         }
     80         // 鼠标移进
     81          window.onmousemove= function (event){
     82             let e = event|| window.event;
     83             let scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
     84             let scrollY = document.documentElement.scrollTop || document.body.scrollTop;
     85             currentPoint.x = e.pageX || e.clientX + scrollX;
     86             currentPoint.y= e.pageY || e.clientY + scrollY;  
     87         }
     88         // 鼠标移出
     89         window.onmouseout = function() {
     90             currentPoint.x = null;
     91             currentPoint.y = null;
     92         }
     93             
     94          
     95         function currentCircle(x,y){
     96            circle.call(this,x,y)
     97            this.drawCircle=function (ctx){
     98                ctx.beginPath();
     99                ctx.arc(this.x,this.y,this.radius,0,360);
    100                ctx.fillStyle='rgba(255,255,255,0)';
    101                ctx.fill();
    102            }
    103         }
    104 
    105         // 创建圆(构造器函数)
    106         function circle(x,y){
    107             this.x=x;
    108             this.y=y;
    109             this.radius=random(.8,4);
    110             // 偏移
    111             this.speed_x=random(-1,1);
    112             this.speed_y=random(-1,1);
    113 
    114             // 移动
    115             this.move=function (width,height){
    116                 this.speed_x=(this.x<width && this.x>0)?this.speed_x:(-this.speed_x);
    117                 this.speed_y=(this.y<width && this.y>0)?this.speed_y:(-this.speed_y);
    118                 this.x+=this.speed_x;
    119                 this.y+=this.speed_y;
    120             }
    121 
    122             // 画圆
    123             this.drawCircle=function (ctx){
    124                 ctx.beginPath();
    125                 ctx.fillStyle=`rgba(${random(0,255)},${random(0,255)},${random(0,255)},.6)`  
    126                 ctx.arc(this.x,this.y,this.radius,0,360);
    127                 ctx.fill(); 
    128             }
    129 
    130             // 画连线
    131             this.drawLine=function(ctx,_circle){
    132                 let dx=this.x-_circle.x;
    133                 let dy=this.y-_circle.y;
    134                 let d=Math.sqrt( Math.pow(dx,2) + Math.pow(dy,2) );
    135                 // 勾股定理求距离
    136                 if(d<120){
    137                     ctx.beginPath();
    138                     ctx.moveTo(this.x,this.y);
    139                     ctx.lineTo(_circle.x,_circle.y);
    140                     ctx.strokeStyle='rgba(201, 201, 201, 0.5)';
    141                     ctx.stroke();
    142                 }             
    143             }
    144         }        
    145 </script>
    146 </body>
    147 </html>
    View Code
  • 相关阅读:
    keras_12_keras自带的Applications
    keras_11_keras中示例数据集
    keras_10_回调函数 Callbacks
    Runloop
    SDWebImage
    NSOperation
    单例模式
    GCD
    一文读懂汉明码
    聊聊SPOOLing技术
  • 原文地址:https://www.cnblogs.com/Jeanchjy/p/12559130.html
Copyright © 2011-2022 走看看