关于前端:canvas实现炫酷粒子效果以及流星效果

26次阅读

共计 10264 个字符,预计需要花费 26 分钟才能阅读完成。

一:粒子成果

<html>

<head>
  <meta charset="utf-8">
  <title>www.husonghe.com</title>
  <style>
    html {
      height: 100%;
      background-image: -webkit-radial-gradient(ellipse farthest-corner at center center, #1b44e4 0%, #020f3a 100%);
      background-image: radial-gradient(ellipse farthest-corner at center center, #1b44e4 0%, #020f3a 100%);
      cursor: move;
    }

    body {
      width: 100%;
      margin: 0;
      overflow: hidden;
    }
  </style>
</head>

<body>


  <canvas id="canv" width="1920" height="572"></canvas>
  <script>
    var num = 200;
    var w = window.innerWidth;
    var h = window.innerHeight;
    var max = 100;
    var _x = 0;
    var _y = 0;
    var _z = 150;
    var dtr = function (d) {return d * Math.PI / 180;};

    var rnd = function () {return Math.sin(Math.floor(Math.random() * 360) * Math.PI / 180);
    };
    var dist = function (p1, p2, p3) {return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2) + Math.pow(p2.z - p1.z, 2));
    };

    var cam = {
      obj: {
        x: _x,
        y: _y,
        z: _z
      },
      dest: {
        x: 0,
        y: 0,
        z: 1
      },
      dist: {
        x: 0,
        y: 0,
        z: 200
      },
      ang: {
        cplane: 0,
        splane: 0,
        ctheta: 0,
        stheta: 0
      },
      zoom: 1,
      disp: {
        x: w / 2,
        y: h / 2,
        z: 0
      },
      upd: function () {
        cam.dist.x = cam.dest.x - cam.obj.x;
        cam.dist.y = cam.dest.y - cam.obj.y;
        cam.dist.z = cam.dest.z - cam.obj.z;
        cam.ang.cplane = -cam.dist.z / Math.sqrt(cam.dist.x * cam.dist.x + cam.dist.z * cam.dist.z);
        cam.ang.splane = cam.dist.x / Math.sqrt(cam.dist.x * cam.dist.x + cam.dist.z * cam.dist.z);
        cam.ang.ctheta = Math.sqrt(cam.dist.x * cam.dist.x + cam.dist.z * cam.dist.z) / Math.sqrt(cam.dist.x * cam.dist.x + cam.dist.y * cam.dist.y + cam.dist.z * cam.dist.z);
        cam.ang.stheta = -cam.dist.y / Math.sqrt(cam.dist.x * cam.dist.x + cam.dist.y * cam.dist.y + cam.dist.z * cam.dist.z);
      }
    };

    var trans = {
      parts: {sz: function (p, sz) {
          return {
            x: p.x * sz.x,
            y: p.y * sz.y,
            z: p.z * sz.z
          };
        },
        rot: {x: function (p, rot) {
            return {
              x: p.x,
              y: p.y * Math.cos(dtr(rot.x)) - p.z * Math.sin(dtr(rot.x)),
              z: p.y * Math.sin(dtr(rot.x)) + p.z * Math.cos(dtr(rot.x))
            };
          },
          y: function (p, rot) {
            return {x: p.x * Math.cos(dtr(rot.y)) + p.z * Math.sin(dtr(rot.y)),
              y: p.y,
              z: -p.x * Math.sin(dtr(rot.y)) + p.z * Math.cos(dtr(rot.y))
            };
          },
          z: function (p, rot) {
            return {x: p.x * Math.cos(dtr(rot.z)) - p.y * Math.sin(dtr(rot.z)),
              y: p.x * Math.sin(dtr(rot.z)) + p.y * Math.cos(dtr(rot.z)),
              z: p.z
            };
          }
        },
        pos: function (p, pos) {
          return {
            x: p.x + pos.x,
            y: p.y + pos.y,
            z: p.z + pos.z
          };
        }
      },
      pov: {plane: function (p) {
          return {
            x: p.x * cam.ang.cplane + p.z * cam.ang.splane,
            y: p.y,
            z: p.x * -cam.ang.splane + p.z * cam.ang.cplane
          };
        },
        theta: function (p) {
          return {
            x: p.x,
            y: p.y * cam.ang.ctheta - p.z * cam.ang.stheta,
            z: p.y * cam.ang.stheta + p.z * cam.ang.ctheta
          };
        },
        set: function (p) {
          return {
            x: p.x - cam.obj.x,
            y: p.y - cam.obj.y,
            z: p.z - cam.obj.z
          };
        }
      },
      persp: function (p) {
        return {
          x: p.x * cam.dist.z / p.z * cam.zoom,
          y: p.y * cam.dist.z / p.z * cam.zoom,
          z: p.z * cam.zoom,
          p: cam.dist.z / p.z
        };
      },
      disp: function (p, disp) {
        return {
          x: p.x + disp.x,
          y: -p.y + disp.y,
          z: p.z + disp.z,
          p: p.p
        };
      },
      steps: function (_obj_, sz, rot, pos, disp) {var _args = trans.parts.sz(_obj_, sz);
        _args = trans.parts.rot.x(_args, rot);
        _args = trans.parts.rot.y(_args, rot);
        _args = trans.parts.rot.z(_args, rot);
        _args = trans.parts.pos(_args, pos);
        _args = trans.pov.plane(_args);
        _args = trans.pov.theta(_args);
        _args = trans.pov.set(_args);
        _args = trans.persp(_args);
        _args = trans.disp(_args, disp);
        return _args;
      }
    };

    (function () {
      "use strict";
      var threeD = function (param) {this.transIn = {};
        this.transOut = {};
        this.transIn.vtx = (param.vtx);
        this.transIn.sz = (param.sz);
        this.transIn.rot = (param.rot);
        this.transIn.pos = (param.pos);
      };

      threeD.prototype.vupd = function () {
        this.transOut = trans.steps(

          this.transIn.vtx,
          this.transIn.sz,
          this.transIn.rot,
          this.transIn.pos,
          cam.disp
        );
      };

      var Build = function () {
        this.vel = 0.04;
        this.lim = 360;
        this.diff = 200;
        this.initPos = 100;
        this.toX = _x;
        this.toY = _y;
        this.go();};

      Build.prototype.go = function () {this.canvas = document.getElementById("canv");
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight;
        this.$ = canv.getContext("2d");
        this.$.globalCompositeOperation = 'source-over';
        this.varr = [];
        this.dist = [];
        this.calc = [];

        for (var i = 0, len = num; i < len; i++) {this.add();
        }

        this.rotObj = {
          x: 0,
          y: 0,
          z: 0
        };
        this.objSz = {
          x: w / 5,
          y: h / 5,
          z: w / 5
        };
      };

      Build.prototype.add = function () {
        this.varr.push(new threeD({
          vtx: {x: rnd(),
            y: rnd(),
            z: rnd()},
          sz: {
            x: 0,
            y: 0,
            z: 0
          },
          rot: {
            x: 20,
            y: -20,
            z: 0
          },
          pos: {x: this.diff * Math.sin(360 * Math.random() * Math.PI / 180),
            y: this.diff * Math.sin(360 * Math.random() * Math.PI / 180),
            z: this.diff * Math.sin(360 * Math.random() * Math.PI / 180)
          }
        }));
        this.calc.push({x: 360 * Math.random(),
          y: 360 * Math.random(),
          z: 360 * Math.random()});
      };

      Build.prototype.upd = function () {cam.obj.x += (this.toX - cam.obj.x) * 0.05;
        cam.obj.y += (this.toY - cam.obj.y) * 0.05;
      };

      Build.prototype.draw = function () {this.$.clearRect(0, 0, this.canvas.width, this.canvas.height);
        cam.upd();
        this.rotObj.x += 0.1;
        this.rotObj.y += 0.1;
        this.rotObj.z += 0.1;

        for (var i = 0; i < this.varr.length; i++) {for (var val in this.calc[i]) {if (this.calc[i].hasOwnProperty(val)) {this.calc[i][val] += this.vel;
              if (this.calc[i][val] > this.lim) this.calc[i][val] = 0;
            }
          }

          this.varr[i].transIn.pos = {x: this.diff * Math.cos(this.calc[i].x * Math.PI / 180),
            y: this.diff * Math.sin(this.calc[i].y * Math.PI / 180),
            z: this.diff * Math.sin(this.calc[i].z * Math.PI / 180)
          };
          this.varr[i].transIn.rot = this.rotObj;
          this.varr[i].transIn.sz = this.objSz;
          this.varr[i].vupd();
          if (this.varr[i].transOut.p < 0) continue;
          var g = this.$.createRadialGradient(this.varr[i].transOut.x, this.varr[i].transOut.y, this.varr[i].transOut.p, this.varr[i].transOut.x, this.varr[i].transOut.y, this.varr[i].transOut.p * 2);
          this.$.globalCompositeOperation = 'lighter';
          g.addColorStop(0, 'hsla(255, 255%, 255%, 1)');
          g.addColorStop(.5, 'hsla(' + (i + 2) + ',85%, 40%,1)');
          g.addColorStop(1, 'hsla(' + (i) + ',85%, 40%,.5)');
          this.$.fillStyle = g;
          this.$.beginPath();
          this.$.arc(this.varr[i].transOut.x, this.varr[i].transOut.y, this.varr[i].transOut.p * 2, 0, Math.PI * 2, false);
          this.$.fill();
          this.$.closePath();}
      };
      Build.prototype.anim = function () {window.requestAnimationFrame = (function () {
          return window.requestAnimationFrame ||
            function (callback, element) {window.setTimeout(callback, 1000 / 60);
            };
        })();
        var anim = function () {this.upd();
          this.draw();
          window.requestAnimationFrame(anim);

        }.bind(this);
        window.requestAnimationFrame(anim);
      };

      Build.prototype.run = function () {this.anim();

        window.addEventListener('mousemove', function (e) {this.toX = (e.clientX - this.canvas.width / 2) * -0.8;
          this.toY = (e.clientY - this.canvas.height / 2) * 0.8;
        }.bind(this));
        window.addEventListener('touchmove', function (e) {e.preventDefault();
          this.toX = (e.touches[0].clientX - this.canvas.width / 2) * -0.8;
          this.toY = (e.touches[0].clientY - this.canvas.height / 2) * 0.8;
        }.bind(this));
        window.addEventListener('mousedown', function (e) {for (var i = 0; i < 100; i++) {this.add();
          }
        }.bind(this));
        window.addEventListener('touchstart', function (e) {e.preventDefault();
          for (var i = 0; i < 100; i++) {this.add();
          }
        }.bind(this));
      };
      var app = new Build();
      app.run();})();
    window.addEventListener('resize', function () {
      canvas.width = w = window.innerWidth;
      canvas.height = h = window.innerHeight;
    }, false);
  </script>
