From e21e517371e3b46a424bd4d4bce64360cf7450ee Mon Sep 17 00:00:00 2001 From: Andrew Tomaka Date: Fri, 26 Sep 2014 10:02:19 -0400 Subject: [PATCH] Minimize js and remove unused --- assets/scripts/SeamlessLoop.js | 201 ------- assets/scripts/rainyday.js | 1011 -------------------------------- assets/scripts/rainyday.min.js | 6 + index.html | 2 +- 4 files changed, 7 insertions(+), 1213 deletions(-) delete mode 100644 assets/scripts/SeamlessLoop.js delete mode 100644 assets/scripts/rainyday.js create mode 100644 assets/scripts/rainyday.min.js diff --git a/assets/scripts/SeamlessLoop.js b/assets/scripts/SeamlessLoop.js deleted file mode 100644 index a423b5a..0000000 --- a/assets/scripts/SeamlessLoop.js +++ /dev/null @@ -1,201 +0,0 @@ -/** - * SeamlessLoop.js 2.0 - Reproduces seamless loops on HTML5/Javascript - * https://github.com/Hivenfour/SeamlessLoop - * - * Copyright (c) 2012 Main Software, - * Written by DarĂ­o Tejedor Rico. Contact mail: hivenfour@gmail.com - * The source code is freely distributable under the terms of LGPL license. - * License details at http://www.gnu.org/licenses/lgpl-3.0.txt - * - * USAGE: - * - Create the Seamlessloop object - * var loop = new SeamlessLoop(); - * - * - Add as many sounds as you will use, providing duration in miliseconds - * (sounds must be pre-loaded if you want to update the loop without gaps) - * loop.addUri(uri, length, "sound1"); - * loop.addUri(uri, length, "sound2"); - * ... - * - * - Establish your callback function that will be called when all sounds are pre-loaded - * loop.callback(soundsLoaded); - * - * - Start reproducing the seamless loop: - * function soundsLoaded() { - * var n = 1; - * loop.start("sound" + n); - * }; - * - * - Update the looping sound, you can do this - * synchronously (waiting the loop to finish) - * or asynchronously (change sound immediately): - * n++; - * loop.update("sound" + n, false); - * - * - Modify the seamless loop volume: - * loop.volume(0.5); - * loop.volume(loop.volume() + 0.1); - * - * - Stop the seamless loop: - * loop.stop(); - */ - -function SeamlessLoop() { - this.is = { - ff: Boolean(!(window.mozInnerScreenX == null) && /firefox/.test( navigator.userAgent.toLowerCase() )), - ie: Boolean(document.all && !window.opera), - opera: Boolean(window.opera), - chrome: Boolean(window.chrome), - safari: Boolean(!window.chrome && /safari/.test( navigator.userAgent.toLowerCase() ) && window.getComputedStyle && !window.globalStorage && !window.opera) - }; - console.debug("ff: " + this.is.ff); - console.debug("ie: " + this.is.ie); - console.debug("opera: " + this.is.opera); - console.debug("chrome: " + this.is.chrome); - console.debug("safari: " + this.is.safari); - this._total = 0; - this._load = 0; - this.cb_loaded; - this.cb_loaded_flag = new Boolean(); - this.timeout; - this.playDelay = -30; - this.stopDelay = 30; - if(this.is.chrome) this.playDelay = -25; - if(this.is.chrome) this.stopDelay = 25; - if(this.is.ff) this.playDelay = -25; - if(this.is.ff) this.stopDelay = 85; - if(this.is.opera) this.playDelay = 5; - if(this.is.opera) this.stopDelay = 0; - console.debug(this.playDelay + ", " + this.stopDelay); - this.next = 1; - this.audios = new Array(); - this.actual = new Array(); - this.dropOld = new Boolean(); - this.old; - this._volume = 1; - - var t = this; - this._eventCanplaythrough = function(audBool) { - if(audBool == false) { - audBool = true; - t._load++; - if(t._load == t._total) { - t.loaded = true; - if(t.cb_loaded_flag == true) { - t.cb_loaded(); - t.cb_loaded_flag = false; - } - } - } - }; - - this._eventPlaying = function(audMute) { - setTimeout(function() { - audMute.pause(); - try { - audMute.currentTime = 0; - } catch (e){console.debug(e.message);}; - }, t.stopDelay); - - if(t.dropOld == true) { - setTimeout(function() { - if(t.old.paused == false) { - t.old.pause(); - try { - t.old.currentTime = 0; - } catch (e){console.debug(e.message);}; - } - }, t.stopDelay); - t.dropOld = false; - } - }; - - this._eventEnded = function(aud) { - aud.volume = this._volume; - }; - - this.doLoop = function() { - var key = (this.next == 1 ? "_1" : "_2"); - var antikey = (this.next == 1 ? "_2" : "_1"); - - var t = this; - this.timeout = setTimeout(function() {t.doLoop();}, this.actual._length + this.playDelay); - - if(this.is.opera) this.actual[antikey].pause(); - - this.actual[key].play(); - this.next *= -1; - }; - - this.isLoaded = function() { - return Boolean(this._load == this._total); - }; -} - -SeamlessLoop.prototype.start = function(id) { - if(id != "") { - this.actual = this.audios[id]; - } - this.doLoop(); -}; - -SeamlessLoop.prototype.volume = function(vol) { - if(typeof vol != "undefined") { - this.actual._1.volume = vol; - this.actual._2.volume = vol; - this._volume = vol; - } - - return vol; -}; - -SeamlessLoop.prototype.stop = function() { - clearTimeout(this.timeout); - this.actual._1.currentTime = 0; - this.actual._1.pause(); - this.actual._2.currentTime = 0; - this.actual._2.pause(); -}; - -SeamlessLoop.prototype.callback = function(cb_loaded) { - this.cb_loaded = cb_loaded; - if(this.isLoaded() == true) cb_loaded(); - else this.cb_loaded_flag = true; -}; - -SeamlessLoop.prototype.update = function(id, sync) { - //var key = (this.next == 1 ? "_1" : "_2"); - var antikey = (this.next == 1 ? "_2" : "_1"); - - this.old = this.actual[antikey]; - this.actual = this.audios[id]; - if(sync == false) { - if(this.old.paused == false) { - this.dropOld = true; - if(this.is.opera) this.old.pause(); - } - clearTimeout(this.timeout); - this.doLoop(); - } -}; - -SeamlessLoop.prototype.addUri = function(uri, length, id) { - this.audios[id] = new Array(); - this.audios[id]._length = length; - var t = this; - this.audios[id]._1_isLoaded = new Boolean(); - this.audios[id]._2_isLoaded = new Boolean(); - this.audios[id]._1 = new Audio(uri); - this.audios[id]._2 = new Audio(uri); - this._total++; - this.audios[id]._1.addEventListener("canplaythrough", function() {t._eventCanplaythrough(t.audios[id]._1_isLoaded);}); - this.audios[id]._2.addEventListener("canplaythrough", function() {t._eventCanplaythrough(t.audios[id]._2_isLoaded);}); - this.audios[id]._1.addEventListener("playing", function() {t._eventPlaying(t.audios[id]._2);}); - this.audios[id]._2.addEventListener("playing", function() {t._eventPlaying(t.audios[id]._1);}); - this.audios[id]._1.addEventListener("ended", function() {t._eventEnded(t.audios[id]._1);}); - this.audios[id]._2.addEventListener("ended", function() {t._eventEnded(t.audios[id]._2);}); - this.audios[id]._1.load(); - this.audios[id]._2.load(); - this.audios[id]._1.volume = this._volume; - this.audios[id]._2.volume = this._volume; -}; diff --git a/assets/scripts/rainyday.js b/assets/scripts/rainyday.js deleted file mode 100644 index f72a478..0000000 --- a/assets/scripts/rainyday.js +++ /dev/null @@ -1,1011 +0,0 @@ -/** - * Defines a new instance of the rainyday.js. - * @param options options element with script parameters - * @param canvas to be used (if not defined a new one will be created) - */ - -function RainyDay(options, canvas) { - - if (this === window) { //if *this* is the window object, start over with a *new* object - return new RainyDay(options); - } - - this.img = options.image; - var defaults = { - opacity: 1, - blur: 10, - crop: [0, 0, this.img.naturalWidth, this.img.naturalHeight], - enableSizeChange: true, - parentElement: document.getElementsByTagName('body')[0], - fps: 30, - fillStyle: '#8ED6FF', - enableCollisions: true, - gravityThreshold: 3, - gravityAngle: Math.PI / 2, - gravityAngleVariance: 0, - reflectionScaledownFactor: 5, - reflectionDropMappingWidth: 200, - reflectionDropMappingHeight: 200, - width: this.img.clientWidth, - height: this.img.clientHeight, - position: 'absolute', - top: 0, - left: 0 - }; - - // add the defaults to options - for (var option in defaults) { - if (typeof options[option] === 'undefined') { - options[option] = defaults[option]; - } - } - this.options = options; - - this.drops = []; - - // prepare canvas elements - this.canvas = canvas || this.prepareCanvas(); - this.prepareBackground(); - this.prepareGlass(); - - // assume defaults - this.reflection = this.REFLECTION_MINIATURE; - this.trail = this.TRAIL_DROPS; - this.gravity = this.GRAVITY_NON_LINEAR; - this.collision = this.COLLISION_SIMPLE; - - // set polyfill of requestAnimationFrame - this.setRequestAnimFrame(); -} - -/** - * Create the main canvas over a given element - * @returns HTMLElement the canvas - */ -RainyDay.prototype.prepareCanvas = function() { - var canvas = document.createElement('canvas'); - canvas.style.position = this.options.position; - canvas.style.top = this.options.top; - canvas.style.left = this.options.left; - canvas.width = this.options.width; - canvas.height = this.options.height; - this.options.parentElement.appendChild(canvas); - if (this.options.enableSizeChange) { - this.setResizeHandler(); - } - return canvas; -}; - -RainyDay.prototype.setResizeHandler = function() { - // use setInterval if oneresize event already use by other. - if (window.onresize !== null) { - window.setInterval(this.checkSize.bind(this), 100); - } else { - window.onresize = this.checkSize.bind(this); - window.onorientationchange = this.checkSize.bind(this); - } -}; - -/** - * Periodically check the size of the underlying element - */ -RainyDay.prototype.checkSize = function() { - var clientWidth = this.img.clientWidth; - var clientHeight = this.img.clientHeight; - var clientOffsetLeft = this.img.offsetLeft; - var clientOffsetTop = this.img.offsetTop; - var canvasWidth = this.canvas.width; - var canvasHeight = this.canvas.height; - var canvasOffsetLeft = this.canvas.offsetLeft; - var canvasOffsetTop = this.canvas.offsetTop; - - if (canvasWidth !== clientWidth || canvasHeight !== clientHeight) { - this.canvas.width = clientWidth; - this.canvas.height = clientHeight; - this.prepareBackground(); - this.glass.width = this.canvas.width; - this.glass.height = this.canvas.height; - this.prepareReflections(); - } - if (canvasOffsetLeft !== clientOffsetLeft || canvasOffsetTop !== clientOffsetTop) { - this.canvas.offsetLeft = clientOffsetLeft; - this.canvas.offsetTop = clientOffsetTop; - } -}; - -/** - * Start animation loop - */ -RainyDay.prototype.animateDrops = function() { - if (this.addDropCallback) { - this.addDropCallback(); - } - // |this.drops| array may be changed as we iterate over drops - var dropsClone = this.drops.slice(); - var newDrops = []; - for (var i = 0; i < dropsClone.length; ++i) { - if (dropsClone[i].animate()) { - newDrops.push(dropsClone[i]); - } - } - this.drops = newDrops; - window.requestAnimFrame(this.animateDrops.bind(this)); -}; - -/** - * Polyfill for requestAnimationFrame - */ -RainyDay.prototype.setRequestAnimFrame = function() { - var fps = this.options.fps; - window.requestAnimFrame = (function() { - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - function(callback) { - window.setTimeout(callback, 1000 / fps); - }; - })(); -}; - -/** - * Create the helper canvas for rendering raindrop reflections. - */ -RainyDay.prototype.prepareReflections = function() { - this.reflected = document.createElement('canvas'); - this.reflected.width = this.canvas.width / this.options.reflectionScaledownFactor; - this.reflected.height = this.canvas.height / this.options.reflectionScaledownFactor; - var ctx = this.reflected.getContext('2d'); - ctx.drawImage(this.img, this.options.crop[0], this.options.crop[1], this.options.crop[2], this.options.crop[3], 0, 0, this.reflected.width, this.reflected.height); -}; - -/** - * Create the glass canvas. - */ -RainyDay.prototype.prepareGlass = function() { - this.glass = document.createElement('canvas'); - this.glass.width = this.canvas.width; - this.glass.height = this.canvas.height; - this.context = this.glass.getContext('2d'); -}; - -/** - * Main function for starting rain rendering. - * @param presets list of presets to be applied - * @param speed speed of the animation (if not provided or 0 static image will be generated) - */ -RainyDay.prototype.rain = function(presets, speed) { - // prepare canvas for drop reflections - if (this.reflection !== this.REFLECTION_NONE) { - this.prepareReflections(); - } - - this.animateDrops(); - - // animation - this.presets = presets; - - this.PRIVATE_GRAVITY_FORCE_FACTOR_Y = (this.options.fps * 0.001) / 25; - this.PRIVATE_GRAVITY_FORCE_FACTOR_X = ((Math.PI / 2) - this.options.gravityAngle) * (this.options.fps * 0.001) / 50; - - // prepare gravity matrix - if (this.options.enableCollisions) { - - // calculate max radius of a drop to establish gravity matrix resolution - var maxDropRadius = 0; - for (var i = 0; i < presets.length; i++) { - if (presets[i][0] + presets[i][1] > maxDropRadius) { - maxDropRadius = Math.floor(presets[i][0] + presets[i][1]); - } - } - - if (maxDropRadius > 0) { - // initialize the gravity matrix - var mwi = Math.ceil(this.canvas.width / maxDropRadius); - var mhi = Math.ceil(this.canvas.height / maxDropRadius); - this.matrix = new CollisionMatrix(mwi, mhi, maxDropRadius); - } else { - this.options.enableCollisions = false; - } - } - - for (var i = 0; i < presets.length; i++) { - if (!presets[i][3]) { - presets[i][3] = -1; - } - } - - var lastExecutionTime = 0; - this.addDropCallback = function() { - var timestamp = new Date().getTime(); - if (timestamp - lastExecutionTime < speed) { - return; - } - lastExecutionTime = timestamp; - var context = this.canvas.getContext('2d'); - context.clearRect(0, 0, this.canvas.width, this.canvas.height); - context.drawImage(this.background, 0, 0, this.canvas.width, this.canvas.height); - // select matching preset - var preset; - for (var i = 0; i < presets.length; i++) { - if (presets[i][2] > 1 || presets[i][3] === -1) { - if (presets[i][3] !== 0) { - presets[i][3]--; - for (var y = 0; y < presets[i][2]; ++y) { - this.putDrop(new Drop(this, Math.random() * this.canvas.width, Math.random() * this.canvas.height, presets[i][0], presets[i][1])); - } - } - } else if (Math.random() < presets[i][2]) { - preset = presets[i]; - break; - } - } - if (preset) { - this.putDrop(new Drop(this, Math.random() * this.canvas.width, Math.random() * this.canvas.height, preset[0], preset[1])); - } - context.save(); - context.globalAlpha = this.options.opacity; - context.drawImage(this.glass, 0, 0, this.canvas.width, this.canvas.height); - context.restore(); - } - .bind(this); -}; - -/** - * Adds a new raindrop to the animation. - * @param drop drop object to be added to the animation - */ -RainyDay.prototype.putDrop = function(drop) { - drop.draw(); - if (this.gravity && drop.r > this.options.gravityThreshold) { - if (this.options.enableCollisions) { - this.matrix.update(drop); - } - this.drops.push(drop); - } -}; - -/** - * Clear the drop and remove from the list if applicable. - * @drop to be cleared - * @force force removal from the list - * result if true animation of this drop should be stopped - */ -RainyDay.prototype.clearDrop = function(drop, force) { - var result = drop.clear(force); - if (result) { - var index = this.drops.indexOf(drop); - if (index >= 0) { - this.drops.splice(index, 1); - } - } - return result; -}; - -/** - * Defines a new raindrop object. - * @param rainyday reference to the parent object - * @param centerX x position of the center of this drop - * @param centerY y position of the center of this drop - * @param min minimum size of a drop - * @param base base value for randomizing drop size - */ - -function Drop(rainyday, centerX, centerY, min, base) { - this.x = Math.floor(centerX); - this.y = Math.floor(centerY); - this.r = (Math.random() * base) + min; - this.rainyday = rainyday; - this.context = rainyday.context; - this.reflection = rainyday.reflected; -} - -/** - * Draws a raindrop on canvas at the current position. - */ -Drop.prototype.draw = function() { - this.context.save(); - this.context.beginPath(); - - var orgR = this.r; - this.r = 0.95 * this.r; - if (this.r < 3) { - this.context.arc(this.x, this.y, this.r, 0, Math.PI * 2, true); - this.context.closePath(); - } else if (this.colliding || this.yspeed > 2) { - if (this.colliding) { - var collider = this.colliding; - this.r = 1.001 * (this.r > collider.r ? this.r : collider.r); - this.x += (collider.x - this.x); - this.colliding = null; - } - - var yr = 1 + 0.1 * this.yspeed; - this.context.moveTo(this.x - this.r / yr, this.y); - this.context.bezierCurveTo(this.x - this.r, this.y - this.r * 2, this.x + this.r, this.y - this.r * 2, this.x + this.r / yr, this.y); - this.context.bezierCurveTo(this.x + this.r, this.y + yr * this.r, this.x - this.r, this.y + yr * this.r, this.x - this.r / yr, this.y); - } else { - this.context.arc(this.x, this.y, this.r * 0.9, 0, Math.PI * 2, true); - this.context.closePath(); - } - - this.context.clip(); - - this.r = orgR; - - if (this.rainyday.reflection) { - this.rainyday.reflection(this); - } - - this.context.restore(); -}; - -/** - * Clears the raindrop region. - * @param force force stop - * @returns Boolean true if the animation is stopped - */ -Drop.prototype.clear = function(force) { - this.context.clearRect(this.x - this.r - 1, this.y - this.r - 2, 2 * this.r + 2, 2 * this.r + 2); - if (force) { - this.terminate = true; - return true; - } - if ((this.y - this.r > this.rainyday.canvas.height) || (this.x - this.r > this.rainyday.canvas.width) || (this.x + this.r < 0)) { - // over edge so stop this drop - return true; - } - return false; -}; - -/** - * Moves the raindrop to a new position according to the gravity. - */ -Drop.prototype.animate = function() { - if (this.terminate) { - return false; - } - var stopped = this.rainyday.gravity(this); - if (!stopped && this.rainyday.trail) { - this.rainyday.trail(this); - } - if (this.rainyday.options.enableCollisions) { - var collisions = this.rainyday.matrix.update(this, stopped); - if (collisions) { - this.rainyday.collision(this, collisions); - } - } - return !stopped || this.terminate; -}; - -/** - * TRAIL function: no trail at all - */ -RainyDay.prototype.TRAIL_NONE = function() { - // nothing going on here -}; - -/** - * TRAIL function: trail of small drops (default) - * @param drop raindrop object - */ -RainyDay.prototype.TRAIL_DROPS = function(drop) { - if (!drop.trailY || drop.y - drop.trailY >= Math.random() * 100 * drop.r) { - drop.trailY = drop.y; - this.putDrop(new Drop(this, drop.x + (Math.random() * 2 - 1) * Math.random(), drop.y - drop.r - 5, Math.ceil(drop.r / 5), 0)); - } -}; - -/** - * TRAIL function: trail of unblurred image - * @param drop raindrop object - */ -RainyDay.prototype.TRAIL_SMUDGE = function(drop) { - var y = drop.y - drop.r - 3; - var x = drop.x - drop.r / 2 + (Math.random() * 2); - if (y < 0 || x < 0) { - return; - } - this.context.drawImage(this.clearbackground, x, y, drop.r, 2, x, y, drop.r, 2); -}; - -/** - * GRAVITY function: no gravity at all - * @returns Boolean true if the animation is stopped - */ -RainyDay.prototype.GRAVITY_NONE = function() { - return true; -}; - -/** - * GRAVITY function: linear gravity - * @param drop raindrop object - * @returns Boolean true if the animation is stopped - */ -RainyDay.prototype.GRAVITY_LINEAR = function(drop) { - if (this.clearDrop(drop)) { - return true; - } - - if (drop.yspeed) { - drop.yspeed += this.PRIVATE_GRAVITY_FORCE_FACTOR_Y * Math.floor(drop.r); - drop.xspeed += this.PRIVATE_GRAVITY_FORCE_FACTOR_X * Math.floor(drop.r); - } else { - drop.yspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_Y; - drop.xspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_X; - } - - drop.y += drop.yspeed; - drop.draw(); - return false; -}; - -/** - * GRAVITY function: non-linear gravity (default) - * @param drop raindrop object - * @returns Boolean true if the animation is stopped - */ -RainyDay.prototype.GRAVITY_NON_LINEAR = function(drop) { - if (this.clearDrop(drop)) { - return true; - } - - if (drop.collided) { - drop.collided = false; - drop.seed = Math.floor(drop.r * Math.random() * this.options.fps); - drop.skipping = false; - drop.slowing = false; - } else if (!drop.seed || drop.seed < 0) { - drop.seed = Math.floor(drop.r * Math.random() * this.options.fps); - drop.skipping = drop.skipping === false ? true : false; - drop.slowing = true; - } - - drop.seed--; - - if (drop.yspeed) { - if (drop.slowing) { - drop.yspeed /= 1.1; - drop.xspeed /= 1.1; - if (drop.yspeed < this.PRIVATE_GRAVITY_FORCE_FACTOR_Y) { - drop.slowing = false; - } - - } else if (drop.skipping) { - drop.yspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_Y; - drop.xspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_X; - } else { - drop.yspeed += 1 * this.PRIVATE_GRAVITY_FORCE_FACTOR_Y * Math.floor(drop.r); - drop.xspeed += 1 * this.PRIVATE_GRAVITY_FORCE_FACTOR_X * Math.floor(drop.r); - } - } else { - drop.yspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_Y; - drop.xspeed = this.PRIVATE_GRAVITY_FORCE_FACTOR_X; - } - - if (this.options.gravityAngleVariance !== 0) { - drop.xspeed += ((Math.random() * 2 - 1) * drop.yspeed * this.options.gravityAngleVariance); - } - - drop.y += drop.yspeed; - drop.x += drop.xspeed; - - drop.draw(); - return false; -}; - -/** - * Utility function to return positive min value - * @param val1 first number - * @param val2 second number - */ -RainyDay.prototype.positiveMin = function(val1, val2) { - var result = 0; - if (val1 < val2) { - if (val1 <= 0) { - result = val2; - } else { - result = val1; - } - } else { - if (val2 <= 0) { - result = val1; - } else { - result = val2; - } - } - return result <= 0 ? 1 : result; -}; - -/** - * REFLECTION function: no reflection at all - */ -RainyDay.prototype.REFLECTION_NONE = function() { - this.context.fillStyle = this.options.fillStyle; - this.context.fill(); -}; - -/** - * REFLECTION function: miniature reflection (default) - * @param drop raindrop object - */ -RainyDay.prototype.REFLECTION_MINIATURE = function(drop) { - var sx = Math.max((drop.x - this.options.reflectionDropMappingWidth) / this.options.reflectionScaledownFactor, 0); - var sy = Math.max((drop.y - this.options.reflectionDropMappingHeight) / this.options.reflectionScaledownFactor, 0); - var sw = this.positiveMin(this.options.reflectionDropMappingWidth * 2 / this.options.reflectionScaledownFactor, this.reflected.width - sx); - var sh = this.positiveMin(this.options.reflectionDropMappingHeight * 2 / this.options.reflectionScaledownFactor, this.reflected.height - sy); - var dx = Math.max(drop.x - 1.1 * drop.r, 0); - var dy = Math.max(drop.y - 1.1 * drop.r, 0); - this.context.drawImage(this.reflected, sx, sy, sw, sh, dx, dy, drop.r * 2, drop.r * 2); -}; - -/** - * COLLISION function: default collision implementation - * @param drop one of the drops colliding - * @param collisions list of potential collisions - */ -RainyDay.prototype.COLLISION_SIMPLE = function(drop, collisions) { - var item = collisions; - var drop2; - while (item != null) { - var p = item.drop; - if (Math.sqrt(Math.pow(drop.x - p.x, 2) + Math.pow(drop.y - p.y, 2)) < (drop.r + p.r)) { - drop2 = p; - break; - } - item = item.next; - } - - if (!drop2) { - return; - } - - // rename so that we're dealing with low/high drops - var higher, - lower; - if (drop.y > drop2.y) { - higher = drop; - lower = drop2; - } else { - higher = drop2; - lower = drop; - } - - this.clearDrop(lower); - // force stopping the second drop - this.clearDrop(higher, true); - this.matrix.remove(higher); - lower.draw(); - - lower.colliding = higher; - lower.collided = true; -}; - -/** - * Resizes canvas, draws original image and applies blurring algorithm. - */ -RainyDay.prototype.prepareBackground = function() { - this.background = document.createElement('canvas'); - this.background.width = this.canvas.width; - this.background.height = this.canvas.height; - - this.clearbackground = document.createElement('canvas'); - this.clearbackground.width = this.canvas.width; - this.clearbackground.height = this.canvas.height; - - var context = this.background.getContext('2d'); - context.clearRect(0, 0, this.canvas.width, this.canvas.height); - - context.drawImage(this.img, this.options.crop[0], this.options.crop[1], this.options.crop[2], this.options.crop[3], 0, 0, this.canvas.width, this.canvas.height); - - context = this.clearbackground.getContext('2d'); - context.clearRect(0, 0, this.canvas.width, this.canvas.height); - context.drawImage(this.img, this.options.crop[0], this.options.crop[1], this.options.crop[2], this.options.crop[3], 0, 0, this.canvas.width, this.canvas.height); - - if (!isNaN(this.options.blur) && this.options.blur >= 1) { - this.stackBlurCanvasRGB(this.canvas.width, this.canvas.height, this.options.blur); - } -}; - -/** - * Implements the Stack Blur Algorithm (@see http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html). - * @param width width of the canvas - * @param height height of the canvas - * @param radius blur radius - */ -RainyDay.prototype.stackBlurCanvasRGB = function(width, height, radius) { - - var shgTable = [ - [0, 9], - [1, 11], - [2, 12], - [3, 13], - [5, 14], - [7, 15], - [11, 16], - [15, 17], - [22, 18], - [31, 19], - [45, 20], - [63, 21], - [90, 22], - [127, 23], - [181, 24] - ]; - - var mulTable = [ - 512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, - 454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512, - 482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, - 437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512, - 497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, - 320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456, - 446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335, - 329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512, - 505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405, - 399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328, - 324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271, - 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456, - 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388, - 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335, - 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292, - 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259 - ]; - - radius |= 0; - - var context = this.background.getContext('2d'); - var imageData = context.getImageData(0, 0, width, height); - var pixels = imageData.data; - var x, - y, - i, - p, - yp, - yi, - yw, - rSum, - gSum, - bSum, - rOutSum, - gOutSum, - bOutSum, - rInSum, - gInSum, - bInSum, - pr, - pg, - pb, - rbs; - var radiusPlus1 = radius + 1; - var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2; - - var stackStart = new BlurStack(); - var stackEnd = new BlurStack(); - var stack = stackStart; - for (i = 1; i < 2 * radius + 1; i++) { - stack = stack.next = new BlurStack(); - if (i === radiusPlus1) { - stackEnd = stack; - } - } - stack.next = stackStart; - var stackIn = null; - var stackOut = null; - - yw = yi = 0; - - var mulSum = mulTable[radius]; - var shgSum; - for (var ssi = 0; ssi < shgTable.length; ++ssi) { - if (radius <= shgTable[ssi][0]) { - shgSum = shgTable[ssi - 1][1]; - break; - } - } - - for (y = 0; y < height; y++) { - rInSum = gInSum = bInSum = rSum = gSum = bSum = 0; - - rOutSum = radiusPlus1 * (pr = pixels[yi]); - gOutSum = radiusPlus1 * (pg = pixels[yi + 1]); - bOutSum = radiusPlus1 * (pb = pixels[yi + 2]); - - rSum += sumFactor * pr; - gSum += sumFactor * pg; - bSum += sumFactor * pb; - - stack = stackStart; - - for (i = 0; i < radiusPlus1; i++) { - stack.r = pr; - stack.g = pg; - stack.b = pb; - stack = stack.next; - } - - for (i = 1; i < radiusPlus1; i++) { - p = yi + ((width - 1 < i ? width - 1 : i) << 2); - rSum += (stack.r = (pr = pixels[p])) * (rbs = radiusPlus1 - i); - gSum += (stack.g = (pg = pixels[p + 1])) * rbs; - bSum += (stack.b = (pb = pixels[p + 2])) * rbs; - - rInSum += pr; - gInSum += pg; - bInSum += pb; - - stack = stack.next; - } - - stackIn = stackStart; - stackOut = stackEnd; - for (x = 0; x < width; x++) { - pixels[yi] = (rSum * mulSum) >> shgSum; - pixels[yi + 1] = (gSum * mulSum) >> shgSum; - pixels[yi + 2] = (bSum * mulSum) >> shgSum; - - rSum -= rOutSum; - gSum -= gOutSum; - bSum -= bOutSum; - - rOutSum -= stackIn.r; - gOutSum -= stackIn.g; - bOutSum -= stackIn.b; - - p = (yw + ((p = x + radius + 1) < (width - 1) ? p : (width - 1))) << 2; - - rInSum += (stackIn.r = pixels[p]); - gInSum += (stackIn.g = pixels[p + 1]); - bInSum += (stackIn.b = pixels[p + 2]); - - rSum += rInSum; - gSum += gInSum; - bSum += bInSum; - - stackIn = stackIn.next; - - rOutSum += (pr = stackOut.r); - gOutSum += (pg = stackOut.g); - bOutSum += (pb = stackOut.b); - - rInSum -= pr; - gInSum -= pg; - bInSum -= pb; - - stackOut = stackOut.next; - - yi += 4; - } - yw += width; - } - - for (x = 0; x < width; x++) { - gInSum = bInSum = rInSum = gSum = bSum = rSum = 0; - - yi = x << 2; - rOutSum = radiusPlus1 * (pr = pixels[yi]); - gOutSum = radiusPlus1 * (pg = pixels[yi + 1]); - bOutSum = radiusPlus1 * (pb = pixels[yi + 2]); - - rSum += sumFactor * pr; - gSum += sumFactor * pg; - bSum += sumFactor * pb; - - stack = stackStart; - - for (i = 0; i < radiusPlus1; i++) { - stack.r = pr; - stack.g = pg; - stack.b = pb; - stack = stack.next; - } - - yp = width; - - for (i = 1; i < radiusPlus1; i++) { - yi = (yp + x) << 2; - - rSum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i); - gSum += (stack.g = (pg = pixels[yi + 1])) * rbs; - bSum += (stack.b = (pb = pixels[yi + 2])) * rbs; - - rInSum += pr; - gInSum += pg; - bInSum += pb; - - stack = stack.next; - - if (i < (height - 1)) { - yp += width; - } - } - - yi = x; - stackIn = stackStart; - stackOut = stackEnd; - for (y = 0; y < height; y++) { - p = yi << 2; - pixels[p] = (rSum * mulSum) >> shgSum; - pixels[p + 1] = (gSum * mulSum) >> shgSum; - pixels[p + 2] = (bSum * mulSum) >> shgSum; - - rSum -= rOutSum; - gSum -= gOutSum; - bSum -= bOutSum; - - rOutSum -= stackIn.r; - gOutSum -= stackIn.g; - bOutSum -= stackIn.b; - - p = (x + (((p = y + radiusPlus1) < (height - 1) ? p : (height - 1)) * width)) << 2; - - rSum += (rInSum += (stackIn.r = pixels[p])); - gSum += (gInSum += (stackIn.g = pixels[p + 1])); - bSum += (bInSum += (stackIn.b = pixels[p + 2])); - - stackIn = stackIn.next; - - rOutSum += (pr = stackOut.r); - gOutSum += (pg = stackOut.g); - bOutSum += (pb = stackOut.b); - - rInSum -= pr; - gInSum -= pg; - bInSum -= pb; - - stackOut = stackOut.next; - - yi += width; - } - } - - context.putImageData(imageData, 0, 0); - -}; - -/** - * Defines a new helper object for Stack Blur Algorithm. - */ -function BlurStack() { - this.r = 0; - this.g = 0; - this.b = 0; - this.next = null; -} - -/** - * Defines a gravity matrix object which handles collision detection. - * @param x number of columns in the matrix - * @param y number of rows in the matrix - * @param r grid size - */ -function CollisionMatrix(x, y, r) { - this.resolution = r; - this.xc = x; - this.yc = y; - this.matrix = new Array(x); - for (var i = 0; i <= (x + 5); i++) { - this.matrix[i] = new Array(y); - for (var j = 0; j <= (y + 5); ++j) { - this.matrix[i][j] = new DropItem(null); - } - } -} - -/** - * Updates position of the given drop on the collision matrix. - * @param drop raindrop to be positioned/repositioned - * @param forceDelete if true the raindrop will be removed from the matrix - * @returns collisions if any - */ -CollisionMatrix.prototype.update = function(drop, forceDelete) { - if (drop.gid) { - if (!this.matrix[drop.gmx] || !this.matrix[drop.gmx][drop.gmy]) { - return null; - } - this.matrix[drop.gmx][drop.gmy].remove(drop); - if (forceDelete) { - return null; - } - - drop.gmx = Math.floor(drop.x / this.resolution); - drop.gmy = Math.floor(drop.y / this.resolution); - if (!this.matrix[drop.gmx] || !this.matrix[drop.gmx][drop.gmy]) { - return null; - } - this.matrix[drop.gmx][drop.gmy].add(drop); - - var collisions = this.collisions(drop); - if (collisions && collisions.next != null) { - return collisions.next; - } - } else { - drop.gid = Math.random().toString(36).substr(2, 9); - drop.gmx = Math.floor(drop.x / this.resolution); - drop.gmy = Math.floor(drop.y / this.resolution); - if (!this.matrix[drop.gmx] || !this.matrix[drop.gmx][drop.gmy]) { - return null; - } - - this.matrix[drop.gmx][drop.gmy].add(drop); - } - return null; -}; - -/** - * Looks for collisions with the given raindrop. - * @param drop raindrop to be checked - * @returns DropItem list of drops that collide with it - */ -CollisionMatrix.prototype.collisions = function(drop) { - var item = new DropItem(null); - var first = item; - - item = this.addAll(item, drop.gmx - 1, drop.gmy + 1); - item = this.addAll(item, drop.gmx, drop.gmy + 1); - item = this.addAll(item, drop.gmx + 1, drop.gmy + 1); - - return first; -}; - -/** - * Appends all found drop at a given location to the given item. - * @param to item to which the results will be appended to - * @param x x position in the matrix - * @param y y position in the matrix - * @returns last discovered item on the list - */ -CollisionMatrix.prototype.addAll = function(to, x, y) { - if (x > 0 && y > 0 && x < this.xc && y < this.yc) { - var items = this.matrix[x][y]; - while (items.next != null) { - items = items.next; - to.next = new DropItem(items.drop); - to = to.next; - } - } - return to; -}; - -/** - * Removed the drop from its current position - * @param drop to be removed - */ -CollisionMatrix.prototype.remove = function(drop) { - this.matrix[drop.gmx][drop.gmy].remove(drop); -}; - -/** - * Defines a linked list item. - */ -function DropItem(drop) { - this.drop = drop; - this.next = null; -} - -/** - * Adds the raindrop to the end of the list. - * @param drop raindrop to be added - */ -DropItem.prototype.add = function(drop) { - var item = this; - while (item.next != null) { - item = item.next; - } - item.next = new DropItem(drop); -}; - -/** - * Removes the raindrop from the list. - * @param drop raindrop to be removed - */ -DropItem.prototype.remove = function(drop) { - var item = this; - var prevItem = null; - while (item.next != null) { - prevItem = item; - item = item.next; - if (item.drop.gid === drop.gid) { - prevItem.next = item.next; - } - } -}; diff --git a/assets/scripts/rainyday.min.js b/assets/scripts/rainyday.min.js new file mode 100644 index 0000000..802e0ba --- /dev/null +++ b/assets/scripts/rainyday.min.js @@ -0,0 +1,6 @@ +/*! + * rainyday.js v0.1.2 - https://github.com/maroslaw/rainyday.js + * Copyright (c) 2014 Marek Brodziak + * Licensed under the GPLv2 license + */ +function RainyDay(a,b){if(this===window)return new RainyDay(a);this.img=a.image;var c={opacity:1,blur:10,crop:[0,0,this.img.naturalWidth,this.img.naturalHeight],enableSizeChange:!0,parentElement:document.getElementsByTagName("body")[0],fps:30,fillStyle:"#8ED6FF",enableCollisions:!0,gravityThreshold:3,gravityAngle:Math.PI/2,gravityAngleVariance:0,reflectionScaledownFactor:5,reflectionDropMappingWidth:200,reflectionDropMappingHeight:200,width:this.img.clientWidth,height:this.img.clientHeight,position:"absolute",top:0,left:0};for(var d in c)"undefined"==typeof a[d]&&(a[d]=c[d]);this.options=a,this.drops=[],this.canvas=b||this.prepareCanvas(),this.prepareBackground(),this.prepareGlass(),this.reflection=this.REFLECTION_MINIATURE,this.trail=this.TRAIL_DROPS,this.gravity=this.GRAVITY_NON_LINEAR,this.collision=this.COLLISION_SIMPLE,this.setRequestAnimFrame()}function Drop(a,b,c,d,e){this.x=Math.floor(b),this.y=Math.floor(c),this.r=Math.random()*e+d,this.rainyday=a,this.context=a.context,this.reflection=a.reflected}function BlurStack(){this.r=0,this.g=0,this.b=0,this.next=null}function CollisionMatrix(a,b,c){this.resolution=c,this.xc=a,this.yc=b,this.matrix=new Array(a);for(var d=0;a+5>=d;d++){this.matrix[d]=new Array(b);for(var e=0;b+5>=e;++e)this.matrix[d][e]=new DropItem(null)}}function DropItem(a){this.drop=a,this.next=null}RainyDay.prototype.prepareCanvas=function(){var a=document.createElement("canvas");return a.style.position=this.options.position,a.style.top=this.options.top,a.style.left=this.options.left,a.width=this.options.width,a.height=this.options.height,this.options.parentElement.appendChild(a),this.options.enableSizeChange&&this.setResizeHandler(),a},RainyDay.prototype.setResizeHandler=function(){null!==window.onresize?window.setInterval(this.checkSize.bind(this),100):(window.onresize=this.checkSize.bind(this),window.onorientationchange=this.checkSize.bind(this))},RainyDay.prototype.checkSize=function(){var a=this.img.clientWidth,b=this.img.clientHeight,c=this.img.offsetLeft,d=this.img.offsetTop,e=this.canvas.width,f=this.canvas.height,g=this.canvas.offsetLeft,h=this.canvas.offsetTop;(e!==a||f!==b)&&(this.canvas.width=a,this.canvas.height=b,this.prepareBackground(),this.glass.width=this.canvas.width,this.glass.height=this.canvas.height,this.prepareReflections()),(g!==c||h!==d)&&(this.canvas.offsetLeft=c,this.canvas.offsetTop=d)},RainyDay.prototype.animateDrops=function(){this.addDropCallback&&this.addDropCallback();for(var a=this.drops.slice(),b=[],c=0;cc&&(c=Math.floor(a[d][0]+a[d][1]));if(c>0){var e=Math.ceil(this.canvas.width/c),f=Math.ceil(this.canvas.height/c);this.matrix=new CollisionMatrix(e,f,c)}else this.options.enableCollisions=!1}for(var d=0;dc-g)){g=c;var d=this.canvas.getContext("2d");d.clearRect(0,0,this.canvas.width,this.canvas.height),d.drawImage(this.background,0,0,this.canvas.width,this.canvas.height);for(var e,f=0;f1||-1===a[f][3]){if(0!==a[f][3]){a[f][3]--;for(var h=0;hthis.options.gravityThreshold&&(this.options.enableCollisions&&this.matrix.update(a),this.drops.push(a))},RainyDay.prototype.clearDrop=function(a,b){var c=a.clear(b);if(c){var d=this.drops.indexOf(a);d>=0&&this.drops.splice(d,1)}return c},Drop.prototype.draw=function(){this.context.save(),this.context.beginPath();var a=this.r;if(this.r=.95*this.r,this.r<3)this.context.arc(this.x,this.y,this.r,0,2*Math.PI,!0),this.context.closePath();else if(this.colliding||this.yspeed>2){if(this.colliding){var b=this.colliding;this.r=1.001*(this.r>b.r?this.r:b.r),this.x+=b.x-this.x,this.colliding=null}var c=1+.1*this.yspeed;this.context.moveTo(this.x-this.r/c,this.y),this.context.bezierCurveTo(this.x-this.r,this.y-2*this.r,this.x+this.r,this.y-2*this.r,this.x+this.r/c,this.y),this.context.bezierCurveTo(this.x+this.r,this.y+c*this.r,this.x-this.r,this.y+c*this.r,this.x-this.r/c,this.y)}else this.context.arc(this.x,this.y,.9*this.r,0,2*Math.PI,!0),this.context.closePath();this.context.clip(),this.r=a,this.rainyday.reflection&&this.rainyday.reflection(this),this.context.restore()},Drop.prototype.clear=function(a){return this.context.clearRect(this.x-this.r-1,this.y-this.r-2,2*this.r+2,2*this.r+2),a?(this.terminate=!0,!0):this.y-this.r>this.rainyday.h||this.x-this.r>this.rainyday.w||this.x+this.r<0?!0:!1},Drop.prototype.animate=function(){if(this.terminate)return!1;var a=this.rainyday.gravity(this);if(!a&&this.rainyday.trail&&this.rainyday.trail(this),this.rainyday.options.enableCollisions){var b=this.rainyday.matrix.update(this,a);b&&this.rainyday.collision(this,b)}return!a||this.terminate},RainyDay.prototype.TRAIL_NONE=function(){},RainyDay.prototype.TRAIL_DROPS=function(a){(!a.trailY||a.y-a.trailY>=100*Math.random()*a.r)&&(a.trailY=a.y,this.putDrop(new Drop(this,a.x+(2*Math.random()-1)*Math.random(),a.y-a.r-5,Math.ceil(a.r/5),0)))},RainyDay.prototype.TRAIL_SMUDGE=function(a){var b=a.y-a.r-3,c=a.x-a.r/2+2*Math.random();0>b||0>c||this.context.drawImage(this.clearbackground,c,b,a.r,2,c,b,a.r,2)},RainyDay.prototype.GRAVITY_NONE=function(){return!0},RainyDay.prototype.GRAVITY_LINEAR=function(a){return this.clearDrop(a)?!0:(a.yspeed?(a.yspeed+=this.PRIVATE_GRAVITY_FORCE_FACTOR_Y*Math.floor(a.r),a.xspeed+=this.PRIVATE_GRAVITY_FORCE_FACTOR_X*Math.floor(a.r)):(a.yspeed=this.PRIVATE_GRAVITY_FORCE_FACTOR_Y,a.xspeed=this.PRIVATE_GRAVITY_FORCE_FACTOR_X),a.y+=a.yspeed,a.draw(),!1)},RainyDay.prototype.GRAVITY_NON_LINEAR=function(a){return this.clearDrop(a)?!0:(a.collided?(a.collided=!1,a.seed=Math.floor(a.r*Math.random()*this.options.fps),a.skipping=!1,a.slowing=!1):(!a.seed||a.seed<0)&&(a.seed=Math.floor(a.r*Math.random()*this.options.fps),a.skipping=a.skipping===!1?!0:!1,a.slowing=!0),a.seed--,a.yspeed?a.slowing?(a.yspeed/=1.1,a.xspeed/=1.1,a.yspeeda?0>=a?b:a:0>=b?a:b,0>=c?1:c},RainyDay.prototype.REFLECTION_NONE=function(){this.context.fillStyle=this.options.fillStyle,this.context.fill()},RainyDay.prototype.REFLECTION_MINIATURE=function(a){var b=Math.max((a.x-this.options.reflectionDropMappingWidth)/this.options.reflectionScaledownFactor,0),c=Math.max((a.y-this.options.reflectionDropMappingHeight)/this.options.reflectionScaledownFactor,0),d=this.positiveMin(2*this.options.reflectionDropMappingWidth/this.options.reflectionScaledownFactor,this.reflected.width-b),e=this.positiveMin(2*this.options.reflectionDropMappingHeight/this.options.reflectionScaledownFactor,this.reflected.height-c),f=Math.max(a.x-1.1*a.r,0),g=Math.max(a.y-1.1*a.r,0);this.context.drawImage(this.reflected,b,c,d,e,f,g,2*a.r,2*a.r)},RainyDay.prototype.COLLISION_SIMPLE=function(a,b){for(var c,d=b;null!=d;){var e=d.drop;if(Math.sqrt(Math.pow(a.x-e.x,2)+Math.pow(a.y-e.y,2))c.y?(f=a,g=c):(f=c,g=a),this.clearDrop(g),this.clearDrop(f,!0),this.matrix.remove(f),g.draw(),g.colliding=f,g.collided=!0}},RainyDay.prototype.prepareBackground=function(){this.background=document.createElement("canvas"),this.background.width=this.canvas.width,this.background.height=this.canvas.height,this.clearbackground=document.createElement("canvas"),this.clearbackground.width=this.canvas.width,this.clearbackground.height=this.canvas.height;var a=this.background.getContext("2d");a.clearRect(0,0,this.canvas.width,this.canvas.height),a.drawImage(this.img,this.options.crop[0],this.options.crop[1],this.options.crop[2],this.options.crop[3],0,0,this.canvas.width,this.canvas.height),a=this.clearbackground.getContext("2d"),a.clearRect(0,0,this.canvas.width,this.canvas.height),a.drawImage(this.img,this.options.crop[0],this.options.crop[1],this.options.crop[2],this.options.crop[3],0,0,this.canvas.width,this.canvas.height),!isNaN(this.options.blur)&&this.options.blur>=1&&this.stackBlurCanvasRGB(this.canvas.width,this.canvas.height,this.options.blur)},RainyDay.prototype.stackBlurCanvasRGB=function(a,b,c){var d=[[0,9],[1,11],[2,12],[3,13],[5,14],[7,15],[11,16],[15,17],[22,18],[31,19],[45,20],[63,21],[90,22],[127,23],[181,24]],e=[512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512,454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512,482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456,437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512,497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328,320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456,446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335,329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512,505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405,399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328,324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271,268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456,451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388,385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335,332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292,289,287,285,282,280,278,275,273,271,269,267,265,263,261,259];c|=0;var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z=this.background.getContext("2d"),A=z.getImageData(0,0,a,b),B=A.data,C=c+1,D=C*(C+1)/2,E=new BlurStack,F=new BlurStack,G=E;for(h=1;2*c+1>h;h++)G=G.next=new BlurStack,h===C&&(F=G);G.next=E;var H=null,I=null;l=k=0;for(var J,K=e[c],L=0;Lg;g++){for(s=t=u=m=n=o=0,p=C*(v=B[k]),q=C*(w=B[k+1]),r=C*(x=B[k+2]),m+=D*v,n+=D*w,o+=D*x,G=E,h=0;C>h;h++)G.r=v,G.g=w,G.b=x,G=G.next;for(h=1;C>h;h++)i=k+((h>a-1?a-1:h)<<2),m+=(G.r=v=B[i])*(y=C-h),n+=(G.g=w=B[i+1])*y,o+=(G.b=x=B[i+2])*y,s+=v,t+=w,u+=x,G=G.next;for(H=E,I=F,f=0;a>f;f++)B[k]=m*K>>J,B[k+1]=n*K>>J,B[k+2]=o*K>>J,m-=p,n-=q,o-=r,p-=H.r,q-=H.g,r-=H.b,i=l+((i=f+c+1)f;f++){for(t=u=s=n=o=m=0,k=f<<2,p=C*(v=B[k]),q=C*(w=B[k+1]),r=C*(x=B[k+2]),m+=D*v,n+=D*w,o+=D*x,G=E,h=0;C>h;h++)G.r=v,G.g=w,G.b=x,G=G.next;for(j=a,h=1;C>h;h++)k=j+f<<2,m+=(G.r=v=B[k])*(y=C-h),n+=(G.g=w=B[k+1])*y,o+=(G.b=x=B[k+2])*y,s+=v,t+=w,u+=x,G=G.next,b-1>h&&(j+=a);for(k=f,H=E,I=F,g=0;b>g;g++)i=k<<2,B[i]=m*K>>J,B[i+1]=n*K>>J,B[i+2]=o*K>>J,m-=p,n-=q,o-=r,p-=H.r,q-=H.g,r-=H.b,i=f+((i=g+C)0&&c>0&&b - +