StackOverflow_17343502: Cavas element 'rubbing out' effect with JavaScript

Illustration of answer (plus bitmap verification) to: http://stackoverflow.com/questions/17343502/cavas-element-rubbing-out-effect-with-javascript

by Gustavo Carvalho

HTML

<p>Click and Drag the mouse to clean the window</p>

<div id="container">
  <canvas id="bottom" width=271 height=267></canvas>
  <canvas id="middle" width=271 height=267></canvas>
  <canvas id="top" width=271 height=267></canvas>
</div>

<button id="btn-reset">
Reset
</button>

CSS

body {
  background-color: ivory;
}

#container {
  position: relative;
  width: 271px;
  height: 267px;
  border: 1px solid black;
}

#bottom {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
}

#middle {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 2;
}

#top {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 3;
}

#btn-reset {
  margin-top: 15px;
  width: 271px;
}

JavaScript

//  robust requestAnimationFrame polyfill
// http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
(function() {
  var lastTime = 0;
  var vendors = ['webkit', 'moz'];
  for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
    window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
  }

  if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element) {
    var currTime = new Date().getTime();
    var timeToCall = Math.max(0, 16 - (currTime - lastTime));
    var id = window.setTimeout(function() {
        callback(currTime + timeToCall);
      },
      timeToCall);
    lastTime = currTime + timeToCall;
    return id;
  };

  if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id) {
    clearTimeout(id);
  };
}());

//------------------------------------------------------//

// canvases container
var container = document.getElementById("container");

// bottom canvas
var bottomCanvas = document.getElementById("bottom");
var bottomCtx = bottomCanvas.getContext("2d");

// middle canvas
var middleCanvas = document.getElementById("middle");
var middleCtx = middleCanvas.getContext("2d");

// top canvas
var topCanvas = document.getElementById("top");
var topCtx = topCanvas.getContext("2d");

// hidden canvas (bitmask)
var mask = document.createElement("canvas");
var maskCtx = mask.getContext("2d");
mask.width = 271;
mask.height = 267;
// fill a black rectangle in the same position of the "glass"
maskCtx.fillStyle = "rgba(0,0,0,1)";
maskCtx.fillRect(15, 15, mask.width - 30, mask.height - 27);

// load images and draw each one on its respective canvas layer:

var dirty = new Image();
dirty.onload = function() {
  middleCtx.drawImage(this, 0, 0);
  middleCtx.globalCompositeOperation = "xor";
}
dirty.src =...