</body>

</html>

二:流星成果

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title> 一起来看流星雨 </title>
</head>
<style type="text/css">
  body {background-color: black;}

  body,
  html {
    width: 100%;
    height: 100%;
    overflow: hidden;
  }
</style>

<body>
  <canvas id="stars"></canvas>
</body>

</html>
<script>
  var context;
  var arr = new Array();
  var starCount = 800;
  var rains = new Array();
  var rainCount = 20;
  // 初始化画布及 context
  function init() {
    // 获取 canvas
    var stars = document.getElementById("stars");
    windowWidth = window.innerWidth; // 以后的窗口的高度
    stars.width = windowWidth;
    stars.height = window.innerHeight;
    // 获取 context
    context = stars.getContext("2d");
  }
  // 创立一个星星对象
  var Star = function () {this.x = windowWidth * Math.random();// 横坐标
    this.y = 5000 * Math.random();// 纵坐标
    this.text = ".";// 文本
    this.color = "white";// 色彩
    // 产生随机色彩
    this.getColor = function () {var _r = Math.random();
      if (_r < 0.5) {this.color = "#333";} else {this.color = "white";}
    }
    // 初始化
    this.init = function () {this.getColor();
    }
    // 绘制
    this.draw = function () {
      context.fillStyle = this.color;
      context.fillText(this.text, this.x, this.y);
    }
  }
  // 画月亮
  function drawMoon() {var moon = new Image();
    moon.src = "./images/moon.jpg"
    context.drawImage(moon, -5, -10);
  }
  // 页面加载的时候
  window.onload = function () {init();
    // 画星星
    for (var i = 0; i < starCount; i++) {var star = new Star();
      star.init();
      star.draw();
      arr.push(star);
    }
    // 画流星
    for (var i = 0; i < rainCount; i++) {var rain = new MeteorRain();
      rain.init();
      rain.draw();
      rains.push(rain);
    }
    drawMoon();// 绘制月亮
    playStars();// 绘制闪动的星星
    playRains();// 绘制流星}
  // 星星闪起来
  function playStars() {for (var n = 0; n < starCount; n++) {arr[n].getColor();
      arr[n].draw();}

    setTimeout("playStars()", 100);
  }

  /* 流星雨开始 */
  var MeteorRain = function () {
    this.x = -1;
    this.y = -1;
    this.length = -1;// 长度
    this.angle = 30; // 歪斜角度
    this.width = -1;// 宽度
    this.height = -1;// 高度
    this.speed = 1;// 速度
    this.offset_x = -1;// 横轴挪动偏移量
    this.offset_y = -1;// 纵轴挪动偏移量
    this.alpha = 1; // 透明度
    this.color1 = "";// 流星的色调
    this.color2 = ""; // 流星的色调
    /**************** 初始化函数 ********************/
    this.init = function () // 初始化
    {this.getPos();
      this.alpha = 1;// 透明度
      this.getRandomColor();
      // 最小长度,最大长度
      var x = Math.random() * 80 + 150;
      this.length = Math.ceil(x);
      //         x = Math.random()*10+30;
      this.angle = 30; // 流星倾斜角
      x = Math.random() + 0.5;
      this.speed = Math.ceil(x); // 流星的速度
      var cos = Math.cos(this.angle * 3.14 / 180);
      var sin = Math.sin(this.angle * 3.14 / 180);
      this.width = this.length * cos; // 流星所占宽度
      this.height = this.length * sin;// 流星所占高度
      this.offset_x = this.speed * cos;
      this.offset_y = this.speed * sin;
    }
    /************** 获取随机色彩函数 *****************/
    this.getRandomColor = function () {var a = Math.ceil(255 - 240 * Math.random());
      // 中段色彩
      this.color1 = "rgba(" + a + "," + a + "," + a + ",1)";
      // 完结色彩
      this.color2 = "black";
    }
    /*************** 从新计算流星坐标的函数 ******************/
    this.countPos = function ()//
    {
      // 往左下挪动,x 缩小,y 减少
      this.x = this.x - this.offset_x;
      this.y = this.y + this.offset_y;
    }
    /***************** 获取随机坐标的函数 *****************/
    this.getPos = function () //
    {
      // 横坐标 200--1200
      this.x = Math.random() * window.innerWidth; // 窗口高度
      // 纵坐标小于 600
      this.y = Math.random() * window.innerHeight; // 窗口宽度}
    /**** 绘制流星 ***************************/
    this.draw = function () // 绘制一个流星的函数
    {context.save();
      context.beginPath();
      context.lineWidth = 1; // 宽度
      context.globalAlpha = this.alpha; // 设置透明度
      // 创立横向突变色彩, 终点坐标至起点坐标
      var line = context.createLinearGradient(this.x, this.y,
        this.x + this.width,
        this.y - this.height);
      // 分段设置色彩
      line.addColorStop(0, "white");
      line.addColorStop(0.3, this.color1);
      line.addColorStop(0.6, this.color2);
      context.strokeStyle = line;
      // 终点
      context.moveTo(this.x, this.y);
      // 起点
      context.lineTo(this.x + this.width, this.y - this.height);
      context.closePath();
      context.stroke();
      context.restore();}
    this.move = function () {
      // 清空流星像素
      var x = this.x + this.width - this.offset_x;
      var y = this.y - this.height;
      context.clearRect(x - 3, y - 3, this.offset_x + 5, this.offset_y + 5);
      //         context.strokeStyle="red";
      //         context.strokeRect(x,y-1,this.offset_x+1,this.offset_y+1);
      // 从新计算地位,往左下挪动
      this.countPos();
      // 透明度减少
      this.alpha -= 0.002;
      // 重绘
      this.draw();}
  }
  // 绘制流星
  function playRains() {for (var n = 0; n < rainCount; n++) {var rain = rains[n];
      rain.move();// 挪动
      if (rain.y > window.innerHeight) {// 超出界线后重来
        context.clearRect(rain.x, rain.y - rain.height, rain.width, rain.height);
        rains[n] = new MeteorRain();
        rains[n].init();}
    }
    setTimeout("playRains()", 2);
  }
/* 流星雨完结 */
</script>

正文完
 0