<canvas></canvas>


<script type="text/javascript">
  // https://github.com/NobleJS/setImmediate
  
  !function(global,undefined){"use strict";function canUseNextTick(){return"object"==typeof process&&"[object process]"===Object.prototype.toString.call(process)}function canUseMessageChannel(){return!!global.MessageChannel}function canUsePostMessage(){if(!global.postMessage||global.importScripts)return!1;var a=!0,b=global.onmessage;return global.onmessage=function(){a=!1},global.postMessage("","*"),global.onmessage=b,a}function canUseReadyStateChange(){return"document"in global&&"onreadystatechange"in global.document.createElement("script")}function installNextTickImplementation(a){a.setImmediate=function(){var a=tasks.addFromSetImmediateArguments(arguments);return process.nextTick(function(){tasks.runIfPresent(a)}),a}}function installMessageChannelImplementation(a){var b=new global.MessageChannel;b.port1.onmessage=function(a){var b=a.data;tasks.runIfPresent(b)},a.setImmediate=function(){var a=tasks.addFromSetImmediateArguments(arguments);return b.port2.postMessage(a),a}}function installPostMessageImplementation(a){function c(a,b){return"string"==typeof a&&a.substring(0,b.length)===b}function d(a){if(a.source===global&&c(a.data,b)){var d=a.data.substring(b.length);tasks.runIfPresent(d)}}var b="com.bn.NobleJS.setImmediate"+Math.random();global.addEventListener?global.addEventListener("message",d,!1):global.attachEvent("onmessage",d),a.setImmediate=function(){var a=tasks.addFromSetImmediateArguments(arguments);return global.postMessage(b+a,"*"),a}}function installReadyStateChangeImplementation(a){a.setImmediate=function(){var a=tasks.addFromSetImmediateArguments(arguments),b=global.document.createElement("script");return b.onreadystatechange=function(){tasks.runIfPresent(a),b.onreadystatechange=null,b.parentNode.removeChild(b),b=null},global.document.documentElement.appendChild(b),a}}function installSetTimeoutImplementation(a){a.setImmediate=function(){var a=tasks.addFromSetImmediateArguments(arguments);return global.setTimeout(function(){tasks.runIfPresent(a)},0),a}}var tasks=function(){function Task(a,b){this.handler=a,this.args=b}Task.prototype.run=function(){if("function"==typeof this.handler)this.handler.apply(undefined,this.args);else{var scriptSource=""+this.handler;eval(scriptSource)}};var nextHandle=1,tasksByHandle={},currentlyRunningATask=!1;return{addFromSetImmediateArguments:function(a){var b=a[0],c=Array.prototype.slice.call(a,1),d=new Task(b,c),e=nextHandle++;return tasksByHandle[e]=d,e},runIfPresent:function(a){if(currentlyRunningATask)global.setTimeout(function(){tasks.runIfPresent(a)},0);else{var b=tasksByHandle[a];if(b){currentlyRunningATask=!0;try{b.run()}finally{delete tasksByHandle[a],currentlyRunningATask=!1}}}},remove:function(a){delete tasksByHandle[a]}}}();if(!global.setImmediate){var attachTo="function"==typeof Object.getPrototypeOf&&"setTimeout"in Object.getPrototypeOf(global)?Object.getPrototypeOf(global):global;canUseNextTick()?installNextTickImplementation(attachTo):canUsePostMessage()?installPostMessageImplementation(attachTo):canUseMessageChannel()?installMessageChannelImplementation(attachTo):canUseReadyStateChange()?installReadyStateChangeImplementation(attachTo):installSetTimeoutImplementation(attachTo),attachTo.clearImmediate=tasks.remove}}("object"==typeof global&&global?global:this);
</script>
* {
  box-size: border-box;
}

html, body {
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100%;
  
  overflow: hidden;
  background-color: black;
}
if (window.console && window.console.clear)
  window.console.clear();

