Take the tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

just wanted to gather your opinion on my little javascript library.

It features Math, String, Array, canvas and location extensions, aswell 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) {
    this.fps = null;
    this.delta = 1;
    this.lastTime = +new Date;
    this.callback = callback;
    this.request = null;
};

Loop.prototype.start = function() {

    var _this = this;
    this.request = requestAnimationFrame(function(now) {
        _this.start();
        _this.delta = (now - _this.lastTime);
        _this.fps = 1000/_this.delta;
        _this.delta = _this.delta / (1000/60) > 2 ? 1 : _this.delta / (1000/60);
        _this.lastTime = now;
        _this.callback();
    });
};

Loop.prototype.stop = function() { cancelAnimationFrame(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;
};

Ticker.prototype.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;
};

Ticker.prototype.reset = function() {
    if (this.auto_reverse) { this.reverse = this.reverse ? false : true; }

    var _this = this;
    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
(function() {

    var lastTime = 0, vendors = ['ms', 'moz', 'webkit', 'o'];
    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
    }

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

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


/* ====================== */
/* ======= 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(path) {
    var script = document.createElement("script");
    script.setAttribute("src", path);
    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;
}
share|improve this question
add comment

1 Answer

up vote 6 down vote accepted

Here are some tips.

1)

Avoid using java keywords. In Math.rand, there is a variable called float. Try calling it toFloat.

2)

It's best not to browser sniff. Detect for features instead.

Old Code:

function createRequestObject() {

    var request, browser = navigator.appName;

    if (browser == "Microsoft Internet Explorer")
    { request = new ActiveXObject("Microsoft.XMLHTTP"); }
    else
    { request = new XMLHttpRequest(); }

    return request;
}

New Code:

function createRequestObject() {
    var request;
    if (ActiveXObject) {
        request = new ActiveXObject("Microsoft.XMLHTTP");
    } else {
        request = new XMLHttpRequest();
    }
    return request;
}

3)

Try not to repeat yourself.

Old Code:

CanvasRenderingContext2D.prototype.strokeRect = function(x, y, w, h, r1, r2, r3, r4) {
    if (r1 == null) {    
        this.beginPath();
        //...
        this.closePath();
        this.stroke();
    } else {
        //...
        this.beginPath();
        //...
        this.closePath();
        this.stroke();
    }
};

New Code:

CanvasRenderingContext2D.prototype.strokeRect = function(x, y, w, h, r1, r2, r3, r4) {
    this.beginPath();
    if (r1 == null) {    
        this.moveTo(x, y);
        //...
    } else {
        //...
    }
    this.closePath();
    this.stroke();
};

4)

Make functions as small as possible. Try adding functions to the prototype instead of creating them inside the constructor.

Old Code:

var Loop = function(callback, 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);
    };

//...
};

New Code:

Loop.prototype.start = function () {
    // Timeout is used to specify a framerate
            var _this = this;
    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);
};

5)

Rename String.prototype.charAt to String.prototype.replaceByIndex

6)

this.fps = fps ? fps : 60; is the same as this.fps = fps || 60;

share|improve this answer
 
Thanks a bunch! One question though: In the prototype example, how do I create the necessary reference _this used to have ? –  elias94xx Sep 11 '12 at 9:12
 
@elias94xx Create a reference outside the function to this called _this. Refer to the updated code example. –  Larry Battle Sep 11 '12 at 14:36
 
Oh of course, got confused a little. :) –  elias94xx Sep 11 '12 at 14:51
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.