diff --git a/files/assets/js/vendor/critters.js b/files/assets/js/vendor/critters.js index 6a773f778..0de40a1a8 100644 --- a/files/assets/js/vendor/critters.js +++ b/files/assets/js/vendor/critters.js @@ -1,33 +1,1042 @@ -var BugDispatch={options:{minDelay:500,maxDelay:1E4,minBugs:2,maxBugs:20,minSpeed:5,maxSpeed:10,maxLargeTurnDeg:150,maxSmallTurnDeg:10,maxWiggleDeg:5,imageSprite:"fireflies.webp",bugWidth:13,bugHeight:14,num_frames:5,zoom:10,canFly:!0,canDie:!0,numDeathTypes:3,monitorMouseMovement:!1,eventDistanceToBug:40,minTimeBetweenMultipy:1E3,mouseOver:"random"},initialize:function(a){this.options=mergeOptions(this.options,a);this.options.minBugs>this.options.maxBugs&&(this.options.minBugs=this.options.maxBugs); -this.modes=["multiply","nothing"];this.options.canFly&&this.modes.push("fly","flyoff");this.options.canDie&&this.modes.push("die");-1==this.modes.indexOf(this.options.mouseOver)&&(this.options.mouseOver="random");this.transform=null;this.transforms={Moz:function(a){this.bug.style.MozTransform=a},webkit:function(a){this.bug.style.webkitTransform=a},O:function(a){this.bug.style.OTransform=a},ms:function(a){this.bug.style.msTransform=a},Khtml:function(a){this.bug.style.KhtmlTransform=a},w3c:function(a){this.bug.style.transform= -a}};if("transform"in document.documentElement.style)this.transform=this.transforms.w3c;else{var b=["Moz","webkit","O","ms","Khtml"],c=0;for(c=0;cb?d=b:dc||(200=--this.toggle_stationary_counter&&this.toggleStationary(),this.stationary))){if(0>=--this.edge_test_counter&&this.bug_near_window_edge()&&(this.angle_deg%=360,0>this.angle_deg&&(this.angle_deg+=360),15=--this.large_turn_counter&&(this.large_turn_angle_deg=this.random(1,this.options.maxLargeTurnDeg,!0),this.next_large_turn());if(0>=--this.small_turn_counter)this.angle_deg+=this.random(1,this.options.maxSmallTurnDeg),this.next_small_turn();else{a=this.random(1,this.options.maxWiggleDeg,!0);if(0a||0>this.large_turn_angle_deg&&0=this.options.num_frames&&(this.walkIndex=0)},fly:function(a){var b=this.bug.top,c=this.bug.left,d=c-a.left,e=b-a.top,f=Math.atan(e/d);50>Math.abs(d)+Math.abs(e)&&(this.bug.style.backgroundPosition=-2*this.options.bugWidth+ -"px -"+2*this.options.bugHeight+"px");30>Math.abs(d)+Math.abs(e)&&(this.bug.style.backgroundPosition=-1*this.options.bugWidth+"px -"+2*this.options.bugHeight+"px");if(10>Math.abs(d)+Math.abs(e))this.bug.style.backgroundPosition="0 0",this.stop(),this.go();else{var g=Math.cos(f)*this.options.flySpeed;f=Math.sin(f)*this.options.flySpeed;if(c>a.left&&0a.left&&0>g)g*=-1,Math.abs(d)f||b>a.top&&0a&&(a=0);0===a?(a=-2*this.options.bugHeight,b*=Math.random()):1===a?(a=Math.random()*c,b+=2*this.options.bugWidth): -2===a?(a=c+2*this.options.bugHeight,b*=Math.random()):(a=Math.random()*c,b=-3*this.options.bugWidth);this.bug.style.backgroundPosition=-3*this.options.bugWidth+"px "+(this.wingsOpen?"0":"-"+this.options.bugHeight+"px");this.bug.top=a;this.bug.left=b;this.drawBug();a={};a.top=this.random(this.options.edge_resistance,document.documentElement.clientHeight-this.options.edge_resistance);a.left=this.random(this.options.edge_resistance,document.documentElement.clientWidth-this.options.edge_resistance);this.startFlying(a)}}, -walkIn:function(){this.bug||this.makeBug();if(this.bug){this.stop();var a=Math.round(4*Math.random()-.5),b=document,c=b.documentElement,d=b.getElementsByTagName("body")[0];b=window.innerWidth||c.clientWidth||d.clientWidth;c=window.innerHeight||c.clientHeight||d.clientHeight;3a&&(a=0);0===a?(a=-1.3*this.options.bugHeight,b*=Math.random()):1===a?(a=Math.random()*c,b+=.3*this.options.bugWidth):2===a?(a=c+.3*this.options.bugHeight,b*=Math.random()):(a=Math.random()*c,b=-1.3*this.options.bugWidth); -this.bug.style.backgroundPosition=-3*this.options.bugWidth+"px "+(this.wingsOpen?"0":"-"+this.options.bugHeight+"px");this.bug.top=a;this.bug.left=b;this.drawBug();this.go()}},flyOff:function(){this.stop();var a=this.random(0,3),b={},c=document,d=c.documentElement,e=c.getElementsByTagName("body")[0];c=window.innerWidth||d.clientWidth||e.clientWidth;d=window.innerHeight||d.clientHeight||e.clientHeight;0===a?(b.top=-200,b.left=Math.random()*c):1===a?(b.top=Math.random()*d,b.left=c+200):2===a?(b.top= -d+200,b.left=Math.random()*c):(b.top=Math.random()*d,b.left=-200);this.startFlying(b)},die:function(){this.stop();var a=this.random(0,this.options.numDeathTypes-1);this.alive=!1;this.drop(a)},drop:function(a){var b=this.bug.top,c=document,d=c.documentElement;c=c.getElementsByTagName("body")[0];var e=window.innerHeight||d.clientHeight||c.clientHeight;e-=this.options.bugHeight;var f=this.random(0,20,!0);Date.now();var g=this;this.bug.classList.add("bug-dead");this.dropTimer=requestAnimFrame(function(c){g._lastTimestamp= -c;g.dropping(c,b,e,f,a)})},dropping:function(a,b,c,d,e){a-=this._lastTimestamp;var f=b+.002*a*a,g=this;f>=c?(f=c,clearTimeout(this.dropTimer),this.angle_deg=0,this.angle_rad=this.deg2rad(this.angle_deg),this.transform("rotate("+(90-this.angle_deg)+"deg) scale("+this.zoom+")"),this.bug.style.top=null,this.bug.style.bottom=Math.ceil((this.options.bugWidth*this.zoom-this.options.bugHeight*this.zoom)/2-this.options.bugHeight/2*(1-this.zoom))+"px",this.bug.style.left=this.bug.left+"px",this.bug.style.backgroundPosition= -"-"+2*e*this.options.bugWidth+"px 100%",this.twitch(e)):(this.dropTimer=requestAnimFrame(function(a){g.dropping(a,b,c,d,e)}),20>a||(this.angle_deg=(this.angle_deg+d)%360,this.angle_rad=this.deg2rad(this.angle_deg),this.moveBug(this.bug.left,f,this.angle_deg)))},twitch:function(a,b){b||(b=0);var c=this;if(0===a||1===a)c.twitchTimer=setTimeout(function(){c.bug.style.backgroundPosition="-"+(2*a+b%2)*c.options.bugWidth+"px 100%";c.twitchTimer=setTimeout(function(){b++;c.bug.style.backgroundPosition="-"+ -(2*a+b%2)*c.options.bugWidth+"px 100%";c.twitch(a,++b)},c.random(300,800))},this.random(1E3,1E4))},rad2deg:function(a){return a*this.rad2deg_k},deg2rad:function(a){return a*this.deg2rad_k},random:function(a,b,c){if(a==b)return a;a=Math.round(a-.5+Math.random()*(b-a+1));return c?.5document.documentElement.clientHeight-this.options.edge_resistance&&(this.near_edge|=this.NEAR_BOTTOM_EDGE);this.bug.leftdocument.documentElement.clientWidth-this.options.edge_resistance&&(this.near_edge|=this.NEAR_RIGHT_EDGE);return this.near_edge},getPos:function(){return this.inserted&& -this.bug&&this.bug.style?{top:parseInt(this.bug.top,10),left:parseInt(this.bug.left,10)}:null}},SpawnBug=function(){var a={},b;for(b in Bug)Bug.hasOwnProperty(b)&&(a[b]=Bug[b]);return a},mergeOptions=function(a,b,c){"undefined"==typeof c&&(c=!0);a=c?cloneOf(a):a;for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);return a},cloneOf=function(a){if(null==a||"object"!=typeof a)return a;var b=a.constructor(),c;for(c in a)a.hasOwnProperty(c)&&(b[c]=cloneOf(a[c]));return b}; -window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a,b){window.setTimeout(a,1E3/60)}}(); \ No newline at end of file +// ==ClosureCompiler== +// @compilation_level SIMPLE_OPTIMIZATIONS +// @output_file_name bug-min.js +// ==/ClosureCompiler== +/** + * @preserve Bug.js - https://github.com/Auz/Bug + * Released under MIT-style license. + * Original Screen Bug http://screen-bug.googlecode.com/git/index.html + */ +/** + * Bug.js - Add bugs to your page + * + * https://github.com/Auz/Bug + * + * license: MIT-style license. + * copyright: Copyright (c) 2016 Graham McNicoll + * + * + * Created for an aprils fool joke at Education.com 2013. I knew there was probably a script + * that did it already, and there was: http://screen-bug.googlecode.com/git/index.html. + * I used this as the starting point and heavily modified it, used sprite image animation, + * and added many new features. + * + * + * Original Screen Bug http://screen-bug.googlecode.com/git/index.html + * Copyright ©2011 Kernc (kerncece ^_^ gmail) + * Released under WTFPL license. + * + */ +"use strict"; + + +var startStationaryToggle = Date.now() + 10000; + +var BugDispatch = { + + options: { + minDelay: 500, + maxDelay: 10000, + minBugs: 2, + maxBugs: 20, + minSpeed: 5, + maxSpeed: 10, + maxLargeTurnDeg: 150, + maxSmallTurnDeg: 10, + maxWiggleDeg: 5, + imageSprite: 'fly-sprite.png', + bugWidth: 13, + bugHeight: 14, + num_frames: 5, + zoom: 10, // random zoom variation from 1 to 10 - 10 being full size. + canFly: true, + canDie: true, + numDeathTypes: 3, + monitorMouseMovement: false, + eventDistanceToBug: 40, + minTimeBetweenMultipy: 1000, + mouseOver: 'random' // can be 'fly', 'flyoff' (if the bug can fly), die', 'multiply', 'nothing' or 'random' + }, + + initialize: function(options) { + + this.options = mergeOptions(this.options, options); + + // sanity check: + if (this.options.minBugs > this.options.maxBugs) { + this.options.minBugs = this.options.maxBugs; + } + + this.modes = ['multiply', 'nothing']; + + if (this.options.canFly) { + this.modes.push('fly', 'flyoff'); + } + if (this.options.canDie) { + this.modes.push('die'); + } + + if (this.modes.indexOf(this.options.mouseOver) == -1) { + // invalid mode: use random: + this.options.mouseOver = 'random'; + } + + // can we transform? + this.transform = null; + + this.transforms = { + 'Moz': function(s) { + this.bug.style.MozTransform = s; + }, + 'webkit': function(s) { + this.bug.style.webkitTransform = s; + }, + 'O': function(s) { + this.bug.style.OTransform = s; + }, + 'ms': function(s) { + this.bug.style.msTransform = s; + }, + 'Khtml': function(s) { + this.bug.style.KhtmlTransform = s; + }, + 'w3c': function(s) { + this.bug.style.transform = s; + } + }; + + + // check to see if it is a modern browser: + + if ('transform' in document.documentElement.style) { + this.transform = this.transforms.w3c; + } else { + + // feature detection for the other transforms: + var vendors = ['Moz', 'webkit', 'O', 'ms', 'Khtml'], + i = 0; + + for (i = 0; i < vendors.length; i++) { + if (vendors[i] + 'Transform' in document.documentElement.style) { + this.transform = this.transforms[vendors[i]]; + break; + } + } + } + + // dont support transforms... quit + if (!this.transform) return; + + // make bugs: + this.bugs = []; + var numBugs = (this.options.mouseOver === 'multiply') ? this.options.minBugs : this.random(this.options.minBugs, this.options.maxBugs, true), + i = 0, + that = this; + + for (i = 0; i < numBugs; i++) { + var options = JSON.parse(JSON.stringify(this.options)), + b = SpawnBug(); + + options.wingsOpen = (this.options.canFly) ? ((Math.random() > 0.5) ? true : false) : true, + options.walkSpeed = this.random(this.options.minSpeed, this.options.maxSpeed), + + b.initialize(this.transform, options); + this.bugs.push(b); + } + + // fly them in staggered: + this.spawnDelay = []; + for (i = 0; i < numBugs; i++) { + var delay = this.random(this.options.minDelay, this.options.maxDelay, true), + thebug = this.bugs[i]; + // fly the bug onto the page: + this.spawnDelay[i] = setTimeout((function(thebug) { + return function() { + if (that.options.canFly) { + thebug.flyIn(); + } else { + thebug.walkIn(); + } + + }; + }(thebug)), delay); + + // add mouse over events: + that.add_events_to_bug(thebug); + } + + // add window event if required: + if (this.options.monitorMouseMovement) { + window.onmousemove = function() { + that.check_if_mouse_close_to_bug(); + }; + } + + }, + + stop: function() { + for (var i = 0; i < this.bugs.length; i++) { + if(this.spawnDelay[i]) clearTimeout(this.spawnDelay[i]); + this.bugs[i].stop(); + } + }, + + end: function() { + for (var i = 0; i < this.bugs.length; i++) { + if(this.spawnDelay[i]) clearTimeout(this.spawnDelay[i]); + this.bugs[i].stop(); + this.bugs[i].remove(); + } + }, + + reset: function() { + this.stop(); + for (var i = 0; i < this.bugs.length; i++) { + this.bugs[i].reset(); + this.bugs[i].walkIn(); + } + }, + + killAll: function() { + for (var i = 0; i < this.bugs.length; i++) { + if(this.spawnDelay[i]) clearTimeout(this.spawnDelay[i]); + this.bugs[i].die(); + } + }, + + add_events_to_bug: function(thebug) { + var that = this; + if (thebug.bug) { + if (thebug.bug.addEventListener) { + thebug.bug.addEventListener('mouseover', function(e) { + that.on_bug(thebug); + }); + } else if (thebug.bug.attachEvent) { + thebug.bug.attachEvent('onmouseover', function(e) { + that.on_bug(thebug); + }); + } + } + }, + + check_if_mouse_close_to_bug: function(e) { + e = e || window.event; + if (!e) { + return; + } + + var posx = 0, + posy = 0; + if (e.client && e.client.x) { + posx = e.client.x; + posy = e.client.y; + } else if (e.clientX) { + posx = e.clientX; + posy = e.clientY; + } else if (e.page && e.page.x) { + posx = e.page.x - (document.body.scrollLeft + document.documentElement.scrollLeft); + posy = e.page.y - (document.body.scrollTop + document.documentElement.scrollTop); + } else if (e.pageX) { + posx = e.pageX - (document.body.scrollLeft + document.documentElement.scrollLeft); + posy = e.pageY - (document.body.scrollTop + document.documentElement.scrollTop); + } + var numBugs = this.bugs.length, + i = 0; + for (i = 0; i < numBugs; i++) { + var pos = this.bugs[i].getPos(); + if (pos) { + if (Math.abs(pos.top - posy) + Math.abs(pos.left - posx) < this.options.eventDistanceToBug && !this.bugs[i].flyperiodical) { + this.near_bug(this.bugs[i]); + } + } + } + + }, + + near_bug: function(bug) { + this.on_bug(bug); + }, + + on_bug: function(bug) { + if (!bug.alive) { + return; + } + + var mode = this.options.mouseOver; + + if (mode === 'random') { + mode = this.modes[(this.random(0, (this.modes.length - 1), true))]; + } + + if (mode === 'fly') { + // fly away! + bug.stop(); + bug.flyRand(); + } else if (mode === 'nothing') { + return; + } else if (mode === 'flyoff') { + // fly away and off the page + bug.stop(); + bug.flyOff(); + } else if (mode === 'die') { + // drop dead! + bug.die(); + } else if (mode === 'multiply') { + if (!this.multiplyDelay && this.bugs.length < this.options.maxBugs) { + // spawn another: + // create new bug: + var b = SpawnBug(), + options = JSON.parse(JSON.stringify(this.options)), + pos = bug.getPos(), + that = this; + + options.wingsOpen = (this.options.canFly) ? ((Math.random() > 0.5) ? true : false) : true; + options.walkSpeed = this.random(this.options.minSpeed, this.options.maxSpeed); + + b.initialize(this.transform, options); + b.drawBug(pos.top, pos.left); + // fly them both away: + if (options.canFly) { + b.flyRand(); + bug.flyRand(); + } else { + b.go(); + bug.go(); + } + // store new bug: + this.bugs.push(b); + // watch out for spawning too quickly: + this.multiplyDelay = true; + setTimeout(function() { + // add event to this bug: + that.add_events_to_bug(b); + that.multiplyDelay = false; + }, this.options.minTimeBetweenMultipy); + } + + } + }, + + random: function(min, max, round) { + if (min == max) return ((round) ? Math.round(min) : min); + + var result = ((min - 0.5) + (Math.random() * (max - min + 1))); + if (result > max) { + result = max; + } else if (result < min) { + result = min; + } + return ((round) ? Math.round(result) : result); + } + + +}; + +var BugController = function() { + this.initialize.apply(this, arguments); +} +BugController.prototype = BugDispatch; + +var SpiderController = function() { + var spiderOptions = { + imageSprite: 'spider-sprite.png', + bugWidth: 69, + bugHeight: 90, + num_frames: 7, + canFly: false, + canDie: true, + numDeathTypes: 2, + zoom: 6, + minDelay: 1, + maxDelay: 2, + minSpeed: 6, + maxSpeed: 13, + minBugs: 3, + maxBugs: 10 + }; + this.options = mergeOptions(this.options, spiderOptions); + this.initialize.apply(this, arguments); + +} +SpiderController.prototype = BugDispatch; + +/***************/ +/** Bug **/ +/***************/ + +var Bug = { + + options: { + wingsOpen: false, + walkSpeed: 2, + flySpeed: 40, + edge_resistance: 50, + zoom: 10 + + }, + + initialize: function(transform, options) { + + this.options = mergeOptions(this.options, options); + + this.NEAR_TOP_EDGE = 1; + this.NEAR_BOTTOM_EDGE = 2; + this.NEAR_LEFT_EDGE = 4; + this.NEAR_RIGHT_EDGE = 8; + this.directions = {}; // 0 degrees starts on the East + this.directions[this.NEAR_TOP_EDGE] = 270; + this.directions[this.NEAR_BOTTOM_EDGE] = 90; + this.directions[this.NEAR_LEFT_EDGE] = 0; + this.directions[this.NEAR_RIGHT_EDGE] = 180; + this.directions[this.NEAR_TOP_EDGE + this.NEAR_LEFT_EDGE] = 315; + this.directions[this.NEAR_TOP_EDGE + this.NEAR_RIGHT_EDGE] = 225; + this.directions[this.NEAR_BOTTOM_EDGE + this.NEAR_LEFT_EDGE] = 45; + this.directions[this.NEAR_BOTTOM_EDGE + this.NEAR_RIGHT_EDGE] = 135; + + this.angle_deg = 0; + this.angle_rad = 0; + this.large_turn_angle_deg = 0; + this.near_edge = false; + this.edge_test_counter = 10; + this.small_turn_counter = 0; + this.large_turn_counter = 0; + this.fly_counter = 0; + this.toggle_stationary_counter = Math.random() * 50; + this.zoom = this.random(this.options.zoom, 10) / 10; + + this.stationary = false; + this.bug = null; + this.active = true; + this.wingsOpen = this.options.wingsOpen; + this.transform = transform; + this.walkIndex = 0; + this.flyIndex = 0; + this.alive = true; + this.twitchTimer = null; + + this.rad2deg_k = 180 / Math.PI; + this.deg2rad_k = Math.PI / 180; + + this.makeBug(); + + this.angle_rad = this.deg2rad(this.angle_deg); + + this.angle_deg = this.random(0, 360, true); + + }, + + go: function() { + if (this.transform) { + this.drawBug(); + var that = this; + + this.animating = true; + + this.going = requestAnimFrame(function(t) { + that.animate(t); + }); + } + }, + + stop: function() { + this.animating = false; + if (this.going) { + clearTimeout(this.going); + this.going = null; + } + if (this.flyperiodical) { + clearTimeout(this.flyperiodical); + this.flyperiodical = null; + } + if (this.twitchTimer) { + clearTimeout(this.twitchTimer); + this.twitchTimer = null; + } + }, + + remove: function() { + this.active = false; + if (this.inserted && this.bug.parentNode) { + this.bug.parentNode.removeChild(this.bug); + this.inserted = false; + } + }, + + reset: function() { + this.alive = true; + this.active = true; + this.bug.style.bottom = ''; + this.bug.style.top = 0; + this.bug.style.left = 0; + this.bug.classList.remove('bug-dead'); + }, + + animate: function(t) { + + if (!this.animating || !this.alive || !this.active) return; + + var that = this; + this.going = requestAnimFrame(function(t) { + that.animate(t); + }); + + if (!('_lastTimestamp' in this)) this._lastTimestamp = t; + + var delta = t - this._lastTimestamp; + + if (delta < 40) return; // don't animate too frequently + + // sometimes if the browser doesnt have focus, or the delta in request animation + // frame can be very large. We set a sensible max so that the bugs dont spaz out. + + if (delta > 200) delta = 200; + + this._lastTimestamp = t; + + if (Date.now() > startStationaryToggle && --this.toggle_stationary_counter <= 0) { + this.toggleStationary(); + } + if (this.stationary) { + return; + } + + + if (--this.edge_test_counter <= 0 && this.bug_near_window_edge()) { + // if near edge, go away from edge + this.angle_deg %= 360; + if (this.angle_deg < 0) this.angle_deg += 360; + + if (Math.abs(this.directions[this.near_edge] - this.angle_deg) > 15) { + var angle1 = this.directions[this.near_edge] - this.angle_deg; + var angle2 = (360 - this.angle_deg) + this.directions[this.near_edge]; + this.large_turn_angle_deg = (Math.abs(angle1) < Math.abs(angle2) ? angle1 : angle2); + + this.edge_test_counter = 10; + this.large_turn_counter = 100; + this.small_turn_counter = 30; + } + } + if (--this.large_turn_counter <= 0) { + this.large_turn_angle_deg = this.random(1, this.options.maxLargeTurnDeg, true); + this.next_large_turn(); + } + if (--this.small_turn_counter <= 0) { + this.angle_deg += this.random(1, this.options.maxSmallTurnDeg); + this.next_small_turn(); + } else { + var dangle = this.random(1, this.options.maxWiggleDeg, true); + if ((this.large_turn_angle_deg > 0 && dangle < 0) || (this.large_turn_angle_deg < 0 && dangle > 0)) { + dangle = -dangle; // ensures both values either + or - + } + this.large_turn_angle_deg -= dangle; + this.angle_deg += dangle; + } + + this.angle_rad = this.deg2rad(this.angle_deg); + + var dx = Math.cos(this.angle_rad) * this.options.walkSpeed * (delta / 100); + var dy = -Math.sin(this.angle_rad) * this.options.walkSpeed * (delta / 100); + + this.moveBug((this.bug.left + dx), (this.bug.top + dy), (90 - this.angle_deg)); + this.walkFrame(); + + }, + + makeBug: function() { + if (!this.bug && this.active) { + var row = (this.wingsOpen) ? '0' : '-' + this.options.bugHeight + 'px', + bug = document.createElement('div'); + bug.className = 'bug'; + bug.style.background = 'transparent url(' + this.options.imageSprite + ') no-repeat 0 ' + row; + bug.style.width = this.options.bugWidth + 'px'; + bug.style.height = this.options.bugHeight + 'px'; + bug.style.position = 'fixed'; + bug.style.top = 0; + bug.style.left = 0; + bug.style.zIndex = '9999999'; + + this.bug = bug; + this.setPos(); + + } + + }, + + setPos: function(top, left) { + this.bug.top = top || this.random(this.options.edge_resistance, document.documentElement.clientHeight - this.options.edge_resistance); + + this.bug.left = left || this.random(this.options.edge_resistance, document.documentElement.clientWidth - this.options.edge_resistance); + + this.moveBug(this.bug.left, this.bug.top, (90 - this.angle_deg)); + }, + + moveBug: function(x, y, deg) { + // keep track of where we are: + this.bug.left = x; + this.bug.top = y; + + // transform: + var trans = "translate(" + parseInt(x) + "px," + parseInt(y) + "px)"; + if (deg) { + //console.log("translate("+(x)+"px, "+(y)+"px) rotate("+deg+"deg)"); + trans += " rotate(" + deg + "deg)"; + } + trans += " scale(" + this.zoom + ")"; + + this.transform(trans); + + }, + + drawBug: function(top, left) { + + if (!this.bug) { + this.makeBug(); + } + if(!this.bug) return; + + if (top && left) { + this.setPos(top, left); + } else { + this.setPos(this.bug.top, this.bug.left) + } + if (!this.inserted) { + this.inserted = true; + document.body.appendChild(this.bug); + } + }, + + toggleStationary: function() { + this.stationary = !this.stationary; + this.next_stationary(); + var ypos = (this.wingsOpen) ? '0' : '-' + this.options.bugHeight + 'px'; + if (this.stationary) { + + this.bug.style.backgroundPosition = '0 ' + ypos; + } else { + this.bug.style.backgroundPosition = '-' + this.options.bugWidth + 'px ' + ypos; + } + }, + + walkFrame: function() { + var xpos = (-1 * (this.walkIndex * this.options.bugWidth)) + 'px', + ypos = (this.wingsOpen) ? '0' : '-' + this.options.bugHeight + 'px'; + this.bug.style.backgroundPosition = xpos + ' ' + ypos; + this.walkIndex++; + if (this.walkIndex >= this.options.num_frames) this.walkIndex = 0; + }, + + fly: function(landingPosition) { + var currentTop = this.bug.top, + currentLeft = this.bug.left, + diffx = (currentLeft - landingPosition.left), + diffy = (currentTop - landingPosition.top), + angle = Math.atan(diffy / diffx); + + if (Math.abs(diffx) + Math.abs(diffy) < 50) { + this.bug.style.backgroundPosition = (-2 * this.options.bugWidth) + 'px -' + (2 * this.options.bugHeight) + 'px'; + } + if (Math.abs(diffx) + Math.abs(diffy) < 30) { + this.bug.style.backgroundPosition = (-1 * this.options.bugWidth) + 'px -' + (2 * this.options.bugHeight) + 'px'; + } + if (Math.abs(diffx) + Math.abs(diffy) < 10) { + // close enough: + this.bug.style.backgroundPosition = '0 0'; //+row+'px')); + + this.stop(); + this.go(); + //this.go.delay(100, this); + + return; + + } + + // make it wiggle: disabled becuase its just too fast to see... better would be to make its path wiggly. + //angle = angle - (this.deg2rad(this.random(0,10))); + //console.log('angle: ',this.rad2deg(angle)); + + var dx = Math.cos(angle) * this.options.flySpeed, + dy = Math.sin(angle) * this.options.flySpeed; + + if ((currentLeft > landingPosition.left && dx > 0) || (currentLeft > landingPosition.left && dx < 0)) { + // make sure angle is right way + dx = -1 * dx; + if (Math.abs(diffx) < Math.abs(dx)) { + dx = dx / 4; + } + } + if ((currentTop < landingPosition.top && dy < 0) || (currentTop > landingPosition.top && dy > 0)) { + dy = -1 * dy; + if (Math.abs(diffy) < Math.abs(dy)) { + dy = dy / 4; + } + } + + this.moveBug((currentLeft + dx), (currentTop + dy)); + + }, + + flyRand: function() { + this.stop(); + var landingPosition = {}; + landingPosition.top = this.random(this.options.edge_resistance, document.documentElement.clientHeight - this.options.edge_resistance); + landingPosition.left = this.random(this.options.edge_resistance, document.documentElement.clientWidth - this.options.edge_resistance); + + this.startFlying(landingPosition); + }, + + startFlying: function(landingPosition) { + + var currentTop = this.bug.top, + currentLeft = this.bug.left, + diffx = (landingPosition.left - currentLeft), + diffy = (landingPosition.top - currentTop); + + this.bug.left = landingPosition.left; + this.bug.top = landingPosition.top; + + this.angle_rad = Math.atan(diffy / diffx); + this.angle_deg = this.rad2deg(this.angle_rad); + + if (diffx > 0) { + // going left: quadrant 1 or 2 + this.angle_deg = 90 + this.angle_deg; + } else { + // going right: quadrant 3 or 4 + this.angle_deg = 270 + this.angle_deg; + } + + this.moveBug(currentLeft, currentTop, this.angle_deg); + + // start animation: + var that = this; + this.flyperiodical = setInterval(function() { + that.fly(landingPosition); + }, 10); + }, + + flyIn: function() { + if (!this.bug) { + this.makeBug(); + } + + if(!this.bug) return; + + this.stop(); + // pick a random side: + var side = Math.round(Math.random() * 4 - 0.5), + d = document, + e = d.documentElement, + g = d.getElementsByTagName('body')[0], + windowX = window.innerWidth || e.clientWidth || g.clientWidth, + windowY = window.innerHeight || e.clientHeight || g.clientHeight; + if (side > 3) side = 3; + if (side < 0) side = 0; + var style = {}, + s; + if (side === 0) { + // top: + style.top = (-2 * this.options.bugHeight); + style.left = Math.random() * windowX; + } else if (side === 1) { + // right: + style.top = Math.random() * windowY; + style.left = windowX + (2 * this.options.bugWidth); + } else if (side === 2) { + // bottom: + style.top = windowY + (2 * this.options.bugHeight); + style.left = Math.random() * windowX; + } else { + // left: + style.top = Math.random() * windowY; + style.left = (-3 * this.options.bugWidth); + } + var row = (this.wingsOpen) ? '0' : '-' + this.options.bugHeight + 'px'; + this.bug.style.backgroundPosition = (-3 * this.options.bugWidth) + 'px ' + row; + this.bug.top = style.top + this.bug.left = style.left + + this.drawBug(); + + // landing position: + var landingPosition = {}; + landingPosition.top = this.random(this.options.edge_resistance, document.documentElement.clientHeight - this.options.edge_resistance); + landingPosition.left = this.random(this.options.edge_resistance, document.documentElement.clientWidth - this.options.edge_resistance); + + this.startFlying(landingPosition); + }, + + walkIn: function() { + if (!this.bug) { + this.makeBug(); + } + + if(!this.bug) return; + + this.stop(); + // pick a random side: + var side = Math.round(Math.random() * 4 - 0.5), + d = document, + e = d.documentElement, + g = d.getElementsByTagName('body')[0], + windowX = window.innerWidth || e.clientWidth || g.clientWidth, + windowY = window.innerHeight || e.clientHeight || g.clientHeight; + if (side > 3) side = 3; + if (side < 0) side = 0; + var style = {}, + s; + if (side === 0) { + // top: + style.top = (-1.3 * this.options.bugHeight); + style.left = Math.random() * windowX; + } else if (side === 1) { + // right: + style.top = Math.random() * windowY; + style.left = windowX + (0.3 * this.options.bugWidth); + } else if (side === 2) { + // bottom: + style.top = windowY + (0.3 * this.options.bugHeight); + style.left = Math.random() * windowX; + } else { + // left: + style.top = Math.random() * windowY; + style.left = (-1.3 * this.options.bugWidth); + } + var row = (this.wingsOpen) ? '0' : '-' + this.options.bugHeight + 'px'; + this.bug.style.backgroundPosition = (-3 * this.options.bugWidth) + 'px ' + row; + this.bug.top = style.top + this.bug.left = style.left + + this.drawBug(); + + // start walking: + this.go(); + + }, + + flyOff: function() { + this.stop(); + // pick a random side to fly off to, where 0 is top and continuing clockwise. + var side = this.random(0, 3), + style = {}, + d = document, + e = d.documentElement, + g = d.getElementsByTagName('body')[0], + windowX = window.innerWidth || e.clientWidth || g.clientWidth, + windowY = window.innerHeight || e.clientHeight || g.clientHeight; + + if (side === 0) { + // top: + style.top = -200; + style.left = Math.random() * windowX; + } else if (side === 1) { + // right: + style.top = Math.random() * windowY; + style.left = windowX + 200; + } else if (side === 2) { + //bottom: + style.top = windowY + 200; + style.left = Math.random() * windowX; + } else { + // left: + style.top = Math.random() * windowY; + style.left = -200; + } + this.startFlying(style); + }, + + die: function() { + this.stop(); + //pick death style: + var deathType = this.random(0, this.options.numDeathTypes - 1); + + this.alive = false; + this.drop(deathType); + }, + + drop: function(deathType) { + var startPos = this.bug.top, + d = document, + e = d.documentElement, + g = d.getElementsByTagName('body')[0], + finalPos = window.innerHeight || e.clientHeight || g.clientHeight, + finalPos = finalPos - this.options.bugHeight, + rotationRate = this.random(0, 20, true), + startTime = Date.now(), + that = this; + + this.bug.classList.add('bug-dead'); + + this.dropTimer = requestAnimFrame(function(t) { + that._lastTimestamp = t; + that.dropping(t, startPos, finalPos, rotationRate, deathType); + }); + + }, + + dropping: function(t, startPos, finalPos, rotationRate, deathType) { + var elapsedTime = t - this._lastTimestamp, + deltaPos = (0.002 * (elapsedTime * elapsedTime)), + newPos = startPos + deltaPos; + //console.log(t, elapsedTime, deltaPos, newPos); + + var that = this; + + + if (newPos >= finalPos) { + newPos = finalPos; + clearTimeout(this.dropTimer); + + + + this.angle_deg = 0; + this.angle_rad = this.deg2rad(this.angle_deg); + this.transform("rotate(" + (90 - this.angle_deg) + "deg) scale(" + this.zoom + ")"); + this.bug.style.top = null; + // because it is (or might be) zoomed and rotated, we cannot just just bottom = 0. Figure out real bottom position: + var rotationOffset = ((this.options.bugWidth * this.zoom) - (this.options.bugHeight * this.zoom)) / 2; + var zoomOffset = ((this.options.bugHeight) / 2) * (1 - this.zoom); + this.bug.style.bottom = Math.ceil((rotationOffset - zoomOffset)) + 'px'; // because its rotated and zoomed. + this.bug.style.left = this.bug.left + 'px'; + this.bug.style.backgroundPosition = '-' + ((deathType * 2) * this.options.bugWidth) + 'px 100%'; + + + this.twitch(deathType); + + return; + } + + this.dropTimer = requestAnimFrame(function(t) { + that.dropping(t, startPos, finalPos, rotationRate, deathType); + }); + + if (elapsedTime < 20) return; + + this.angle_deg = ((this.angle_deg + rotationRate) % 360); + this.angle_rad = this.deg2rad(this.angle_deg); + + this.moveBug(this.bug.left, newPos, this.angle_deg); + }, + + twitch: function(deathType, legPos) { + //this.bug.style.back + if (!legPos) legPos = 0; + var that = this; + if (deathType === 0 || deathType === 1) { + that.twitchTimer = setTimeout(function() { + that.bug.style.backgroundPosition = '-' + ((deathType * 2 + (legPos % 2)) * that.options.bugWidth) + 'px 100%'; + that.twitchTimer = setTimeout(function() { + legPos++; + that.bug.style.backgroundPosition = '-' + ((deathType * 2 + (legPos % 2)) * that.options.bugWidth) + 'px 100%'; + that.twitch(deathType, ++legPos); + }, that.random(300, 800)); + }, this.random(1000, 10000)); + } + }, + + /* helper methods: */ + rad2deg: function(rad) { + return rad * this.rad2deg_k; + }, + deg2rad: function(deg) { + return deg * this.deg2rad_k; + }, + random: function(min, max, plusminus) { + if (min == max) return min; + var result = Math.round(min - 0.5 + (Math.random() * (max - min + 1))); + if (plusminus) return Math.random() > 0.5 ? result : -result; + return result; + }, + + next_small_turn: function() { + this.small_turn_counter = Math.round(Math.random() * 10); + }, + next_large_turn: function() { + this.large_turn_counter = Math.round(Math.random() * 40); + }, + next_stationary: function() { + this.toggle_stationary_counter = this.random(50, 300); + }, + + bug_near_window_edge: function() { + this.near_edge = 0; + if (this.bug.top < this.options.edge_resistance) + this.near_edge |= this.NEAR_TOP_EDGE; + else if (this.bug.top > document.documentElement.clientHeight - this.options.edge_resistance) + this.near_edge |= this.NEAR_BOTTOM_EDGE; + if (this.bug.left < this.options.edge_resistance) + this.near_edge |= this.NEAR_LEFT_EDGE; + else if (this.bug.left > document.documentElement.clientWidth - this.options.edge_resistance) + this.near_edge |= this.NEAR_RIGHT_EDGE; + return this.near_edge; + }, + + getPos: function() { + if (this.inserted && this.bug && this.bug.style) { + return { + 'top': parseInt(this.bug.top, 10), + 'left': parseInt(this.bug.left, 10) + }; + } + return null; + } + +}; + +var SpawnBug = function() { + var newBug = {}, + prop; + for (prop in Bug) { + if (Bug.hasOwnProperty(prop)) { + newBug[prop] = Bug[prop]; + } + } + return newBug; +}; + +// debated about which pattern to use to instantiate each bug... +// see http://jsperf.com/obj-vs-prototype-vs-other + + + +/** + * Helper methods: + **/ + +var mergeOptions = function(obj1, obj2, clone) { + if (typeof(clone) == 'undefined') { + clone = true; + } + var newobj = (clone) ? cloneOf(obj1) : obj1; + for (var key in obj2) { + if (obj2.hasOwnProperty(key)) { + newobj[key] = obj2[key]; + } + } + return newobj; +}; + +var cloneOf = function(obj) { + if (obj == null || typeof(obj) != 'object') + return obj; + + var temp = obj.constructor(); // changed + + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + temp[key] = cloneOf(obj[key]); + } + } + return temp; +} + +/* Request animation frame polyfill */ +/* http://paulirish.com/2011/requestanimationframe-for-smart-animating/ */ +window.requestAnimFrame = (function() { + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || function( /* function */ callback, /* DOMElement */ element) { + window.setTimeout(callback, 1000 / 60); + }; +})();