// PoorPainter
// Small painting loop library (purpose of this pen)
(function(exports) {
  exports.poorPainter = function(options) {
    (function scheduleUpdate() {
      var result = options.update();
      if (result === false)
        return;
        
      if (options.updatePeriod === 0 && window.setImmediate) {
        window.setImmediate(scheduleUpdate);
        return;
      }        
     
      // TODO: correct the period depending on how long the update took
      window.setTimeout(scheduleUpdate, options.updatePeriod);
    })();
    
    (function schedulePaint() {
      var result = options.paint();
      if (result === false)
        return;
        
      window.requestAnimationFrame(schedulePaint);
    })();
  }
})(window);
// end of library

$(function() {    
  var $body = $('body');
  var $canvas = $('canvas');
  var context = $canvas[0].getContext('2d');
  
  var width;
  var height;
  
  // preview hack:
  var updatePeriod = window.location.href.indexOf('fullcpgrid') > 0 ? 0 : 4;
  
  function resize() {    
    width = $body.width();
    height = $body.height();
    
    $canvas[0].width = width;
    $canvas[0].height = height;
  };
  
  resize();
  $(window).resize(resize);  
  
  /*var lastX = 0;
  var lastY = 0;
  $canvas.mousemove(function(e) {
    if (Math.abs(e.pageX - lastX) < 10 && Math.abs(e.pageY - lastY) < 10)
      return;
    
    paintQueue.push({ 
      color: '#000',
      mode: 'source-over',
      circle: { cx: e.pageX, cy: e.pageY, r: 40 } 
    });
    lastX = e.pageX;
    lastY = e.pageY;
  });*/  
  
  var paintQueue = [];
  var colors = [/*'#80DAEB',*/ '#F4C430'/*, '#93C572'*/];
  var textColor = '#FF6347';
  var textData = [
    '3,1',      '3,2', '3,3', // '3,4', '3,5',        '3,7',        '3,9',         '3,10',
    '5,1','6,2','5,2', '5,3', // '6,4', '5,5',        '5,7',        '5,9',         '5,10',
    '7,1',      '7,2', '7,3',        // '7,5',        '7,7',        '7,9',         '7,10',
    '9,1',      '9,2', '9,3', // '9,4', '9,5', '9,6', '9,7', '9,8', '9,9',         '9,10'
  ].reduce(function(hash, key) {
    hash[key] = true;
    return hash;
  }, {})
  
  poorPainter({
    update: function() {
      paintQueue.push(nextFigure());
    },
    updatePeriod: updatePeriod,
    
    paint : function() {
      var item;
      while (item = paintQueue.pop()) {      
        //context.globalCompositeOperation = 'lighter';
        //context.globalAlpha = 0.1;        
        //context.arc(circle.cx, circle.cy, circle.r, 0, 2 * Math.PI, false);
        drawFigure(item);        
      }      
    }
  });
  
  function randomInt(min, max) {
    if (max === undefined) {
      max = min;
      min = 0;
    }
    
    return Math.floor(Math.random() * (max  - min) + min);
  };
  
  function nextFigure() { 
    var size = 30;
    
    var column = randomInt(0, (width+size) / (3*size));    
    var rowDistance = Math.sqrt(3) * size / 2;
    var row = randomInt(0, (height+size) / rowDistance);
    
    var cx = column * 3*size;
    if ((row % 2) === 0)
      cx += 1.5*size;
    var cy = row * rowDistance;   
    
    if (textData[(row+1) + ',' + (column+1)])
      return;
       
    var color = textData[(row+1) + ',' + (column+1)]
              ? textColor
              : colors[randomInt(colors.length)];
    
    return { size: size, cx: cx, cy: cy, color: color };
  }
  
  function drawFigure(figure) {
    var side = figure.size;
    var cx = figure.cx;
    var cy = figure.cy;
    
    context.globalAlpha = 0.5;
    context.fillStyle = figure.color;
    context.beginPath();
    context.moveTo(cx + side * Math.cos(0), cy + side * Math.sin(0));    
    for (var i = 1; i <= 6; i += 1) {
        context.lineTo(
          cx + side * Math.cos(i * 2 * Math.PI / 6),
          cy + side * Math.sin(i * 2 * Math.PI / 6)
        );
    }
    context.closePath();
    context.fill();
  }
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js