rDrama/files/assets/js/vendor/critters.js

1043 lines
33 KiB
JavaScript

// ==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);
};
})();