<canvas id="canvas" width="600" height="400"></canvas>
<div id="fps"></div>
body, html {
    background: #000;
    width: 100%;
    height: 400px;
    overflow: hidden;
    padding:0;
    margin:0;
}
#canvas {
  padding:0;
  display:block;
  margin:0 auto;
}
#W{
  font-family:'Helvetica Neue',Arial,sans-serif;
  font-weight:100;
  color:#fff;
  text-align:center;
  line-height:400px;
  font-size:100px;
  width:100%;
  height:400;
  position:absolute;
  z-index:999;
  top:0;
  left:0;
}

#fps { 
  font-family:'Helvetica Neue',Arial,sans-serif;
  font-weight:100;
  width:100px;
  height:30px; 
  position:fixed; 
  top:0;
  left:0;
  color:#fff;}
var maxpoints = 50,
    pointradius = 3,
    multicollect = false,
    jitter = false,
    maxdist = 100,
    mindist = 70,
    gravity = true,
    gravityforce = .3,
    rainbow = false;

var r = 0, g = 0, b = 0;

var canvas = document.getElementById("canvas"),
    context = canvas.getContext("2d");
    points = [],
    canvasW = canvas.width,
    canvasH = canvas.height,
    screencap = context.getImageData(0, 0, canvasW, canvasH);

var mousepos = [], mousedown = false, collected = [];

var fps = 0, now, lastUpdate = (new Date)*1 - 1, 
    fpsOut = document.getElementById('fps'),
    intervalfps = 1000 / 60,
    last, t;

function Point(x,y)
{
    this.x = x;
    this.y = y;
    this.connected = [];
    this.dragging = false;
    this.Update = function(){
      
        var mx = this.x - mousepos[0],
            my = this.y - mousepos[1],
            mdist = Math.sqrt(mx * mx + my * my);  
      
        if(jitter)
        {
            this.x += (Math.random() * .2 - .1) * 10;
            this.y += (Math.random() * .2 - .1) * 10;
        }
        
        context.beginPath();
        context.arc(this.x, this.y, pointradius, 0, 2 * Math.PI, false);
        if(rainbow) context.fillStyle = 'rgba(' + r + ' ,' + g + ',' + b + ',255)';
        else context.fillStyle = 'rgba(255,255,255,255)';
        context.fill();
        
        for(var i = 0; i < points.length; i++)
        {
            if(points[i] == this) continue;
            var dx = points[i].x - this.x,
                dy = points[i].y - this.y,
                dist = Math.sqrt(dx * dx + dy * dy);
            
            if(dist <= maxdist)
            {
                context.beginPath();
                context.moveTo(this.x, this.y);
                context.lineTo(points[i].x,points[i].y);
                context.lineWidth = pointradius * 2 - (pointradius * 2 * (dist/maxdist));
                
                if(rainbow) context.strokeStyle = 'rgba(' + r + ' ,' + g + ',' + b + ',' + (1 - (1 * (dist/maxdist))) + ')';
                else context.strokeStyle = 'rgba(255,255,255,' + (1 - (1 * (dist/maxdist))) + ')';
                context.stroke();
                if(gravity)
                {
                    var angle = Math.atan2(dy,dx);
                    if(dist >= mindist)
                    {
                        this.x += Math.cos(angle) * gravityforce * (1 - (1 * (dist/maxdist)));
                        this.y += Math.sin(angle) * gravityforce * (1 - (1 * (dist/maxdist)));
                    }
                    else
                    {
                        this.x -= Math.cos(angle) * gravityforce * (1 - (1 * (dist/maxdist)));
                        this.y -= Math.sin(angle) * gravityforce * (1 - (1 * (dist/maxdist)));
                    }
                }
            }
        }
        
        if((!this.dragging && mdist < 10) || this.dragging)
        {
            console.log('true');
            context.beginPath();
            context.arc(this.x, this.y, 10 + collected.length, 0, 2 * Math.PI, false);
            
            if(rainbow) context.fillStyle = 'rgba(' + r + ' ,' + g + ',' + b + ',.15)';
            else context.fillStyle = 'rgba(255,255,255,.15)';
          
          
            context.fill();
            context.lineWidth = 1;
            if(rainbow) context.strokeStyle = 'rgb('+r+','+g+','+b+')';
            else context.strokeStyle = 'rgb(255,255,255)';
            context.stroke();
            canvas.style.cursor='pointer';
            if(collected.length == 0 || collected[0] == this || multicollect)
            {
                if(mousedown)
                {
                    if(!this.dragging) this.dragging = true;
                }
                else
                {
                    if(this.dragging) this.dragging = false;
                }
                if(this.dragging)
                {
                    if(collected.indexOf(this) == -1) collected.push(this);
                    this.x = mousepos[0];
                    this.y = mousepos[1];
                }
                else
                {
                    if(collected != []) collected = [];
                }
            }
        }
        else
        {
            if(canvas.style.cursor!='default') canvas.style.cursor='default';
        }
        if(this.x < 0) this.x = 0;
        else if(this.x > canvasW) this.x = canvasW;
        if(this.y < 0) this.y = 0;
        else if(this.y > canvasH) this.y = canvasH;
    }
}

function init(){
    points = [];
    for(var i = 0; i < maxpoints; i++)
    {
      var p = new Point(Math.random() * 600, Math.random() * 400);
      points.push(p);
    }
}

function ChangePoints(){
    if(maxpoints > points.length)
    {
        for(var i = points.length; i < maxpoints; i++)
        {
            var p = new Point(Math.random() * 600, Math.random() * 400);
            points.push(p);
        }
    }
    else
    {
        points.splice(maxpoints,points.length - maxpoints);
    }
}

(function (window) {
    var lastTime = 0,
        vendors = ['moz', 'webkit', 'o', 'ms'],
        i;
    
    for (i = 0; i < vendors.length && !window.requestAnimationFrame; i ++)
    {
        window.requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame'];
    }
    init();
    
}(this));

function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    };
}

canvas.addEventListener('mousemove', function(evt) {
    var mousePos = getMousePos(canvas, evt);
    mousepos = [mousePos.x,mousePos.y];
});

canvas.addEventListener('mousedown',function(e){
    mousedown = true;
});

canvas.addEventListener('mouseup',function(e){
    mousedown = false;
});

canvas.addEventListener('mouseout',function(e){
    mousedown = false;
});

function draw(){
  r = Math.round(Math.random() * 255);
  g = Math.round(Math.random() * 255);
  b = Math.round(Math.random() * 255);
  
  console.log(r,g,b);
  var thisFrameFPS = 1000 / ((now=new Date) - lastUpdate);
  fps += (thisFrameFPS - fps) / intervalfps;
  lastUpdate = now;
  fpsOut.innerHTML = fps.toFixed(1) + "fps";
  
  context.putImageData(screencap,0,0);
  for(var i = 0; i < points.length; i++)
  {
      points[i].Update();
  }
  window.requestAnimationFrame(draw);
}

window.requestAnimationFrame(draw);

var gui = new dat.GUI();
gui.close();
gui.add(window, "maxpoints", 1,50).step(1.0).onChange(function(){ChangePoints()});
gui.add(window, "maxdist", 100,1000).step(1.0);
gui.add(window, "mindist", 0,100).step(1.0);
gui.add(window, "pointradius", 1,5).step(1.0);
gui.add(window, "multicollect");
gui.add(window, "jitter");
gui.add(window, "gravity");
gui.add(window, "gravityforce",0,2).step(.01);
gui.add(window, "rainbow");
gui.add(window, "init");

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. http:///cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js