text: /**
   * @author https://github.com/chengquan223
   * @Date 2017-02-16
   */
  (function () {
      //全局变量
      var canvas, ctx, w, h, centerX, centerY;
      var imgOut = document.createElement('img'),
          imgIn = document.createElement('img');
      imgOut.src = 'https://zos.alipayobjects.com/rmsportal/JorDDgUVJljaIxDBpiBM.png';
      imgIn.src = 'https://zos.alipayobjects.com/rmsportal/uIbqAshSeUuRPrRXNOrN.png';
  
      var initCanvas = function () {
          canvas = document.createElement('canvas');
          ctx = canvas.getContext('2d');
          w = canvas.width = document.body.clientWidth;
          h = canvas.height = 560;
          centerX = w / 2;
          centerY = h / 2;
          canvas.id = 'myCanvas';
          document.getElementById('canvasWrapper').appendChild(canvas);
      };
  
      function Circle(x, y, r) {
          this.x = x;
          this.y = y;
          this.r = r;
      }
  
      Circle.prototype = {
          draw: function () {
              ctx.save();
              ctx.lineWidth = '.6';
              ctx.strokeStyle = '#2123C0';
              ctx.beginPath();
              ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
              ctx.stroke();
              ctx.restore();
          },
          birthPoint: function (isLeft) {
              var angle = 180;
              if (isLeft) {
                  angle = -angle;
              }
              angle = Math.floor(Math.random() * +angle);
              return {
                  x: Math.floor(this.x + Math.sin(angle * Math.PI / 180) * (this.r + (Math.random() * 15) + 5)),
                  y: Math.floor(this.y + Math.cos(angle * Math.PI / 180) * (this.r + (Math.random() * 15) + 5))
              };
          }
      };
  
      function Point(x, y) {
          this.x = x;
          this.y = y;
          this.size = Math.random() * 5 + 7;
          this.opacity = Math.random() * 0.25 + 0.1;
          this.t = 0;
          this.interval = Math.random() * 0.2 + 0.01;
          // this.d = Math.floor(Math.random() * 300 + 100);
          this.isRun = true;
      }
  
      Point.prototype = {
          draw: function () {
              ctx.save();
              ctx.globalAlpha = this.opacity;
              ctx.translate(this.x, this.y);
              ctx.rotate(0 * Math.PI / 180);
              ctx.drawImage(imgOut, -this.size / 2, -this.size / 2, this.size, this.size); //用图片代替粒子，效率更高
              ctx.restore();
          },
          relive: function () {
              var radius = pointLayer.circle.r,
                  distance = 220,
                  gap = 20,
                  x = Math.floor(Math.random() * ((centerX - radius - gap) - (centerX - radius - gap - distance)) + centerX - radius - gap - distance),
                  y = Math.floor(Math.random() * ((centerY + 5) - (centerY - 10)) + centerY - 10);
              if (Math.random() > 0.5) {
                  x = Math.floor(Math.random() * ((centerX + radius + gap + distance) - (centerX + radius + gap)) + centerX + radius + gap);
              }
              return new Point(x, y);
          }
      };
  
      function Wave() {
          this.width = w;
          this.height = 150;
          this.K = 2;
          this.F = 3;
          this.MAX = (this.height / 2) - 4;
          this.noise = Math.min(50, 1) * this.MAX;
      }
  
      Wave.prototype = {
          _createLines: function () {
              var lines = this.lines = [],
                  noise = Math.min(50, 1) * this.MAX;
              lines.push({
                  phase: 25,
                  speed: 0.045,
                  attenuation: 3.8,
                  color: 'rgba(103,174,245,.75)',
                  width: .55,
                  distance: 0
              }, {
                  phase: 5,
                  speed: 0.035,
                  attenuation: 8,
                  color: 'rgba(132,219,86,.65)',
                  width: .45,
                  distance: 30
              }, {
                  phase: 140,
                  speed: 0.045,
                  attenuation: 3.5,
                  color: 'rgba(140,87,255,.85)',
                  width: .55,
                  distance: 140
              }, {
                  phase: 160,
                  speed: 0.045,
                  attenuation: 4.5,
                  color: 'rgba(245,139,192,0.71)',
                  width: .55,
                  distance: 40
              });
          },
          _globalAttenuationFn: function (x) {
              return Math.pow(this.K * 4 / (this.K * 4 + Math.pow(x, 4)), this.K * 4);
          },
          _draw: function (line) {
              line.phase = (line.phase + line.speed) % (Math.PI * 64);
              ctx.moveTo(100, 0);
              ctx.beginPath();
              ctx.save();
              ctx.strokeStyle = line.color;
              ctx.lineWidth = line.width || .1;
              var x, y;
              for (var i = -this.K; i <= this.K; i += 0.03) {
                  x = Math.floor(this.width * ((i + this.K) / (this.K * 4)) + w / 4);
                  y = Math.floor(h / 2 + this.noise * this._globalAttenuationFn(i) * (1 / line.attenuation) * Math.sin(this.F * i - line.phase));
                  ctx.lineTo(x, y);
              }
              ctx.stroke();
              ctx.restore();
          },
          render: function () {
              var self = this;
              self.lines.forEach(function (line) {
                  self._draw(line);
              });
          },
          start: function () {
              this._createLines();
          }
      };
  
      var Tween = {
          Quad: {
              easeIn: function (t, b, c, d) {
                  return c * (t /= d) * t + b;
              },
              easeOut: function (t, b, c, d) {
                  return -c * (t /= d) * (t - 2) + b;
              },
              easeInOut: function (t, b, c, d) {
                  if ((t /= d / 2) < 1) return c / 2 * t * t + b;
                  return -c / 2 * ((--t) * (t - 2) - 1) + b;
              }
          },
          Cubic: {
              easeIn: function (t, b, c, d) {
                  return c * (t /= d) * t * t + b;
              },
              easeOut: function (t, b, c, d) {
                  return c * ((t = t / d - 1) * t * t + 1) + b;
              },
              easeInOut: function (t, b, c, d) {
                  if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
                  return c / 2 * ((t -= 2) * t * t + 2) + b;
              }
          },
          Quart: {
              easeIn: function (t, b, c, d) {
                  return c * (t /= d) * t * t * t + b;
              },
              easeOut: function (t, b, c, d) {
                  return -c * ((t = t / d - 1) * t * t * t - 1) + b;
              },
              easeInOut: function (t, b, c, d) {
                  if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
                  return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
              }
          },
      };
  
      //运动点层
      var pointLayer = {
          init: function () {
              var points = this.points = [];
              this.circle = new Circle(w / 2, h / 2, 100);
              for (var i = 0; i < 200; i++) {
                  var random = Math.floor(Math.random() * ((w / 2 + w / 4) - (w / 2 - w / 4)) + (w / 2 - w / 4)),
                      point = new Point(random, centerY),
                      isLeft = random < this.circle.x,
                      endPoint = this.circle.birthPoint(isLeft);
                  point.ex = endPoint.x;
                  point.ey = endPoint.y;
                  point.d = Math.random() * 100 + 50;
                  // point.d = Math.floor(Math.sqrt(Math.pow((point.x - point.ex), 2) + Math.pow((point.y - point.ey), 2)));
                  points.push(point);
              }
          },
          render: function () {
              var self = this;
              var points = self.points;
  
              points.forEach(function (point, i) {
                  //1.刚进页面，满足isRun=true、透明度<0.8
                  //2.当透明度>=0.8时,开始运动，当运动时间t>=d时，设置为isRun=false，
                  //3.当isRun=false时，逐渐降低透明度至0，当透明度<0时。复活粒子
                  if (point.isRun && point.opacity < 0.8) {
                      point.draw();
                      point.opacity += point.interval;
                      // point.opacity += 0.035;
                      return;
                  }
                  if (point.isRun && point.opacity >= 0.8) {
                      point.x = Tween.Cubic.easeInOut(point.t, point.x, point.ex - point.x, point.d);
                      point.y = Tween.Cubic.easeInOut(point.t, point.y, point.ey - point.y, point.d);
                      point.draw();
                      if (point.t < point.d) {
                          point.t++;
                          if (point.x === point.ex && point.y === point.ey) {
                              point.isRun = false;
                          }
                      } else {
                          point.isRun = false;
                      }
                  }
                  if (!point.isRun && point.opacity > 0) {
                      point.draw();
                      point.opacity -= 0.05;
                      return;
                  }
                  if (!point.isRun && point.opacity < 0) {
                      var point = point.relive();
                      var isLeft = point.x < self.circle.x;
                      var endPoint = self.circle.birthPoint(isLeft);
                      point.ex = endPoint.x;
                      point.ey = endPoint.y;
                      point.d = Math.sqrt(Math.pow((point.x - point.ex), 2) + Math.pow((point.y - point.ey), 2));
                      points.splice(i, 1, point);
                  }
              });
          }
      };
  
      //背景层
      var bgLayer = {
          init: function () {
              var dataList = [{
                  type: 'out', //外层圆
                  count: 80, //粒子数目
                  interval: 5, //粒子间隔
                  radiusList: [100, 102, 104, 105, 106, 107, 108, 115, 122, 129, 136]
              }, {
                  type: 'in', //内层圆
                  count: 60,
                  interval: 8,
                  radiusList: [40, 45, 50, 55, 60, 65, 70, 75]
              }, {
                  type: 'highlight', //高亮
                  count: 0,
                  interval: 8,
                  radiusList: [40, 45, 50, 55, 60, 65, 70, 75]
              }];
              this.circles = circles = [];
              dataList.forEach(function (data) {
                  data.radiusList.forEach(function (radius, index) {
                      var circle = new Circle(centerX, centerY, radius);
                      circle.type = data.type;
                      circle.lineWidth = Math.random() * 0.9 + 1.6;
                      circle.radian = Math.PI / Math.random();
                      circle.radianNum = Math.random() * 3 + 3;
                      circle.runSpeed = Math.random() * 0.02 + 0.005;
                      circle.interval = Math.random() * 0.1 + 0.05;
                      circle.particles = (function () {
                          var particles = [];
                          for (var i = 0; i < data.count - data.interval * index; i++) {
                              particles.push({
                                  angle: Math.floor(Math.random() * 360),
                                  size: Math.random() * 5 + 7,
                                  opacity: Math.random()
                              });
                          }
                          return particles;
                      }());
                      circles.push(circle);
                  });
              });
          },
          render: function () {
              this._drawCircle();
              this._drawParticle();
              this._drawBar();
          },
          _drawCircle: function () {
              this.circles.forEach(function (circle) {
                  var shadowColor = 'rgba(0,0,255,1)';
                  if (circle.type && circle.type === 'in') {
                      shadowColor = 'rgba(42,97,0,.4)';
                  }
                  ctx.save();
                  ctx.beginPath();
                  ctx.lineWidth = 1.2;
                  ctx.strokeStyle = 'rgba(19,6,67,.6)';
                  ctx.shadowColor = shadowColor;
                  ctx.shadowBlur = 15;
                  ctx.globalAlpha = 0.75;
                  ctx.arc(centerX, centerY, circle.r, 0, Math.PI * 2);
                  ctx.stroke();
                  ctx.closePath();
                  ctx.restore();
              });
          },
          _drawParticle: function () {
              this.circles.forEach(function (circle) {
                  var img = imgOut;
                  if (circle.type && circle.type === 'in') {
                      img = imgIn;
                  }
                  circle.particles.forEach(function (particle) {
                      var _x = circle.r * Math.cos(particle.angle * (Math.PI / 180)) + centerX;
                      var _y = circle.r * Math.sin(particle.angle * (Math.PI / 180)) + centerY;
                      ctx.save();
                      ctx.globalAlpha = particle.opacity;
                      ctx.translate(_x, _y);
                      ctx.rotate(particle.angle * Math.PI / 180);
                      ctx.drawImage(img, -particle.size / 2, -particle.size / 2, particle.size, particle.size); //用图片代替粒子，效率更高
                      ctx.restore();
                      particle.angle += circle.interval;
                  });
              });
          },
          _drawBar: function () {
              this.circles.forEach(function (circle) {
                  if (circle.type && circle.type === 'in' || circle.type && circle.type === 'highlight') {
                      ctx.save();
                      ctx.beginPath();
                      ctx.globalCompositeOperation = 'lighter';
                      ctx.lineWidth = circle.lineWidth;
                      ctx.strokeStyle = 'rgba(58,255,255,.7)';
                      ctx.arc(centerX, centerY, circle.r, circle.radian, circle.radian + Math.PI / circle.radianNum);
                      ctx.stroke();
                      ctx.restore();
                      circle.radian += circle.runSpeed;
                  }
              });
          },
          fillCenterCircle: function () {
              ctx.save();
              ctx.beginPath();
              ctx.fillStyle = '#050510';
              ctx.arc(centerX, centerY, 42, 0, Math.PI * 2);
              ctx.fill();
              ctx.restore();
          }
      };
  
      (function () {
          'use strict';
  
          var vendors = ['webkit', 'moz'];
          for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
              var vp = vendors[i];
              window.requestAnimationFrame = window[vp + 'RequestAnimationFrame'];
              window.cancelAnimationFrame = window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame'];
          }
          if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy
              ||
              !window.requestAnimationFrame || !window.cancelAnimationFrame) {
              var lastTime = 0;
              window.requestAnimationFrame = function (callback) {
                  var now = Date.now();
                  var nextTime = Math.max(lastTime + 16, now);
                  return setTimeout(function () {
                      callback(lastTime = nextTime);
                  }, nextTime - now);
              };
              window.cancelAnimationFrame = clearTimeout;
          }
      })();
  
      var init = function () {
          initCanvas();
          pointLayer.init();
          wave = new Wave();
          wave.start();
          bgLayer.init();
      }
  
      var renderLoop = function () {
          ctx.clearRect(0, 0, w, h);
          bgLayer.render();
          wave.render();
          pointLayer.render();
          bgLayer.fillCenterCircle();
      }
  
      init();
  
      (function frame() {
          requestAnimationFrame(frame);
          renderLoop();
      }());
  })();