<!DOCTYPE html><html class=''>
<head><script src='//production-assets.codepen.io/assets/editor/live/console_runner-5710c30fb566082d9fcb6e7d97ee7e3f2a326128c9f334a4231b6fd752b29965.js'></script><script src='//production-assets.codepen.io/assets/editor/live/events_runner-d5e4bf42585b8da8c18f7d963dbfc17cd66a79aa586c9448c4de8d6952ee9d97.js'></script><script src='//production-assets.codepen.io/assets/editor/live/css_live_reload_init-25d1423d5d6fb975e7d61832d2c061422a94963ca446583b965dfc5569147311.js'></script><meta charset='UTF-8'><meta name="robots" content="noindex"><link rel="shortcut icon" type="image/x-icon" href="//production-assets.codepen.io/assets/favicon/favicon-8ea04875e70c4b0bb41da869e81236e54394d63638a1ef12fa558a4a835f1164.ico" /><link rel="mask-icon" type="" href="//production-assets.codepen.io/assets/favicon/logo-pin-f2d2b6d2c61838f7e76325261b7195c27224080bc099486ddd6dccb469b8e8e6.svg" color="#111" /><link rel="canonical" href="http://codepen.io/pjkarlik/pen/pbOddA" />


<style class="cp-pen-styles">body {
  background: #333;
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.datgui {
  position: absolute;
  top: 0;
  z-index: 100;
  right: 0;
  opacity: 0.3;
  transition: opacity 700ms ease-out;
}
.datgui:hover {
  opacity: 1;
}
</style></head><body>
<div class="datgui"></div>

<script src='//production-assets.codepen.io/assets/common/stopExecutionOnTimeout-58d22c749295bca52f487966e382a94a495ac103faca9206cbd160bdf8aedf2a.js'></script><script src='//cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.0/dat.gui.min.js'></script>
<script>'use strict';

var _class2, _temp, _initialiseProps;

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

// Blob Class
// Generic Particle class for both grow and explode

var Blob = function Blob(config) {
  var _this = this;

  _classCallCheck(this, Blob);

  this.update = function () {
    _this.x += _this.vx;
    _this.y += _this.vy;
    if (_this.diretion === 'up' && _this.size.start > _this.size.end - 1 || _this.diretion === 'down' && _this.size.start < _this.size.end + 1) {
      _this.died = true;
    }
    _this.size.start = _this.size.start - (_this.size.start - _this.size.end) * 0.1;
  };

  this.x = config.x;
  this.y = config.y;
  this.vx = config.vx;
  this.vy = config.vy;
  this.origin = {
    x: config.origin.x,
    y: config.origin.y
  };
  this.size = {
    start: config.size.start,
    end: config.size.end
  };
  this.diretion = this.size.start < this.size.end ? 'up' : 'down';
  this.operation = config.operation;
  this.died = config.died;
  this.color = config.color;
};

// Render Class //

var Render = (_temp = _class2 = function () {
  function Render(element) {
    _classCallCheck(this, Render);

    _initialiseProps.call(this);

    this.element = element;
    this.operation = 'xor';
    this.canvas = this.createCanvas('canvas');
    this.points = [];
    this.tick = 0;
    this.ops = ~ ~(Math.random() * (this.operation.length - 1));
    window.addEventListener('resize', this.resetCanvas);
    window.addEventListener('mousemove', this.createPoint);
    this.renderLoop();
  }

  // Set Options from GUI

  Render.prototype.drawLine = function drawLine(point1, point2) {
    this.surface.beginPath();
    this.surface.strokeStyle = point1.color;
    this.surface.lineWidth = 0.1;
    this.surface.moveTo(point1.x, point1.y);
    this.surface.lineTo(point2.x, point2.y);
    this.surface.stroke();
  };

  return Render;
}(), _initialiseProps = function _initialiseProps() {
  var _this2 = this;

  this.setOptions = function (options) {
    _this2.operation = options.operation;
    _this2.baseHue = options.baseHue;
    _this2.baseSize = options.baseSize;
    _this2.baseSpeed = options.baseSpeed;
    _this2.drawBlobs = options.drawBlobs;
    _this2.drawLines = options.drawLines;
    _this2.motion = options.motion;
    _this2.speed = options.speed;
  };

  this.setViewport = function (element) {
    var canvasElement = element;
    var width = ~ ~(document.documentElement.clientWidth, window.innerWidth || 0);
    var height = ~ ~(document.documentElement.clientHeight, window.innerHeight || 0);
    _this2.width = width;
    _this2.height = height;
    canvasElement.width = _this2.width;
    canvasElement.height = _this2.height;
  };

  this.createCanvas = function (name) {
    var canvasElement = document.createElement('canvas');
    canvasElement.id = name;
    _this2.setViewport(canvasElement);
    _this2.element.appendChild(canvasElement);
    _this2.surface = canvasElement.getContext('2d');
    _this2.surface.scale(1, 1);
    return canvasElement;
  };

  this.resetCanvas = function () {
    window.cancelAnimationFrame(_this2.animation);
    _this2.setViewport(_this2.canvas);
    _this2.renderLoop();
  };

  this.createPoint = function (event, demo) {
    _this2.tick++;
    if (_this2.tick > 2) {
      _this2.tick = 0;
      var x = event ? event.pageX : _this2.width / 2;
      var y = event ? event.pageY : _this2.height / 2;
      var end = _this2.baseSize + ~ ~(Math.random() * 30);
      var start = demo ? end / 1.1 : 0;
      var origin = {
        x: x,
        y: y
      };
      var point = new Blob({
        x: x,
        y: y,
        vx: Math.random() * _this2.baseSpeed - _this2.baseSpeed / 2,
        vy: Math.random() * _this2.baseSpeed - _this2.baseSpeed / 2,
        origin: origin,
        size: {
          start: start,
          end: end
        },
        died: false,
        color: 'hsl(' + (_this2.baseHue + ~ ~(Math.random() * 60)) + ', 100%, 50%)'
      });
      _this2.points.push(point);
    }
  };

  this.createPop = function (config) {
    var angle = Math.random() * 2 * Math.PI;
    var radius = Math.random() * config.size.start * config.size.start;
    var pointX = config.x + Math.sqrt(radius) * Math.cos(angle);
    var pointY = config.y + Math.sqrt(radius) * Math.sin(angle);
    var point = new Blob({
      x: pointX,
      y: pointY,
      vx: (pointX - config.x) * 0.1 + config.vx,
      vy: (pointY - config.y) * 0.1 + config.vy,
      origin: {
        x: config.x,
        y: config.y
      },
      size: {
        start: config.size.start / 2,
        end: 0
      },
      died: false,
      color: config.color
    });
    _this2.points.push(point);
  };

  this.draw = function (point) {
    _this2.surface.beginPath();
    _this2.surface.fillStyle = point.color;
    _this2.surface.arc(point.x, point.y, point.size.start, 0, 2 * Math.PI, false);
    _this2.surface.fill();
  };

  this.renderLoop = function () {
    _this2.surface.globalCompositeOperation = _this2.operation;
    if (_this2.motion) {
      _this2.surface.drawImage(_this2.canvas, 0, -_this2.speed);
    }
    _this2.surface.fillStyle = 'rgba(0,0,0,0.08)';
    _this2.surface.fillRect(0, 0, _this2.width, _this2.height);

    for (var x = 0; x < _this2.points.length; x++) {
      var point = _this2.points[x];
      if (_this2.drawBlobs) {
        _this2.draw(point);
      }
      point.update();
      if (x < _this2.points.length - 1 && _this2.drawLines) {
        _this2.drawLine(point, point.origin);
      }
      if (point.died) {
        if (point.diretion === 'up') {
          _this2.points.splice(x, 1);
          var amt = ~ ~(Math.random() * 10) + 10;
          for (var i = 0; i < amt; i++) {
            _this2.createPop(point);
          }
        } else {
          _this2.points.splice(x, 1);
        }
      }
    }
    _this2.animation = window.requestAnimationFrame(_this2.renderLoop);
  };
}, _temp);

// GUI Functions and Options

var assignOptions = function assignOptions() {
  demo.setOptions(options);
};

var options = {
  baseHue: 40,
  baseSize: 10,
  baseSpeed: 5,
  operation: 'source-over',
  drawBlobs: true,
  drawLines: false,
  motion: false,
  speed: 3
};

var demo = new Render(document.body);
assignOptions();
var event = {
  pageX: ~ ~(document.documentElement.clientWidth, window.innerWidth || 0) / 2,
  pageY: ~ ~(document.documentElement.clientHeight, window.innerHeight || 0) / 2
};
for (var i = 0; i < 10; i++) {
  demo.createPoint(event, {
    start: true
  });
}

// GUI Folders
var gui = new dat.GUI();
var folderParticle = gui.addFolder('Particle Options');
var folderRender = gui.addFolder('Render Options');
var folderMotion = gui.addFolder('Add Motion');
folderParticle.add(options, 'baseSize', 1, 50).step(1).onFinishChange(assignOptions);
folderRender.add(options, 'baseHue', 1, 360).step(1).onFinishChange(assignOptions);
folderParticle.add(options, 'baseSpeed', 1, 20).step(1).onFinishChange(assignOptions);
folderRender.add(options, 'drawBlobs').onFinishChange(assignOptions);
folderRender.add(options, 'drawLines').onFinishChange(assignOptions);
folderRender.add(options, 'operation', ['xor', 'lighter', 'screen', 'overlay', 'difference', 'exclusion', 'source-over', 'none']).onFinishChange(assignOptions);
folderMotion.add(options, 'motion').onFinishChange(assignOptions);
folderMotion.add(options, 'speed', 1, 10).step(1).onFinishChange(assignOptions);
folderParticle.open();

document.querySelector('.datgui').appendChild(gui.domElement);
//# sourceURL=pen.js
</script>
</body></html>