I just wanted to gather your opinion on my little JavaScript library. It features Math
, String
, Array
, canvas
and location
extensions, as well as some useful animation and timing classes I came up with:
/* ====================== */
/* ======= Math ========= */
/* ====================== */
// Random number
Math.rand = function(min, max, float) {
var random = Math.random() * (max-min) + min;
return float ? random : Math.round(random);
};
// Random number with seed (not fully functional)
Math.srand = function(seed, min, max, float) {
var code = 0;
for (var i = 0, l = seed.length; i < l; i++) { code += seed.charCodeAt(i); }
while (code > 1) { code/= 10; }
var mod = code;
var MAX_INT = Math.pow(2,32) - 1;
var min = min != null ? min : -MAX_INT;
var max = max != null ? max : MAX_INT;
var random = mod * (max-min) + min;
return float ? random : Math.round(random);
};
// 3.141592653589793 -> 180°
Math.toDegrees = function(angle) {
return angle * (180 / Math.PI);
};
// 180° -> 3.141592653589793
Math.toRadians = function(angle) {
return angle * (Math.PI / 180);
};
/* ====================== */
/* ======= String ======= */
/* ====================== */
// string -> String
String.prototype.capitalize = function() {
return this.charAt(0).toUpperCase() + this.slice(1);
};
// "test".charAt(2, "oa") -> "toast"
String.prototype.charAt = function(index, replacement) {
if (replacement == null) { return this.substr(index, 1); }
else { return this.substr(0, index-1) + replacement + this.substr(index); }
};
/* ====================== */
/* ======= Array ======== */
/* ====================== */
// Compares values to an array object and returns the index
Array.prototype.compare = function(values) {
for (var i = 0, l = this.length; i < l; i++) {
var matches = [];
for (var ii = 0, ll = values.length; ii < ll; ii++) {
if (this[i][values[ii][0]] == values[ii][1]) { matches.push(true); }
}
if (matches.length == values.length) { return i; }
}
};
// Reaplces values in a numeric array
Array.prototype.replace = function(a, b) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i] == a) { this[i] = b; }
}
};
/* ====================== */
/* ======= Animation ==== */
/* ====================== */
// An advanced interval class which also calculates delta and fps
var Loop = function(callback, fps) {
var _this = this;
this.fps = fps ? fps : 60;
this.real_fps = null;
this.delta = 1;
this.lastTime = +new Date;
this.request = null;
this.callback = callback;
this.setFPS = function(fps) { this.fps = fps; };
this.start = function() {
// Timeout is used to specify a framerate
this.request = setTimeout(function() {
requestAnimFrame(function() {
_this.start();
_this.delta = (+new Date - _this.lastTime) / (1000 / _this.fps);
_this.real_fps = Math.round((1 + (1-_this.delta))*_this.fps);
_this.callback();
_this.lastTime = +new Date;
});
}, 1000 / this.fps);
};
this.stop = function() {
clearTimeout(this.request);
};
};
// An advanced timeout class which also calculates the current progress
var Ticker = function(start, duration, callback) {
var _this = this;
this.start = start;
this.duration = duration;
// TODO easing options
this.reverse = false;
this.auto_reset = false;
this.auto_reverse = false;
this.callback = callback ? callback : null;
this.timeout = callback ? setTimeout(function() {
_this.callback();
if (_this.auto_reset || _this.auto_reverse) { _this.reset(); }
}, this.duration) : null;
this.status = function() {
var end = this.start + this.duration;
var current = +new Date;
var duration = end - this.start;
var difference = current - this.start;
var progress = this.reverse ? 1 - (difference / duration) : (difference / duration);
if (current >= end) { progress = this.reverse ? 0 : 1; }
return progress;
};
this.reset = function() {
if (this.auto_reverse) { this.reverse = this.reverse ? false : true; }
this.timeout = this.callback ? setTimeout(function() {
_this.callback();
if (_this.auto_reset || _this.auto_reverse) { _this.reset(); }
}, this.duration) : null;
this.start = +new Date;
};
};
// Unifies the HTML5 requestAnimationFrame function
window.requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) { window.setTimeout(callback, 1000 / 60); };
})();
/* ====================== */
/* ======= Canvas ======= */
/* ====================== */
CanvasRenderingContext2D.prototype.center = function() {
return {
x: Math.round(this.canvas.width / 2),
y: Math.round(this.canvas.height / 2)
};
};
// Extends the canvas fillRect function to be able to draw round corners
CanvasRenderingContext2D.prototype.fillRect = function(x, y, w, h, r1, r2, r3, r4) {
if (r1 == null) {
this.beginPath();
this.moveTo(x, y);
this.lineTo(x + w, y);
this.lineTo(x + w, y + h);
this.lineTo(x, y + h);
this.closePath();
this.fill();
} else {
var r2 = r2 == null ? r1 : r2;
var r3 = r3 == null ? r1 : r3;
var r4 = r4 == null ? r2 : r4;
r4 = r4 == null ? r1 : r4;
this.beginPath();
this.moveTo(x, y + r1);
this.quadraticCurveTo(x, y, x + r1, y);
this.lineTo(x + w - r2, y);
this.quadraticCurveTo(x + w, y, x + w, y + r2);
this.lineTo(x + w, y + h - r3);
this.quadraticCurveTo(x + w, y + h, x + w - r3, y + h);
this.lineTo(x + r4, y + h);
this.quadraticCurveTo(x, y + h, x, y + h - r4);
this.closePath();
this.fill();
}
};
// Extends the canvas strokeRect function to be able to draw round corners
CanvasRenderingContext2D.prototype.strokeRect = function(x, y, w, h, r1, r2, r3, r4) {
if (r1 == null) {
this.beginPath();
this.moveTo(x, y);
this.lineTo(x + w, y);
this.lineTo(x + w, y + h);
this.lineTo(x, y + h);
this.closePath();
this.stroke();
} else {
var r2 = r2 == null ? r1 : r2;
var r3 = r3 == null ? r1 : r3;
var r4 = r4 == null ? r2 : r4;
r4 = r4 == null ? r1 : r4;
this.beginPath();
this.moveTo(x, y + r1);
this.quadraticCurveTo(x, y, x + r1, y);
this.lineTo(x + w - r2, y);
this.quadraticCurveTo(x + w, y, x + w, y + r2);
this.lineTo(x + w, y + h - r3);
this.quadraticCurveTo(x + w, y + h, x + w - r3, y + h);
this.lineTo(x + r4, y + h);
this.quadraticCurveTo(x, y + h, x, y + h - r4);
this.closePath();
this.stroke();
}
};
/* ====================== */
/* ======= Document ===== */
/* ====================== */
// Simple cookie handling object
var Cookie = {
set: function(name, value, days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name + "=" + value + expires + "; path=" + location.pathname;
},
unset: function(name) { Cookie.set(name, "", -1); },
get: function(name) {
var search = new RegExp(name + "=([^;]*);");
var result = search.exec(document.cookie);
return result ? result[1] : null;
}
};
// Returns the value of the specified GET parameter (equivalent to PHP's $_GET[name])
location.get = function(name) {
var search = new RegExp(encodeURIComponent(name) + "=([^&]*)&?");
var result = search.exec(location.search);
return result ? result[1] : null;
};
function include(file) {
var dir = document.getElementsByTagName("script")[0].getAttribute("src").match(/([\w_-]+)\/[\w_-]+\.js/)[1];
var script = document.createElement("script");
script.setAttribute("src", dir + "/" + file);
document.getElementsByTagName("head")[0].appendChild(script);
}
function createRequestObject() {
var request, browser = navigator.appName;
if (browser == "Microsoft Internet Explorer")
{ request = new ActiveXObject("Microsoft.XMLHTTP"); }
else
{ request = new XMLHttpRequest(); }
return request;
}