simplex-noise实现canvas闪电交互动画效果代码

代码语言:html

所属分类:动画

代码描述:simplex-noise实现canvas闪电交互动画效果代码

代码标签: simplex-noise canvas 闪电 交互 动画

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">

  
  
<style>
body {
    font-family: Helvetica sans-serif;
    padding: 0;
    margin: 0;
    background-color: #222;
    overflow: hidden;
    -webkit-user-select: none;
       -moz-user-select: none;
         -o-user-select: none;
        -ms-user-select: none;
            user-select: none;
}

canvas {
    position: absolute;
    top: 0;
    left: 0;
}
</style>

  
  
</head>

<body >
  <canvas id='c'></canvas>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/simplex-noise.js"></script>
      <script>
/**
 * requestAnimationFrame
 */
window.requestAnimationFrame = function () {
  return window.requestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.oRequestAnimationFrame ||
  window.msRequestAnimationFrame ||
  function (callback) {window.setTimeout(callback, 1000 / 60);};
}();


/**
 * Lightning
 */
var Lightning = function (window) {

  /**
   * LightningAbstract
   */
  var LightningAbstract = {
    points: null,
    children: null,
    _simplexNoise: new SimplexNoise(),

    render: function (ctx, controls) {
      this._update(controls);
      this._draw(ctx);
    },

    _update: function (controls) {
      throw new Error('Not override');
    },

    _draw: function (ctx) {
      var points = this.points,
      isRoot = false,opts,
      p,p1,dx,dy,dist,
      lineWidth,
      i,len;

      isRoot = !this.parent;
      opts = isRoot ? this : this.parent;

      if (isRoot) {// is root
        var radius,gradient,
        children = this.children,c;

        ctx.save();
        for (i = 0, len = points.length; i < len; i += len - 1) {
          p = points[i];
          radius = Math.random() * (8 - 3) + 3;
          gradient = ctx.createRadialGradient(p.x, p.y, radius / 3, p.x, p.y, radius);
          gradient.addColorStop(0, this._colorToString(1));
          gradient.addColorStop(1, this._colorToString(0));
          ctx.fillStyle = gradient;
          ctx.beginPath();
          ctx.arc(p.x, p.y, radius, 0, Math.PI * 2, false);
          ctx.fill();
        }
        ctx.restore();

        for (i = 0, len = children.length; i < len; i += len - 1) {
          children[i].render(ctx);
        }
      }

      ctx.save();
      ctx.globalCompositeOperation = 'lighter';
      ctx.lineCap = 'round';
      ctx.fillStyle = 'rgba(0, 0, 0, 1)';
      ctx.shadowBlur = opts.blur;
      ctx.shadowColor = this._colorToString(1);
      ctx.beginPath();
      for (i = 0, len = points.length; i < len; i++) {
        p = points[i];
        if (len > 1) {
          p1 = points[i === len - 1 ? i - 1 : i + 1];
          dx = p.x - p1.x;
          dy = p.y - p1.y;
          dist = Math.sqrt(dx * dx + dy * dy);
        } else {
          dist = 0;
        }
        if (dist > 30) dist = 30;
        ctx.moveTo(p.x + dist, p.y);
        ctx.arc(p.x, p.y, dist, 0, Math.PI * 2, false);
      }
      ctx.fill();
      ctx.restore();

      ctx.save();
      ctx.beginPath();
      ctx.strokeStyle = this._colorToString(Math.random() * (opts.maxAlpha - opts.minAlpha) + opts.minAlpha);
      lineWidth = Math.random() * (opts.maxLineWidth - opts.minLineWidth) + opts.minLineWidth;
      ctx.lineWidth = isRoot ? lineWidth : lineWidth * 0.5;
      for (i = 0; i < len; i++) {
        p = points[i];
        ctx[i === 0 ? 'moveTo' : 'lineTo'](p.x, p.y);
      }
      ctx.stroke();
      ctx.restore();
    },

    _noise2d: function (x, y) {
      var octaves = 3,
      fallout = 0.5,
      amp = 1,f = 1,sum = 0,
      i;

      for (i = 0; i < octaves; ++i) {
        amp *= fallout;
        sum += amp * (this._simplexNoise.noise2D(x * f, y * f) + 1) * 0.5;
        f *= 2;
      }

      return sum;
    },

    _filterApply: function (points, lineLength, segmentsNum, base, amp, offset) {
      var pointsOld = this.points,
      // spline
      spline = [],
      catmullRom = this._catmullRom,
      p0,p1,p2,p3,t,per,
      // noise
      p,next,angle,sin,cos,nx,av,ax,ay,bv,bx,by,m,px,py,
      // shortest
      shortest,dx,dy,distSq,minDist,
      i,len,j,k;


      // Spline

      // スプライン補完用に配列の前後にラインの始点, 終点の参照をそれぞれ複製する
      points.unshift(points[0]);
      points.push(points[points.length - 1]);

      per = 1 / segmentsNum;

      // スプライン曲線のポイントを取得
      for (i = 0, len = points.length - 3; i < len; i++) {
        p0 = points[i];
        p1 = points[i + 1];
        p2 = points[i + 2];
        p3 = points[i + 3];

        for (j = 0; j < segmentsNum; j++) {
          t = (j + 1) * per;

          spline.push({
            x: catmullRom(p0.x, p1.x, p2.x, p3.x, t),
            y: catmullRom(p0.y, p1.y, p2.y, p3.y, t) });

        }
      }

      // 補完用に追加した参照を削除
      points.pop();
      // 削除のついでに描画の始点として追加
      spline.unshift(points.shift());


      // Noise

      points = [];
      len = spline.length;
      per = 1 / (len - 1);
      base = 1 / base;

      for (i = 0, len = spline.length; i < len; i++) {
        p = spline[i];
        next = i === len - 1 ? p : spline[i + 1];

        angle = Math.atan2(next.y - p.y, next.x - p.x);
        sin = Math.sin(angle);
        cos = Math.cos(angle);

        nx = i * base;

        av = lineLength * this._noise2d(nx - offset, offset) * 0.5 * amp;
        ax = av * sin;
        ay = av * cos;

        bv = lineLength * this._noise2d(nx + offset, offset) * 0.5 * amp;
        bx = bv * sin;
        by = bv * cos;

        m = Math.sin(Math.PI * (i * per));

        px = p.x + (ax - bx) * m;
        py = p.y - (ay - by) * m;

        if (pointsOld.length) {
          p = pointsOld.shift();
          p.x = px;
          p.y = py;
        } else {
          p = { x: px, y: py };
        }

        points.push(p);
      }


      // Shortest

      shortest = [points[0]];

      for (i = 0, len = points.length; i < len; i++) {
        p = points[i];

        minDist = Infinity;
        k = -1;
        for (j = i; j < len; j++) {
          p2 = points[j];

          dx = p.x - p2.x;
          dy = p.y - p2.y;
          distSq = dx * dx + dy * dy;

          if (p !== p2 && distSq < minDist * minDist) {
            minDist = Math.sqrt(distSq);
            k = j;
          }
        }
        if (k < 0) break;

        shortest.push(points[k]);
        i = k - 1;
      }

      return s.........完整代码请登录后点击上方下载按钮下载查看

网友评论0