bebraw
3/7/2011 - 5:48 PM

Some color utils wrapped in a RequireJS module

Some color utils wrapped in a RequireJS module

/**
 * A class to parse color values
 * @author Stoyan Stefanov <sstoo@gmail.com>
 * @link   http://www.phpied.com/rgb-color-parser-in-javascript/
 * @license Use it if you like it
 */
define(['utils/math'], function(math) {
    var simple_colors = {
        aliceblue: 'f0f8ff',
        antiquewhite: 'faebd7',
        aqua: '00ffff',
        aquamarine: '7fffd4',
        azure: 'f0ffff',
        beige: 'f5f5dc',
        bisque: 'ffe4c4',
        black: '000000',
        blanchedalmond: 'ffebcd',
        blue: '0000ff',
        blueviolet: '8a2be2',
        brown: 'a52a2a',
        burlywood: 'deb887',
        cadetblue: '5f9ea0',
        chartreuse: '7fff00',
        chocolate: 'd2691e',
        coral: 'ff7f50',
        cornflowerblue: '6495ed',
        cornsilk: 'fff8dc',
        crimson: 'dc143c',
        cyan: '00ffff',
        darkblue: '00008b',
        darkcyan: '008b8b',
        darkgoldenrod: 'b8860b',
        darkgray: 'a9a9a9',
        darkgreen: '006400',
        darkkhaki: 'bdb76b',
        darkmagenta: '8b008b',
        darkolivegreen: '556b2f',
        darkorange: 'ff8c00',
        darkorchid: '9932cc',
        darkred: '8b0000',
        darksalmon: 'e9967a',
        darkseagreen: '8fbc8f',
        darkslateblue: '483d8b',
        darkslategray: '2f4f4f',
        darkturquoise: '00ced1',
        darkviolet: '9400d3',
        deeppink: 'ff1493',
        deepskyblue: '00bfff',
        dimgray: '696969',
        dodgerblue: '1e90ff',
        feldspar: 'd19275',
        firebrick: 'b22222',
        floralwhite: 'fffaf0',
        forestgreen: '228b22',
        fuchsia: 'ff00ff',
        gainsboro: 'dcdcdc',
        ghostwhite: 'f8f8ff',
        gold: 'ffd700',
        goldenrod: 'daa520',
        gray: '808080',
        green: '008000',
        greenyellow: 'adff2f',
        honeydew: 'f0fff0',
        hotpink: 'ff69b4',
        indianred : 'cd5c5c',
        indigo : '4b0082',
        ivory: 'fffff0',
        khaki: 'f0e68c',
        lavender: 'e6e6fa',
        lavenderblush: 'fff0f5',
        lawngreen: '7cfc00',
        lemonchiffon: 'fffacd',
        lightblue: 'add8e6',
        lightcoral: 'f08080',
        lightcyan: 'e0ffff',
        lightgoldenrodyellow: 'fafad2',
        lightgrey: 'd3d3d3',
        lightgreen: '90ee90',
        lightpink: 'ffb6c1',
        lightsalmon: 'ffa07a',
        lightseagreen: '20b2aa',
        lightskyblue: '87cefa',
        lightslateblue: '8470ff',
        lightslategray: '778899',
        lightsteelblue: 'b0c4de',
        lightyellow: 'ffffe0',
        lime: '00ff00',
        limegreen: '32cd32',
        linen: 'faf0e6',
        magenta: 'ff00ff',
        maroon: '800000',
        mediumaquamarine: '66cdaa',
        mediumblue: '0000cd',
        mediumorchid: 'ba55d3',
        mediumpurple: '9370d8',
        mediumseagreen: '3cb371',
        mediumslateblue: '7b68ee',
        mediumspringgreen: '00fa9a',
        mediumturquoise: '48d1cc',
        mediumvioletred: 'c71585',
        midnightblue: '191970',
        mintcream: 'f5fffa',
        mistyrose: 'ffe4e1',
        moccasin: 'ffe4b5',
        navajowhite: 'ffdead',
        navy: '000080',
        oldlace: 'fdf5e6',
        olive: '808000',
        olivedrab: '6b8e23',
        orange: 'ffa500',
        orangered: 'ff4500',
        orchid: 'da70d6',
        palegoldenrod: 'eee8aa',
        palegreen: '98fb98',
        paleturquoise: 'afeeee',
        palevioletred: 'd87093',
        papayawhip: 'ffefd5',
        peachpuff: 'ffdab9',
        peru: 'cd853f',
        pink: 'ffc0cb',
        plum: 'dda0dd',
        powderblue: 'b0e0e6',
        purple: '800080',
        red: 'ff0000',
        rosybrown: 'bc8f8f',
        royalblue: '4169e1',
        saddlebrown: '8b4513',
        salmon: 'fa8072',
        sandybrown: 'f4a460',
        seagreen: '2e8b57',
        seashell: 'fff5ee',
        sienna: 'a0522d',
        silver: 'c0c0c0',
        skyblue: '87ceeb',
        slateblue: '6a5acd',
        slategray: '708090',
        snow: 'fffafa',
        springgreen: '00ff7f',
        steelblue: '4682b4',
        tan: 'd2b48c',
        teal: '008080',
        thistle: 'd8bfd8',
        tomato: 'ff6347',
        turquoise: '40e0d0',
        violet: 'ee82ee',
        violetred: 'd02090',
        wheat: 'f5deb3',
        white: 'ffffff',
        whitesmoke: 'f5f5f5',
        yellow: 'ffff00',
        yellowgreen: '9acd32'
    };

    function Color(colorString) {
        this.init(colorString);
    }
    Color.prototype = {
        init: function(color) {
            if (isHash(color)) {
                this.r = color.r || 0;
                this.g = color.g || 0;
                this.b = color.b || 0;
            }
            else {
                this._parseColorString(color);
            }

            this._clampRGB();

            // set up initial hsv
            this.setRGB(this.r, this.g, this.b);
        },
        _clampRGB: function() {
            this.r = math.clamp(this.r, 0, 255);
            this.g = math.clamp(this.g, 0, 255);
            this.b = math.clamp(this.b, 0, 255);
        },
        _parseColorString: function(colorString) {
            if (!defined(colorString)) {
                colorString = 'black';
            }

            // strip any leading #
            if (colorString.charAt(0) == '#') { // remove # if any
                colorString = colorString.substr(1,6);
            }

            colorString = colorString.replace(/ /g,'');
            colorString = colorString.toLowerCase();

            // before getting into regexps, try simple matches
            // and overwrite the input
            for (var key in simple_colors) {
                if (colorString == key) {
                    colorString = simple_colors[key];
                }
            }
            // emd of simple type-in colors

            // array of color definition objects
            var color_defs = [
                {
                    re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
                    example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
                    process: function (bits){
                        return [
                            parseInt(bits[1]),
                            parseInt(bits[2]),
                            parseInt(bits[3])
                        ];
                    }
                },
                {
                    re: /^(\w{2})(\w{2})(\w{2})$/,
                    example: ['#00ff00', '336699'],
                    process: function (bits){
                        return [
                            parseInt(bits[1], 16),
                            parseInt(bits[2], 16),
                            parseInt(bits[3], 16)
                        ];
                    }
                },
                {
                    re: /^(\w{1})(\w{1})(\w{1})$/,
                    example: ['#fb0', 'f0f'],
                    process: function (bits){
                        return [
                            parseInt(bits[1] + bits[1], 16),
                            parseInt(bits[2] + bits[2], 16),
                            parseInt(bits[3] + bits[3], 16)
                        ];
                    }
                }
            ];

            // search through the definitions to find a match
            for (var i = 0; i < color_defs.length; i++) {
                var re = color_defs[i].re;
                var processor = color_defs[i].process;
                var bits = re.exec(colorString);
                if (bits) {
                    var channels = processor(bits);
                    this.r = channels[0];
                    this.g = channels[1];
                    this.b = channels[2];
                }

            }

            // validate/cleanup values
            this.r = (this.r < 0 || isNaN(this.r)) ? 0 : this.r;
            this.g = (this.g < 0 || isNaN(this.g)) ? 0 : this.g;
            this.b = (this.b < 0 || isNaN(this.b)) ? 0 : this.b;
        },
        setRGB: function(r, g, b) { // null = don't change
            var hsv = this.RGB_HSV(
                r == null ? this.r : (this.r = r),
                g == null ? this.g : (this.g = g),
                b == null ? this.b : (this.b = b)
            );

            this.h = isNumber(hsv[0])? hsv[0]: 0;
            this.s = isNumber(hsv[1])? hsv[1]: 0;
            this.v = isNumber(hsv[2])? hsv[2]: 0;
        },
        setHSV: function(h, s, v) { // null = don't change
            if(h < 0) {
                h = 6 + (h % 6);
            }

            var rgb = this.HSV_RGB(
                h==null ? this.h : (this.h=h),
                s==null ? this.s : (this.s=s),
                v==null ? this.v : (this.v=v)
            );

            this.r = isNumber(rgb[0])? rgb[0]: 0;
            this.g = isNumber(rgb[1])? rgb[1]: 0;
            this.b = isNumber(rgb[2])? rgb[2]: 0;
        },
        RGB_HSV: function(r, g, b) {
            var n = Math.min(Math.min(r, g), b);
            var v = Math.max(Math.max(r, g), b);
            var m = v - n;

            if(m == 0) {
                return [ null, 0, v ];
            }

            var h = r==n ? 3 + (b - g) / m : (g == n ? 5 + (r - b) / m : 1 + (g - r) / m);

            return [ h == 6? 0: h, m / v, v ];
        },
        HSV_RGB: function(h, s, v) {
            if (h == null) {
                return [ v, v, v ];
            }

            var i = Math.floor(h);
            var f = i % 2 ? h - i : 1 - (h - i);
            var m = v * (1 - s);
            var n = v * (1 - s * f);

            switch(i) {
                case 6:
                case 0:
                    return [ v, n, m ];
                case 1:
                    return [ n, v, m ];
                case 2:
                    return [ m, v, n ];
                case 3:
                    return [ m, n, v ];
                case 4:
                    return [ n, m, v ];
                case 5:
                    return [ v, m, n ];
            }
        },
        toString: function() {
            var r = Math.round(this.r).toString(16);
            var g = Math.round(this.g).toString(16);
            var b = Math.round(this.b).toString(16);

            return (
                (r.length == 1 ? '0' + r : r) +
                (g.length == 1 ? '0' + g : g) +
                (b.length == 1 ? '0' + b : b)
                ).toUpperCase();
        },
        toRGBArray: function() {
            return [this.r, this.g, this.b];
        },
        toHSVArray: function() {
            return [this.h, this.s, this.v];
        }
    }

    return {Color: Color}
    };
});